00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "stdmisc.h"
00025 #include "nel/misc/time_nl.h"
00026 #include "nel/misc/command.h"
00027 #include "nel/misc/buf_fifo.h"
00028
00029 using namespace std;
00030
00031 #define DEBUG_FIFO 0
00032
00033
00034 #define STAT_FIFO 1
00035
00036 namespace NLMISC {
00037
00038 #ifdef BUFFIFO_TRACK_ALL_BUFFERS
00039 CBufFIFO::TAllBuffers CBufFIFO::_AllBuffers;
00040 #endif
00041
00042
00043 CBufFIFO::CBufFIFO() : _Buffer(NULL), _BufferSize(0), _Empty(true), _Head(NULL), _Tail(NULL), _Rewinder(NULL)
00044 {
00045 #ifdef BUFFIFO_TRACK_ALL_BUFFERS
00046 _AllBuffers.insert(this);
00047 #endif
00048
00049
00050 _BiggestBlock = 0;
00051 _SmallestBlock = 999999999;
00052 _BiggestBuffer = 0;
00053 _SmallestBuffer = 999999999;
00054 _Pushed = 0;
00055 _Fronted = 0;
00056 _Resized = 0;
00057 _PushedTime = 0;
00058 _FrontedTime = 0;
00059 _ResizedTime = 0;
00060 }
00061
00062 CBufFIFO::~CBufFIFO()
00063 {
00064 #ifdef BUFFIFO_TRACK_ALL_BUFFERS
00065 _AllBuffers.erase(this);
00066 #endif
00067
00068 if (_Buffer != NULL)
00069 {
00070 delete []_Buffer;
00071 #if DEBUG_FIFO
00072 nldebug("%p delete", this);
00073 #endif
00074 }
00075 }
00076
00077 void CBufFIFO::push (const uint8 *buffer, uint32 s)
00078 {
00079
00080
00081
00082 #if STAT_FIFO
00083 TTicks before = CTime::getPerformanceTime();
00084 #endif
00085
00086 #if DEBUG_FIFO
00087 nldebug("%p push(%d)", this, s);
00088 #endif
00089
00090 nlassert(s > 0 && s < pow(2.0, static_cast<double>(sizeof(TFifoSize)*8)));
00091
00092
00093 if (s > _BiggestBlock) _BiggestBlock = s;
00094 if (s < _SmallestBlock) _SmallestBlock = s;
00095 _Pushed++;
00096
00097 while (!canFit (s + sizeof (TFifoSize)))
00098 {
00099 resize(_BufferSize * 2);
00100 }
00101
00102 *(TFifoSize *)_Head = s;
00103 _Head += sizeof(TFifoSize);
00104
00105 CFastMem::memcpy(_Head, buffer, s);
00106
00107 _Head += s;
00108
00109 _Empty = false;
00110
00111 #if STAT_FIFO
00112
00113 TTicks after = CTime::getPerformanceTime();
00114 _PushedTime += after - before;
00115 #endif
00116
00117 #if DEBUG_FIFO
00118 display ();
00119 #endif
00120 }
00121
00122 void CBufFIFO::push(const std::vector<uint8> &buffer1, const std::vector<uint8> &buffer2)
00123 {
00124 #if STAT_FIFO
00125 TTicks before = CTime::getPerformanceTime();
00126 #endif
00127
00128 TFifoSize s = buffer1.size() + buffer2.size();
00129
00130 #if DEBUG_FIFO
00131 nldebug("%p push2(%d)", this, s);
00132 #endif
00133
00134 nlassert((buffer1.size() + buffer2.size ()) > 0 && (buffer1.size() + buffer2.size ()) < pow(2.0, static_cast<double>(sizeof(TFifoSize)*8)));
00135
00136
00137 if (this->size() > 10000000)
00138 {
00139 throw Exception ("CBufFIFO::push(): stack full (more than 10mb)");
00140 }
00141
00142
00143
00144 if (s > _BiggestBlock) _BiggestBlock = s;
00145 if (s < _SmallestBlock) _SmallestBlock = s;
00146
00147 _Pushed++;
00148
00149
00150 while (!canFit (s + sizeof (TFifoSize)))
00151 {
00152 resize(_BufferSize * 2);
00153 }
00154
00155
00156 *(TFifoSize *)_Head = s;
00157 _Head += sizeof(TFifoSize);
00158
00159
00160 CFastMem::memcpy(_Head, &(buffer1[0]), buffer1.size());
00161 CFastMem::memcpy(_Head + buffer1.size(), &(buffer2[0]), buffer2.size());
00162 _Head += s;
00163
00164 _Empty = false;
00165
00166 #if STAT_FIFO
00167
00168 TTicks after = CTime::getPerformanceTime();
00169 _PushedTime += after - before;
00170 #endif
00171
00172 #if DEBUG_FIFO
00173 display ();
00174 #endif
00175 }
00176
00177 void CBufFIFO::pop ()
00178 {
00179 if (empty ())
00180 {
00181 nlwarning("BF: Try to pop an empty fifo!");
00182 return;
00183 }
00184
00185 if (_Rewinder != NULL && _Tail == _Rewinder)
00186 {
00187 #if DEBUG_FIFO
00188 nldebug("%p pop rewind!", this);
00189 #endif
00190
00191
00192 _Tail = _Buffer;
00193 _Rewinder = NULL;
00194 }
00195
00196 TFifoSize s = *(TFifoSize *)_Tail;
00197
00198 #if DEBUG_FIFO
00199 nldebug("%p pop(%d)", this, s);
00200 #endif
00201
00202 #ifdef NL_DEBUG
00203
00204 memset (_Tail, '-', s + sizeof (TFifoSize));
00205 #endif
00206
00207 _Tail += s + sizeof (TFifoSize);
00208
00209 if (_Tail == _Head) _Empty = true;
00210
00211 #if DEBUG_FIFO
00212 display ();
00213 #endif
00214 }
00215
00216 uint8 CBufFIFO::frontLast ()
00217 {
00218 uint8 *tail = _Tail;
00219
00220 if (empty ())
00221 {
00222 nlwarning("BF: Try to get the front of an empty fifo!");
00223 return 0;
00224 }
00225
00226 if (_Rewinder != NULL && tail == _Rewinder)
00227 {
00228 #if DEBUG_FIFO
00229 nldebug("%p front rewind!", this);
00230 #endif
00231
00232
00233 tail = _Buffer;
00234 }
00235
00236 TFifoSize s = *(TFifoSize *)tail;
00237
00238 #if DEBUG_FIFO
00239 nldebug("%p frontLast() returns %d ", this, s, *(tail+sizeof(TFifoSize)+size-1));
00240 #endif
00241
00242 return *(tail+sizeof(TFifoSize)+s-1);
00243 }
00244
00245
00246 void CBufFIFO::front (vector<uint8> &buffer)
00247 {
00248 uint8 *tmpbuffer;
00249 uint32 s;
00250
00251 buffer.clear ();
00252
00253 front (tmpbuffer, s);
00254
00255 buffer.resize (s);
00256
00257 CFastMem::memcpy (&(buffer[0]), tmpbuffer, s);
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 }
00303
00304
00305 void CBufFIFO::front (NLMISC::CMemStream &buffer)
00306 {
00307 uint8 *tmpbuffer;
00308 uint32 s;
00309
00310 buffer.clear ();
00311
00312 front (tmpbuffer, s);
00313
00314 buffer.fill (tmpbuffer, s);
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 }
00362
00363 void CBufFIFO::front (uint8 *&buffer, uint32 &s)
00364 {
00365 #if STAT_FIFO
00366 TTicks before = CTime::getPerformanceTime ();
00367 #endif
00368
00369 uint8 *tail = _Tail;
00370
00371 if (empty ())
00372 {
00373 nlwarning("BF: Try to get the front of an empty fifo!");
00374 return;
00375 }
00376
00377 _Fronted++;
00378
00379 if (_Rewinder != NULL && tail == _Rewinder)
00380 {
00381 #if DEBUG_FIFO
00382 nldebug("%p front rewind!", this);
00383 #endif
00384
00385
00386 tail = _Buffer;
00387 }
00388
00389 s = *(TFifoSize *)tail;
00390
00391 #if DEBUG_FIFO
00392 nldebug("%p front(%d)", this, s);
00393 #endif
00394
00395 tail += sizeof (TFifoSize);
00396
00397 #if STAT_FIFO
00398
00399 TTicks after = CTime::getPerformanceTime ();
00400 _FrontedTime += after - before;
00401 #endif
00402
00403 #if DEBUG_FIFO
00404 display ();
00405 #endif
00406
00407 buffer = tail;
00408 }
00409
00410
00411
00412 void CBufFIFO::clear ()
00413 {
00414 _Tail = _Head = _Buffer;
00415 _Rewinder = NULL;
00416 _Empty = true;
00417 }
00418
00419 uint32 CBufFIFO::size ()
00420 {
00421 if (empty ())
00422 {
00423 return 0;
00424 }
00425 else if (_Head == _Tail)
00426 {
00427
00428 if (_Rewinder == NULL)
00429 return _BufferSize;
00430 else
00431 return _Rewinder - _Buffer;
00432 }
00433 else if (_Head > _Tail)
00434 {
00435 return _Head - _Tail;
00436 }
00437 else if (_Head < _Tail)
00438 {
00439 nlassert (_Rewinder != NULL);
00440 return (_Rewinder - _Tail) + (_Head - _Buffer);
00441 }
00442 nlstop;
00443 return 0;
00444 }
00445
00446 void CBufFIFO::resize (uint32 s)
00447 {
00448 #if STAT_FIFO
00449 TTicks before = CTime::getPerformanceTime();
00450 #endif
00451
00452 if (s == 0) s = 100;
00453
00454 #if DEBUG_FIFO
00455 nldebug("%p resize(%d)", this, s);
00456 #endif
00457
00458 if (s > _BiggestBuffer) _BiggestBuffer = s;
00459 if (s < _SmallestBuffer) _SmallestBuffer = s;
00460
00461 _Resized++;
00462
00463 uint32 UsedSize = CBufFIFO::size();
00464
00465
00466 if (s < _BufferSize && UsedSize > s)
00467 {
00468
00469 nlwarning("BF: Can't resize the FIFO because there's not enough room in the new wanted buffer (%d bytes needed at least)", UsedSize);
00470 return;
00471 }
00472
00473 uint8 *NewBuffer = new uint8[s];
00474 if (NewBuffer == NULL)
00475 {
00476 nlerror("Not enough memory to resize the FIFO to %u bytes", s);
00477 }
00478 #ifdef NL_DEBUG
00479
00480 memset (NewBuffer, '-', s);
00481 #endif
00482
00483 #if DEBUG_FIFO
00484 nldebug("%p new %d bytes", this, s);
00485 #endif
00486
00487
00488
00489 if (!empty())
00490 {
00491 if (_Tail < _Head)
00492 {
00493 CFastMem::memcpy (NewBuffer, _Tail, UsedSize);
00494 }
00495 else if (_Tail >= _Head)
00496 {
00497 nlassert (_Rewinder != NULL);
00498
00499 uint size1 = _Rewinder - _Tail;
00500 CFastMem::memcpy (NewBuffer, _Tail, size1);
00501 uint size2 = _Head - _Buffer;
00502 CFastMem::memcpy (NewBuffer + size1, _Buffer, size2);
00503
00504 nlassert (size1+size2==UsedSize);
00505 }
00506 }
00507
00508
00509
00510 _Tail = NewBuffer;
00511 _Head = NewBuffer + UsedSize;
00512 _Rewinder = NULL;
00513
00514
00515 if (_Buffer != NULL)
00516 {
00517 delete []_Buffer;
00518 #if DEBUG_FIFO
00519 nldebug ("delete", this);
00520 #endif
00521 }
00522
00523
00524 _Buffer = NewBuffer;
00525 _BufferSize = s;
00526
00527 #if STAT_FIFO
00528 TTicks after = CTime::getPerformanceTime();
00529 _ResizedTime += after - before;
00530 #endif
00531
00532 #if DEBUG_FIFO
00533 display ();
00534 #endif
00535 }
00536
00537 void CBufFIFO::displayStats (CLog *log)
00538 {
00539 log->displayNL ("%p CurrentQueueSize: %d, TotalQueueSize: %d", this, size(), _BufferSize);
00540 log->displayNL ("%p InQueue: %d", this, _Pushed - _Fronted);
00541
00542 log->displayNL ("%p BiggestBlock: %d, SmallestBlock: %d", this, _BiggestBlock, _SmallestBlock);
00543 log->displayNL ("%p BiggestBuffer: %d, SmallestBuffer: %d", this, _BiggestBuffer, _SmallestBuffer);
00544 log->displayNL ("%p Pushed: %d, PushedTime: total %"NL_I64"d ticks, mean %f ticks", this, _Pushed, _PushedTime, (_Pushed>0?(double)(sint64)_PushedTime / (double)_Pushed:0.0));
00545 log->displayNL ("%p Fronted: %d, FrontedTime: total %"NL_I64"d ticks, mean %f ticks", this, _Fronted, _FrontedTime, (_Fronted>0?(double)(sint64)_FrontedTime / (double)_Fronted:0.0));
00546 log->displayNL ("%p Resized: %d, ResizedTime: total %"NL_I64"d ticks, mean %f ticks", this, _Resized, _ResizedTime, (_Resized>0?(double)(sint64)_ResizedTime / (double)_Resized:0.0));
00547 }
00548
00549 void CBufFIFO::display ()
00550 {
00551 int s = 64;
00552 int gran = s/30;
00553
00554 char str[1024];
00555
00556 smprintf(str, 1024, "%p %p (%5d %5d) %p %p %p ", this, _Buffer, _BufferSize, CBufFIFO::size(), _Rewinder, _Tail, _Head);
00557
00558 int i;
00559 for (i = 0; i < (sint32) _BufferSize; i+= gran)
00560 {
00561 uint8 *pos = _Buffer + i;
00562 if (_Tail >= pos && _Tail < pos + gran)
00563 {
00564 if (_Head >= pos && _Head < pos + gran)
00565 {
00566 if (_Rewinder != NULL && _Rewinder >= pos && _Rewinder < pos + gran)
00567 {
00568 strncat (str, "*", 1024);
00569 }
00570 else
00571 {
00572 strncat (str, "@", 1024);
00573 }
00574 }
00575 else
00576 {
00577 strncat (str, "T", 1024);
00578 }
00579 }
00580 else if (_Head >= pos && _Head < pos + gran)
00581 {
00582 strncat (str, "H", 1024);
00583 }
00584 else if (_Rewinder != NULL && _Rewinder >= pos && _Rewinder < pos + gran)
00585 {
00586 strncat (str, "R", 1024);
00587 }
00588 else
00589 {
00590 if (strlen(str) < 1023)
00591 {
00592 uint32 p = strlen(str);
00593 if (isprint(*pos))
00594 str[p] = *pos;
00595 else
00596 str[p] = '$';
00597
00598 str[p+1] = '\0';
00599 }
00600 }
00601 }
00602
00603 for (; i < s; i+= gran)
00604 {
00605 strncat (str, " ", 1024);
00606 }
00607 #ifdef NL_DEBUG
00608 strncat (str, "\n", 1024);
00609 #else
00610 strncat (str, "\r", 1024);
00611 #endif
00612 DebugLog->display (str);
00613 }
00614
00615 bool CBufFIFO::canFit (uint32 s)
00616 {
00617 if (_Tail == _Head)
00618 {
00619 if (empty())
00620 {
00621
00622 if (_BufferSize >= s)
00623 {
00624
00625 #if DEBUG_FIFO
00626 nldebug("%p reset tail and head", this);
00627 #endif
00628 _Head = _Tail = _Buffer;
00629 return true;
00630 }
00631 else
00632 {
00633
00634 #if DEBUG_FIFO
00635 nldebug("%p buffer full buffersize<size", this);
00636 #endif
00637 return false;
00638 }
00639 }
00640 else
00641 {
00642
00643 #if DEBUG_FIFO
00644 nldebug("%p buffer full h=t", this);
00645 #endif
00646 return false;
00647 }
00648 }
00649 else if (_Tail < _Head)
00650 {
00651 if (_Buffer + _BufferSize - _Head >= (sint32) s)
00652 {
00653
00654 #if DEBUG_FIFO
00655 nldebug("%p fit after", this);
00656 #endif
00657 return true;
00658 }
00659 else if (_Tail - _Buffer >= (sint32) s)
00660 {
00661
00662 #if DEBUG_FIFO
00663 nldebug("%p fit at beginning", this);
00664 #endif
00665 _Rewinder = _Head;
00666 #if DEBUG_FIFO
00667 nldebug("%p set the rewinder", this);
00668 #endif
00669 _Head = _Buffer;
00670 return true;
00671 }
00672 else
00673 {
00674
00675 #if DEBUG_FIFO
00676 nldebug("%p no room t<h", this);
00677 #endif
00678 return false;
00679 }
00680 }
00681 else
00682 {
00683 if (_Tail - _Head >= (sint32) s)
00684 {
00685 #if DEBUG_FIFO
00686 nldebug("%p fit t>h", this);
00687 #endif
00688 return true;
00689 }
00690 else
00691 {
00692 #if DEBUG_FIFO
00693 nldebug("%p no room t>h", this);
00694 #endif
00695 return false;
00696 }
00697 }
00698 }
00699
00700 #ifdef BUFFIFO_TRACK_ALL_BUFFERS
00701 NLMISC_CATEGORISED_COMMAND(misc, dumpAllBuffers, "Dump all the fifo buffer", "no args")
00702 {
00703 log.displayNL("Dumping %u FIFO buffers :", CBufFIFO::_AllBuffers.size());
00704
00705 CBufFIFO::TAllBuffers::iterator first(CBufFIFO::_AllBuffers.begin()), last(CBufFIFO::_AllBuffers.end());
00706 for (; first != last; ++first)
00707 {
00708 CBufFIFO *buf = *first;
00709
00710 log.displayNL("Dumping buffer %p:", buf);
00711
00712 buf->displayStats(&log);
00713 }
00714
00715 return true;
00716 }
00717 #endif
00718
00719
00720 }