GameMemory.cpp 110 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Memory.cpp
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: Memory.cpp
  36. //
  37. // Created: Steven Johnson, August 2001
  38. //
  39. // Desc: Memory manager
  40. //
  41. // ----------------------------------------------------------------------------
  42. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  43. // SYSTEM INCLUDES
  44. // USER INCLUDES
  45. #include "Common/GameMemory.h"
  46. #include "Common/CriticalSection.h"
  47. #include "Common/Errors.h"
  48. #include "Common/GlobalData.h"
  49. #include "Common/PerfTimer.h"
  50. #ifdef MEMORYPOOL_DEBUG
  51. #include "GameClient/ClientRandomValue.h"
  52. #endif
  53. #ifdef MEMORYPOOL_STACKTRACE
  54. #include "Common/StackDump.h"
  55. #endif
  56. #ifdef MEMORYPOOL_DEBUG
  57. DECLARE_PERF_TIMER(MemoryPoolDebugging)
  58. DECLARE_PERF_TIMER(MemoryPoolInitFilling)
  59. #endif
  60. #ifdef _INTERNAL
  61. // for occasional debugging...
  62. //#pragma optimize("", off)
  63. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  64. #endif
  65. // ----------------------------------------------------------------------------
  66. // DEFINES
  67. // ----------------------------------------------------------------------------
  68. /**
  69. define MPSB_DLINK to add a backlink to MemoryPoolSingleBlock; this makes it
  70. faster to free raw DMA blocks.
  71. @todo verify this speedup is enough to be worth the extra space
  72. */
  73. #define MPSB_DLINK
  74. #ifdef MEMORYPOOL_DEBUG
  75. /**
  76. if you define MEMORYPOOL_INTENSE_VERIFY, we do intensive verifications after
  77. nearly every memory operation. this is OFF by default, since it slows down
  78. things a lot, but is worth turning on for really obscure memory corruption issues.
  79. */
  80. #ifndef MEMORYPOOL_INTENSE_VERIFY
  81. #define NO_MEMORYPOOL_INTENSE_VERIFY
  82. #endif
  83. /**
  84. if you define MEMORYPOOL_CHECK_BLOCK_OWNERSHIP, we do lots of calls to verify
  85. that a block actually belongs to the pool it is called with. this is great
  86. for debugging, but can be realllly slow, so is off by default.
  87. */
  88. #ifndef MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
  89. #define NO_MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
  90. #endif
  91. static const char* FREE_SINGLEBLOCK_TAG_STRING = "FREE_SINGLEBLOCK_TAG_STRING";
  92. const Short SINGLEBLOCK_MAGIC_COOKIE = 12345;
  93. const Int GARBAGE_FILL_VALUE = 0xdeadbeef;
  94. // flags for m_debugFlags
  95. enum
  96. {
  97. IGNORE_LEAKS = 0x0001
  98. };
  99. // in debug mode (but not internal), save stacktraces too
  100. #if !defined(MEMORYPOOL_CHECKPOINTING) && defined(MEMORYPOOL_STACKTRACE) && defined(_DEBUG)
  101. #define MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
  102. #endif
  103. #define USE_FILLER_VALUE
  104. const Int MAX_INIT_FILLER_COUNT = 8;
  105. #ifdef USE_FILLER_VALUE
  106. static UnsignedInt s_initFillerValue = 0xf00dcafe; // will be replaced, should never be this value at runtime
  107. static void calcFillerValue(Int index)
  108. {
  109. s_initFillerValue = (index & 3) << 1;
  110. s_initFillerValue |= 0x01;
  111. s_initFillerValue |= (~(s_initFillerValue << 4)) & 0xf0;
  112. s_initFillerValue |= (s_initFillerValue << 8);
  113. s_initFillerValue |= (s_initFillerValue << 16);
  114. DEBUG_LOG(("Setting MemoryPool initFillerValue to %08x (index %d)\n",s_initFillerValue,index));
  115. }
  116. #endif
  117. #endif
  118. #ifdef MEMORYPOOL_BOUNDINGWALL
  119. #define WALLCOUNT (2) // default setting of 8 requires 4*4*2==32 extra bytes PER BLOCK
  120. #define WALLSIZE (WALLCOUNT * sizeof(Int))
  121. #endif
  122. #ifdef MEMORYPOOL_STACKTRACE
  123. #define MEMORYPOOL_STACKTRACE_SIZE (20)
  124. #define MEMORYPOOL_STACKTRACE_SKIP_SIZE (6)
  125. #define MEMORYPOOL_STACKTRACE_SIZE_BYTES (MEMORYPOOL_STACKTRACE_SIZE * sizeof(void*))
  126. #endif
  127. // ----------------------------------------------------------------------------
  128. // PRIVATE DATA
  129. // ----------------------------------------------------------------------------
  130. #ifdef MEMORYPOOL_BOUNDINGWALL
  131. static Int theBoundingWallPattern = 0xbabeface;
  132. #endif
  133. #ifdef MEMORYPOOL_STACKTRACE
  134. /** the max number levels to dump in the stacktrace. a variable rather than
  135. constant so that you can fiddle with it in the debugger if desired, to
  136. get shorter or longer dumps. (you can't go longer than MEMORYPOOL_STACKTRACE_SIZE
  137. in any event. */
  138. static Int theStackTraceDepth = 16;
  139. #endif
  140. #ifdef MEMORYPOOL_DEBUG
  141. static Int theTotalSystemAllocationInBytes = 0;
  142. static Int thePeakSystemAllocationInBytes = 0;
  143. static Int theTotalLargeBlocks = 0;
  144. static Int thePeakLargeBlocks = 0;
  145. Int theTotalDMA = 0;
  146. Int thePeakDMA = 0;
  147. Int theWastedDMA = 0;
  148. Int thePeakWastedDMA = 0;
  149. #define NO_INTENSE_DMA_BOOKKEEPING
  150. #ifdef INTENSE_DMA_BOOKKEEPING
  151. struct UsedNPeak
  152. {
  153. Int used, peak, waste, peakwaste;
  154. UsedNPeak() : used(0), peak(0), waste(0), peakwaste(0) { }
  155. };
  156. typedef std::map< const char*, UsedNPeak, std::less<const char*> > UsedNPeakMap;
  157. static UsedNPeakMap TheUsedNPeakMap;
  158. static Int doingIntenseDMA = 0;
  159. #endif
  160. #endif
  161. static Bool thePreMainInitFlag = false;
  162. static Bool theMainInitFlag = false;
  163. // ----------------------------------------------------------------------------
  164. // PRIVATE PROTOTYPES
  165. // ----------------------------------------------------------------------------
  166. /// @todo srj -- make this work for 8
  167. #define MEM_BOUND_ALIGNMENT 4
  168. static Int roundUpMemBound(Int i);
  169. static void *sysAllocate(Int numBytes);
  170. static void *sysAllocateDoNotZero(Int numBytes);
  171. static void sysFree(void* p);
  172. static void memset32(void* ptr, Int value, Int bytesToFill);
  173. #ifdef MEMORYPOOL_STACKTRACE
  174. static void doStackDumpOutput(const char* m);
  175. static void doStackDump(void **stacktrace, int size);
  176. #endif
  177. static void preMainInitMemoryManager();
  178. // ----------------------------------------------------------------------------
  179. // PRIVATE FUNCTIONS
  180. // ----------------------------------------------------------------------------
  181. //-----------------------------------------------------------------------------
  182. /** round up to the nearest multiple of MEM_BOUND_ALIGNMENT */
  183. static Int roundUpMemBound(Int i)
  184. {
  185. return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1);
  186. }
  187. //-----------------------------------------------------------------------------
  188. /**
  189. identical to sysAllocateDoNotZero, except that the memory block returned
  190. is filled to all-zero-bytes.
  191. */
  192. static void* sysAllocate(Int numBytes)
  193. {
  194. void* p = ::GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, numBytes);
  195. if (!p)
  196. throw ERROR_OUT_OF_MEMORY;
  197. #ifdef MEMORYPOOL_DEBUG
  198. {
  199. USE_PERF_TIMER(MemoryPoolDebugging)
  200. theTotalSystemAllocationInBytes += ::GlobalSize(p);
  201. if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes)
  202. thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes;
  203. }
  204. #endif
  205. return p;
  206. }
  207. //-----------------------------------------------------------------------------
  208. /**
  209. this is the low-level allocator that we use to request memory from the OS.
  210. all (repeat, all) memory allocations in this module should ultimately
  211. go thru this routine (or sysAllocate).
  212. note: throws ERROR_OUT_OF_MEMORY on failure; never returns null
  213. */
  214. static void* sysAllocateDoNotZero(Int numBytes)
  215. {
  216. void* p = ::GlobalAlloc(GMEM_FIXED, numBytes);
  217. if (!p)
  218. throw ERROR_OUT_OF_MEMORY;
  219. #ifdef MEMORYPOOL_DEBUG
  220. {
  221. USE_PERF_TIMER(MemoryPoolDebugging)
  222. #ifdef USE_FILLER_VALUE
  223. {
  224. USE_PERF_TIMER(MemoryPoolInitFilling)
  225. ::memset32(p, s_initFillerValue, ::GlobalSize(p));
  226. }
  227. #endif
  228. theTotalSystemAllocationInBytes += ::GlobalSize(p);
  229. if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes)
  230. thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes;
  231. }
  232. #endif
  233. return p;
  234. }
  235. //-----------------------------------------------------------------------------
  236. /**
  237. the counterpart to sysAllocate / sysAllocateDoNotZero; used to free blocks
  238. allocated by them. it is OK to pass null here (it will just be ignored).
  239. */
  240. static void sysFree(void* p)
  241. {
  242. if (p)
  243. {
  244. #ifdef MEMORYPOOL_DEBUG
  245. {
  246. USE_PERF_TIMER(MemoryPoolDebugging)
  247. ::memset32(p, GARBAGE_FILL_VALUE, ::GlobalSize(p));
  248. theTotalSystemAllocationInBytes -= ::GlobalSize(p);
  249. }
  250. #endif
  251. ::GlobalFree(p);
  252. }
  253. }
  254. // ----------------------------------------------------------------------------
  255. /**
  256. fills memory with a 32-bit value (note: assumes the ptr is 4-byte-aligned)
  257. */
  258. static void memset32(void* ptr, Int value, Int bytesToFill)
  259. {
  260. Int wordsToFill = bytesToFill>>2;
  261. bytesToFill -= (wordsToFill<<2);
  262. Int *p = (Int*)ptr;
  263. for (++wordsToFill; --wordsToFill; )
  264. *p++ = value;
  265. Byte *b = (Byte *)p;
  266. for (++bytesToFill; --bytesToFill; )
  267. *b++ = (Byte)value;
  268. }
  269. #ifdef MEMORYPOOL_STACKTRACE
  270. // ----------------------------------------------------------------------------
  271. /**
  272. This is just a convenience routine that dumps output from the StackDump module
  273. to our normal debug log file, with a little massaging for formatting.
  274. */
  275. static void doStackDumpOutput(const char* m)
  276. {
  277. const char *PREPEND = "STACKTRACE";
  278. if (*m == 0 || strcmp(m, "\n") == 0)
  279. {
  280. DEBUG_LOG((m));
  281. }
  282. else
  283. {
  284. // Note - I am moving the prepend to the end, as this allows double clicking in the
  285. // output window to open the file in VisualStudio. jba.
  286. DEBUG_LOG(("%s, %s",m, PREPEND));
  287. }
  288. }
  289. #endif
  290. #ifdef MEMORYPOOL_STACKTRACE
  291. // ----------------------------------------------------------------------------
  292. /**
  293. dump the given stacktrace to the debug log.
  294. */
  295. static void doStackDump(void **stacktrace, int size)
  296. {
  297. ::doStackDumpOutput("Allocation Stack Trace:");
  298. ::doStackDumpOutput("\n");
  299. ::StackDumpFromAddresses(stacktrace, size, ::doStackDumpOutput);
  300. }
  301. #endif
  302. // ----------------------------------------------------------------------------
  303. // PRIVATE TYPES
  304. // ----------------------------------------------------------------------------
  305. // ----------------------------------------------------------------------------
  306. #ifdef MEMORYPOOL_CHECKPOINTING
  307. /**
  308. This is a auxiliary record that we allocate in debug modes (actually, checkpoint modes)
  309. to retain extra information about blocks; there is a one-to-one correspondence
  310. between this record and a block allocation. The interesting bit about this record is that
  311. we don't deallocate it when the corresponding block is freed; we retain it so we can
  312. later provide information about what blocks were freed when, etc. Yes, this does chew
  313. up a lot of memory! That's why it's debug-mode only; the presumption is that developers
  314. machines have boatloads of RAM. (Note that we *do* free these when resetCheckpoints() is called.)
  315. Note also that we directly allocate/free these with sysAllocate/sysFree, so ctors/dtors
  316. are never executed, nor would virtual functions work -- I know, it's a little evil.
  317. */
  318. class BlockCheckpointInfo
  319. {
  320. private:
  321. BlockCheckpointInfo *m_next; ///< next checkpoint in this pool/dma
  322. const char *m_debugLiteralTagString; ///< the tagstring for the block
  323. Int m_allocCheckpoint; ///< when it was allocated
  324. Int m_freeCheckpoint; ///< when it was freed (-1 if still in existence)
  325. Int m_blockSize; ///< logical size of the block
  326. #ifdef MEMORYPOOL_STACKTRACE
  327. void* m_stacktrace[MEMORYPOOL_STACKTRACE_SIZE]; ///< stacktrace of when block was allocated
  328. #endif
  329. ~BlockCheckpointInfo() {};
  330. public:
  331. BlockCheckpointInfo *getNext(); ///< return next checkpointinfo for this pool/dma
  332. void debugSetFreepoint(Int f); ///< set the checkpoint at which the block was freed.
  333. #ifdef MEMORYPOOL_STACKTRACE
  334. void **getStacktraceInfo(); ///< return a ptr to the allocation stacktrace info.
  335. #endif
  336. static BlockCheckpointInfo *addToList(
  337. BlockCheckpointInfo **pHead,
  338. const char *debugLiteralTagString,
  339. Int allocCheckpoint,
  340. Int blockSize
  341. );
  342. static void freeList(BlockCheckpointInfo **pHead);
  343. Bool shouldBeInReport(Int flags, Int startCheckpoint, Int endCheckpoint);
  344. static void doBlockCheckpointReport( BlockCheckpointInfo *bi, const char *poolName,
  345. Int flags, Int startCheckpoint, Int endCheckpoint );
  346. };
  347. #endif
  348. // ----------------------------------------------------------------------------
  349. /**
  350. This is the fundamental allocation unit; when you allocate via (say) MemoryPool::allocateBlock,
  351. this is what is being allocated for you. (Of course, you don't see the private fields.)
  352. For the most part, we allocate big chunks of these in a monolithic Blob and subdivide
  353. from there. (However, we occasionally allocate these individually, for large blocks.)
  354. Note also that we directly allocate/free these with sysAllocate/sysFree, so ctors/dtors
  355. are never executed, nor would virtual functions work -- I know, it's a little evil.
  356. */
  357. class MemoryPoolSingleBlock
  358. {
  359. private:
  360. MemoryPoolBlob *m_owningBlob; ///< will be NULL if the single block was allocated via sysAllocate()
  361. MemoryPoolSingleBlock *m_nextBlock; ///< if m_owningBlob is nonnull, this points to next free (unallocated) block in the blob; if m_owningBlob is null, this points to the next used (allocated) raw block in the pool.
  362. #ifdef MPSB_DLINK
  363. MemoryPoolSingleBlock *m_prevBlock; ///< if m_owningBlob is nonnull, this points to prev free (unallocated) block in the blob; if m_owningBlob is null, this points to the prev used (allocated) raw block in the pool.
  364. #endif
  365. #ifdef MEMORYPOOL_CHECKPOINTING
  366. BlockCheckpointInfo *m_checkpointInfo; ///< ptr to the checkpointinfo for this block
  367. #endif
  368. #ifdef MEMORYPOOL_BOUNDINGWALL
  369. Int m_wallPattern; ///< unique seed value for the bounding-walls for this block
  370. #endif
  371. #ifdef MEMORYPOOL_DEBUG
  372. const char *m_debugLiteralTagString; ///< ptr to the tagstring for this block.
  373. Int m_logicalSize; ///< logical size of block (not including overhead, walls, etc.)
  374. Int m_wastedSize; ///< if allocated via DMA, the "wasted" bytes
  375. Short m_magicCookie; ///< magic value used to verify that the block is one of ours (as opposed to random pointer)
  376. Short m_debugFlags; ///< misc flags
  377. #ifdef MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
  378. void* m_stacktrace[MEMORYPOOL_STACKTRACE_SIZE]; ///< stacktrace of when block was allocated (if not checkpointing)
  379. #endif
  380. #endif
  381. private:
  382. void* getUserDataNoDbg();
  383. #ifdef MEMORYPOOL_BOUNDINGWALL
  384. void debugFillInWalls();
  385. #endif
  386. public:
  387. static Int calcRawBlockSize(Int logicalSize);
  388. static MemoryPoolSingleBlock *rawAllocateSingleBlock(MemoryPoolSingleBlock **pRawListHead, Int logicalSize, MemoryPoolFactory *owningFactory DECLARE_LITERALSTRING_ARG2);
  389. void removeBlockFromList(MemoryPoolSingleBlock **pHead);
  390. void initBlock(Int logicalSize, MemoryPoolBlob *owningBlob, MemoryPoolFactory *owningFactory DECLARE_LITERALSTRING_ARG2);
  391. void* getUserData();
  392. static MemoryPoolSingleBlock *recoverBlockFromUserData(void* pUserData);
  393. MemoryPoolBlob *getOwningBlob();
  394. MemoryPoolSingleBlock *getNextFreeBlock();
  395. void setNextFreeBlock(MemoryPoolSingleBlock *b);
  396. MemoryPoolSingleBlock *getNextRawBlock();
  397. void setNextRawBlock(MemoryPoolSingleBlock *b);
  398. #ifdef MEMORYPOOL_DEBUG
  399. void debugIgnoreLeaksForThisBlock();
  400. const char *debugGetLiteralTagString();
  401. Int debugGetLogicalSize();
  402. Int debugGetWastedSize();
  403. void debugSetWastedSize(Int waste);
  404. void debugVerifyBlock();
  405. void debugMarkBlockAsFree();
  406. Bool debugCheckUnderrun();
  407. Bool debugCheckOverrun();
  408. Int debugSingleBlockReportLeak(const char* owner);
  409. #endif // MEMORYPOOL_DEBUG
  410. #ifdef MEMORYPOOL_CHECKPOINTING
  411. BlockCheckpointInfo *debugGetCheckpointInfo();
  412. void debugSetCheckpointInfo(BlockCheckpointInfo *bi);
  413. void debugResetCheckpoint();
  414. #endif
  415. };
  416. // ----------------------------------------------------------------------------
  417. class MemoryPoolBlob
  418. {
  419. private:
  420. MemoryPool *m_owningPool; ///< the pool that owns this blob
  421. MemoryPoolBlob *m_nextBlob; ///< next blob in this pool
  422. MemoryPoolBlob *m_prevBlob; ///< prev blob in this pool
  423. MemoryPoolSingleBlock *m_firstFreeBlock; ///< ptr to first available block in this blob
  424. Int m_usedBlocksInBlob; ///< total allocated blocks in this blob
  425. Int m_totalBlocksInBlob; ///< total blocks in this blob (allocated + available)
  426. char *m_blockData; ///< ptr to the blocks (really a MemoryPoolSingleBlock*)
  427. public:
  428. MemoryPoolBlob();
  429. ~MemoryPoolBlob();
  430. void initBlob(MemoryPool *owningPool, Int allocationCount);
  431. void addBlobToList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail);
  432. void removeBlobFromList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail);
  433. MemoryPoolBlob *getNextInList();
  434. Bool hasAnyFreeBlocks();
  435. MemoryPoolSingleBlock *allocateSingleBlock(DECLARE_LITERALSTRING_ARG1);
  436. void freeSingleBlock(MemoryPoolSingleBlock *block);
  437. MemoryPool *getOwningPool();
  438. Int getFreeBlockCount();
  439. Int getUsedBlockCount();
  440. Int getTotalBlockCount();
  441. #ifdef MEMORYPOOL_DEBUG
  442. void debugMemoryVerifyBlob();
  443. Int debugBlobReportLeaks(const char* owner);
  444. Bool debugIsBlockInBlob(void *pBlock);
  445. #endif
  446. #ifdef MEMORYPOOL_CHECKPOINTING
  447. void debugResetCheckpoints();
  448. #endif
  449. };
  450. // ----------------------------------------------------------------------------
  451. // PUBLIC DATA
  452. // ----------------------------------------------------------------------------
  453. MemoryPoolFactory *TheMemoryPoolFactory = NULL;
  454. DynamicMemoryAllocator *TheDynamicMemoryAllocator = NULL;
  455. // ----------------------------------------------------------------------------
  456. // INLINES
  457. // ----------------------------------------------------------------------------
  458. //-----------------------------------------------------------------------------
  459. #ifdef MEMORYPOOL_CHECKPOINTING
  460. inline BlockCheckpointInfo *BlockCheckpointInfo::getNext() { return m_next; }
  461. inline void BlockCheckpointInfo::debugSetFreepoint(Int f) { DEBUG_ASSERTCRASH(m_freeCheckpoint == -1, ("already have a freepoint")); m_freeCheckpoint = f; }
  462. #ifdef MEMORYPOOL_STACKTRACE
  463. inline void **BlockCheckpointInfo::getStacktraceInfo() { return m_stacktrace; }
  464. #endif
  465. #endif
  466. // ----------------------------------------------------------------------------
  467. /**
  468. return a ptr to the user-data area of the block (ie, the part the enduser can deal with).
  469. this call does NO debug verification and is for internal use of class MemoryPoolSingleBlock only.
  470. */
  471. inline void* MemoryPoolSingleBlock::getUserDataNoDbg()
  472. {
  473. char* p = ((char*)this) + sizeof(MemoryPoolSingleBlock);
  474. #ifdef MEMORYPOOL_BOUNDINGWALL
  475. p += WALLSIZE;
  476. #endif
  477. return (void*)p;
  478. }
  479. /**
  480. return a ptr to the user-data area of the block (ie, the part the enduser can deal with).
  481. this call verifies that the block is valid in debug mode.
  482. */
  483. inline void* MemoryPoolSingleBlock::getUserData()
  484. {
  485. // yes, verify the block in this case for plain debug mode (not intense-verify mode)
  486. #ifdef MEMORYPOOL_DEBUG
  487. debugVerifyBlock();
  488. #endif
  489. return getUserDataNoDbg();
  490. }
  491. /**
  492. given a desired logical block size, calculate the physical size needed for each
  493. MemoryPoolSingleBlock (including overhead, etc.)
  494. */
  495. inline /*static*/ Int MemoryPoolSingleBlock::calcRawBlockSize(Int logicalSize)
  496. {
  497. Int s = ::roundUpMemBound(logicalSize) + sizeof(MemoryPoolSingleBlock);
  498. #ifdef MEMORYPOOL_BOUNDINGWALL
  499. s += WALLSIZE*2;
  500. #endif
  501. return s;
  502. }
  503. /**
  504. accessor
  505. */
  506. inline MemoryPoolBlob *MemoryPoolSingleBlock::getOwningBlob()
  507. {
  508. return m_owningBlob;
  509. }
  510. /**
  511. return the next free block in this blob. this call assumes that the block
  512. in question belongs to a blob, and will assert if not.
  513. */
  514. inline MemoryPoolSingleBlock *MemoryPoolSingleBlock::getNextFreeBlock()
  515. {
  516. DEBUG_ASSERTCRASH(m_owningBlob != NULL, ("must be called on blob block"));
  517. return m_nextBlock;
  518. }
  519. /**
  520. set the next free block in this blob. this call assumes that both blocks
  521. in question belongs to a blob, but will NOT assert if not, since it may be
  522. called when the blocks are in an inconsistent state.
  523. */
  524. inline void MemoryPoolSingleBlock::setNextFreeBlock(MemoryPoolSingleBlock *b)
  525. {
  526. //DEBUG_ASSERTCRASH(m_owningBlob != NULL && b->m_owningBlob != NULL, ("must be called on blob block"));
  527. // don't check the 'b' block -- we need to call this before 'b' is fully initialized.
  528. DEBUG_ASSERTCRASH(m_owningBlob != NULL, ("must be called on blob block"));
  529. this->m_nextBlock = b;
  530. #ifdef MPSB_DLINK
  531. if (b) {
  532. b->m_prevBlock = this;
  533. }
  534. #endif
  535. }
  536. /**
  537. return the next raw block in this dma. this call assumes that the block
  538. in question does NOT belong to a blob, and will assert if not.
  539. */
  540. inline MemoryPoolSingleBlock *MemoryPoolSingleBlock::getNextRawBlock()
  541. {
  542. DEBUG_ASSERTCRASH(m_owningBlob == NULL, ("must be called on raw block"));
  543. return m_nextBlock;
  544. }
  545. /**
  546. set the next raw block in this dma. this call assumes that the blocks
  547. in question do NOT belong to a blob, and will assert if not.
  548. */
  549. inline void MemoryPoolSingleBlock::setNextRawBlock(MemoryPoolSingleBlock *b)
  550. {
  551. DEBUG_ASSERTCRASH(m_owningBlob == NULL && (!b || b->m_owningBlob == NULL), ("must be called on raw block"));
  552. m_nextBlock = b;
  553. #ifdef MPSB_DLINK
  554. if (b)
  555. b->m_prevBlock = this;
  556. #endif
  557. }
  558. #ifdef MEMORYPOOL_DEBUG
  559. inline void MemoryPoolSingleBlock::debugIgnoreLeaksForThisBlock()
  560. {
  561. //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
  562. m_debugFlags |= IGNORE_LEAKS;
  563. }
  564. /**
  565. accessor
  566. */
  567. inline const char *MemoryPoolSingleBlock::debugGetLiteralTagString()
  568. {
  569. //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
  570. return m_debugLiteralTagString;
  571. }
  572. #endif
  573. #ifdef MEMORYPOOL_DEBUG
  574. /**
  575. accessor
  576. */
  577. inline Int MemoryPoolSingleBlock::debugGetLogicalSize()
  578. {
  579. //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
  580. return m_logicalSize;
  581. }
  582. #endif
  583. #ifdef MEMORYPOOL_DEBUG
  584. /**
  585. accessor
  586. */
  587. inline Int MemoryPoolSingleBlock::debugGetWastedSize()
  588. {
  589. //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
  590. return m_wastedSize;
  591. }
  592. #endif
  593. #ifdef MEMORYPOOL_DEBUG
  594. inline void MemoryPoolSingleBlock::debugSetWastedSize(Int w)
  595. {
  596. //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
  597. m_wastedSize = w;
  598. }
  599. #endif
  600. #ifdef MEMORYPOOL_CHECKPOINTING
  601. /**
  602. accessor
  603. */
  604. inline BlockCheckpointInfo *MemoryPoolSingleBlock::debugGetCheckpointInfo()
  605. {
  606. return m_checkpointInfo;
  607. }
  608. #endif
  609. #ifdef MEMORYPOOL_CHECKPOINTING
  610. /**
  611. set the checkpoint info for this block.
  612. */
  613. inline void MemoryPoolSingleBlock::debugSetCheckpointInfo(BlockCheckpointInfo *bi)
  614. {
  615. DEBUG_ASSERTCRASH(m_checkpointInfo == NULL, ("should be null"));
  616. m_checkpointInfo = bi;
  617. }
  618. #endif
  619. #ifdef MEMORYPOOL_CHECKPOINTING
  620. /**
  621. sets the checkpointinfo to null, but does NOT free it... the checkpointinfo
  622. is expected to be freed elsewhere.
  623. */
  624. inline void MemoryPoolSingleBlock::debugResetCheckpoint()
  625. {
  626. m_checkpointInfo = NULL;
  627. }
  628. #endif
  629. // ----------------------------------------------------------------------------
  630. /// accessor
  631. inline MemoryPoolBlob *MemoryPoolBlob::getNextInList() { return m_nextBlob; }
  632. /// accessor
  633. inline Bool MemoryPoolBlob::hasAnyFreeBlocks() { return m_firstFreeBlock != NULL; }
  634. /// accessor
  635. inline MemoryPool *MemoryPoolBlob::getOwningPool() { return m_owningPool; }
  636. /// accessor
  637. inline Int MemoryPoolBlob::getFreeBlockCount() { return getTotalBlockCount() - getUsedBlockCount(); }
  638. /// accessor
  639. inline Int MemoryPoolBlob::getUsedBlockCount() { return m_usedBlocksInBlob; }
  640. /// accessor
  641. inline Int MemoryPoolBlob::getTotalBlockCount() { return m_totalBlocksInBlob; }
  642. //-----------------------------------------------------------------------------
  643. // METHODS for BlockCheckpointInfo
  644. //-----------------------------------------------------------------------------
  645. //-----------------------------------------------------------------------------
  646. #ifdef MEMORYPOOL_CHECKPOINTING
  647. /// return true iff this checkpointinfo should be included in a checkpointreport with the given parameters.
  648. Bool BlockCheckpointInfo::shouldBeInReport(Int flags, Int startCheckpoint, Int endCheckpoint)
  649. {
  650. Bool allocFlagsOK = false;
  651. Bool freedFlagsOK = false;
  652. if (m_allocCheckpoint < startCheckpoint && (flags & _REPORT_CP_ALLOCATED_BEFORE))
  653. allocFlagsOK = true;
  654. if (m_allocCheckpoint >= startCheckpoint && m_allocCheckpoint < endCheckpoint && (flags & _REPORT_CP_ALLOCATED_BETWEEN))
  655. allocFlagsOK = true;
  656. if (m_freeCheckpoint == -1)
  657. {
  658. // block still exists! process this only if we want 'em.
  659. freedFlagsOK = (flags & _REPORT_CP_FREED_NEVER) ? true : false;
  660. }
  661. else
  662. {
  663. if (m_freeCheckpoint < startCheckpoint && (flags & _REPORT_CP_FREED_BEFORE))
  664. freedFlagsOK = true;
  665. if (m_freeCheckpoint >= startCheckpoint && m_freeCheckpoint < endCheckpoint && (flags & _REPORT_CP_FREED_BETWEEN))
  666. freedFlagsOK = true;
  667. }
  668. // the block must match both the 'alloc' and 'free' criteria to get a report
  669. return allocFlagsOK && freedFlagsOK;
  670. }
  671. #endif
  672. //-----------------------------------------------------------------------------
  673. #ifdef MEMORYPOOL_CHECKPOINTING
  674. /// print a checkpointreport for the given checkpointinfo. if checkpointinfo is null, print column headers.
  675. /*static*/ void BlockCheckpointInfo::doBlockCheckpointReport(BlockCheckpointInfo *bi,
  676. const char *poolName, Int flags, Int startCheckpoint, Int endCheckpoint )
  677. {
  678. const char *PREPEND = "BLOCKINFO"; // allows grepping more easily
  679. if (!bi)
  680. {
  681. DEBUG_LOG(("%s,%32s,%6s,%6s,%6s,%s\n",PREPEND,"POOLNAME","BLKSZ","ALLOC","FREED","BLOCKNAME"));
  682. }
  683. else
  684. {
  685. DEBUG_ASSERTCRASH(startCheckpoint >= 0 && startCheckpoint <= endCheckpoint, ("bad checkpoints"));
  686. DEBUG_ASSERTCRASH((flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0, ("bad flags: must set at least one alloc flag"));
  687. DEBUG_ASSERTCRASH((flags & _REPORT_CP_FREED_DONTCARE) != 0, ("bad flags: must set at least one freed flag"));
  688. if (bi->shouldBeInReport(flags, startCheckpoint, endCheckpoint))
  689. {
  690. DEBUG_LOG(("%s,%32s,%6d,%6d,%6d,%s\n",PREPEND,poolName,bi->m_blockSize,bi->m_allocCheckpoint,bi->m_freeCheckpoint,bi->m_debugLiteralTagString));
  691. #ifdef MEMORYPOOL_STACKTRACE
  692. if (flags & REPORT_CP_STACKTRACE)
  693. {
  694. ::doStackDump(bi->m_stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth ));
  695. }
  696. #endif
  697. }
  698. }
  699. }
  700. #endif
  701. // ----------------------------------------------------------------------------
  702. #ifdef MEMORYPOOL_CHECKPOINTING
  703. /// free an entire list of checkpointinfos.
  704. /*static*/ void BlockCheckpointInfo::freeList(BlockCheckpointInfo **pHead)
  705. {
  706. BlockCheckpointInfo *p = *pHead;
  707. while (p)
  708. {
  709. BlockCheckpointInfo *n = p->m_next;
  710. ::sysFree((void *)p);
  711. p = n;
  712. }
  713. *pHead = NULL;
  714. }
  715. #endif
  716. // ----------------------------------------------------------------------------
  717. #ifdef MEMORYPOOL_CHECKPOINTING
  718. /**
  719. allocate a new checkpointinfo with the given tag/checkpoint/size, add it to the
  720. linked list, and return the checkpointinfo. (note that this will NOT throw an exception;
  721. if there is not enough memory to allocate a new checkpointinfo, it will quietly return null.)
  722. */
  723. /*static*/ BlockCheckpointInfo *BlockCheckpointInfo::addToList(
  724. BlockCheckpointInfo **pHead,
  725. const char *debugLiteralTagString,
  726. Int allocCheckpoint,
  727. Int blockSize
  728. )
  729. {
  730. DEBUG_ASSERTCRASH(debugLiteralTagString != FREE_SINGLEBLOCK_TAG_STRING, ("bad tag string"));
  731. BlockCheckpointInfo *freed = NULL;
  732. try {
  733. freed = (BlockCheckpointInfo *)::sysAllocate(sizeof(BlockCheckpointInfo));
  734. } catch (...) {
  735. freed = NULL;
  736. }
  737. if (freed)
  738. {
  739. DEBUG_ASSERTCRASH(debugLiteralTagString != NULL, ("null tagstrings are not allowed"));
  740. freed->m_debugLiteralTagString = debugLiteralTagString;
  741. freed->m_allocCheckpoint = allocCheckpoint;
  742. freed->m_freeCheckpoint = -1;
  743. freed->m_blockSize = blockSize;
  744. freed->m_next = *pHead;
  745. *pHead = freed;
  746. }
  747. return freed;
  748. }
  749. #endif
  750. //-----------------------------------------------------------------------------
  751. // METHODS for MemoryPoolSingleBlock
  752. //-----------------------------------------------------------------------------
  753. //-----------------------------------------------------------------------------
  754. /**
  755. fill in a block's fields. this is usually done only just after a block is allocated,
  756. but might also be done at other points in debug mode.
  757. */
  758. void MemoryPoolSingleBlock::initBlock(Int logicalSize, MemoryPoolBlob *owningBlob,
  759. MemoryPoolFactory *owningFactory DECLARE_LITERALSTRING_ARG2)
  760. {
  761. // Note that while it is OK for owningBlob to be null, it is NEVER ok
  762. // for owningFactory to be null.
  763. DEBUG_ASSERTCRASH(owningFactory, ("null factory"));
  764. #ifdef MEMORYPOOL_DEBUG
  765. {
  766. USE_PERF_TIMER(MemoryPoolDebugging)
  767. m_magicCookie = SINGLEBLOCK_MAGIC_COOKIE;
  768. m_debugFlags = 0;
  769. if (!theMainInitFlag)
  770. debugIgnoreLeaksForThisBlock();
  771. DEBUG_ASSERTCRASH(debugLiteralTagString != NULL, ("null tagstrings are not allowed"));
  772. m_debugLiteralTagString = debugLiteralTagString;
  773. m_logicalSize = logicalSize;
  774. m_wastedSize = 0;
  775. #ifdef MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
  776. if (theStackTraceDepth > 0 && (!TheGlobalData || TheGlobalData->m_checkForLeaks))
  777. {
  778. memset(m_stacktrace, 0, MEMORYPOOL_STACKTRACE_SIZE_BYTES);
  779. ::FillStackAddresses(m_stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth), MEMORYPOOL_STACKTRACE_SKIP_SIZE);
  780. }
  781. else
  782. {
  783. m_stacktrace[0] = NULL;
  784. }
  785. #endif
  786. }
  787. #endif MEMORYPOOL_DEBUG
  788. #ifdef MEMORYPOOL_CHECKPOINTING
  789. m_checkpointInfo = NULL;
  790. #endif
  791. #ifdef MEMORYPOOL_BOUNDINGWALL
  792. m_wallPattern = theBoundingWallPattern++;
  793. debugFillInWalls();
  794. #endif
  795. m_nextBlock = NULL;
  796. #ifdef MPSB_DLINK
  797. m_prevBlock = NULL;
  798. #endif
  799. m_owningBlob = owningBlob; // could be NULL
  800. }
  801. //-----------------------------------------------------------------------------
  802. /**
  803. given a 'public' ptr to a block (ie, the ptr returned by the MemoryPool::allocateBlock),
  804. recover the ptr to the MemoryPoolSingleBlock, so we can access the hidden fields.
  805. */
  806. /* static */ MemoryPoolSingleBlock *MemoryPoolSingleBlock::recoverBlockFromUserData(void* pUserData)
  807. {
  808. DEBUG_ASSERTCRASH(pUserData, ("null pUserData"));
  809. if (!pUserData)
  810. return NULL;
  811. char* p = ((char*)pUserData) - sizeof(MemoryPoolSingleBlock);
  812. #ifdef MEMORYPOOL_BOUNDINGWALL
  813. p -= WALLSIZE;
  814. #endif
  815. MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)p;
  816. // yes, verify the block in this case for plain debug mode (not intense-verify mode)
  817. #ifdef MEMORYPOOL_DEBUG
  818. block->debugVerifyBlock();
  819. #endif
  820. return block;
  821. }
  822. //-----------------------------------------------------------------------------
  823. /**
  824. allocate and initialize a single block. this should only used by DynamicMemoryAllocator
  825. when allocating an extraordinarily large block.
  826. */
  827. /*static*/ MemoryPoolSingleBlock *MemoryPoolSingleBlock::rawAllocateSingleBlock(
  828. MemoryPoolSingleBlock **pRawListHead,
  829. Int logicalSize,
  830. MemoryPoolFactory *owningFactory
  831. DECLARE_LITERALSTRING_ARG2)
  832. {
  833. MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)::sysAllocateDoNotZero(calcRawBlockSize(logicalSize));
  834. block->initBlock(logicalSize, NULL, owningFactory PASS_LITERALSTRING_ARG2);
  835. block->setNextRawBlock(*pRawListHead);
  836. *pRawListHead = block;
  837. return block;
  838. }
  839. //-----------------------------------------------------------------------------
  840. /**
  841. remove the block from the list, which is presumed to be a list of raw blocks.
  842. generally, only the DynamicMemoryAllocator should call this.
  843. */
  844. void MemoryPoolSingleBlock::removeBlockFromList(MemoryPoolSingleBlock **pHead)
  845. {
  846. DEBUG_ASSERTCRASH(this->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
  847. #ifdef MPSB_DLINK
  848. DEBUG_ASSERTCRASH(this->m_nextBlock == NULL || this->m_nextBlock->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
  849. if (this->m_prevBlock)
  850. {
  851. DEBUG_ASSERTCRASH(this->m_prevBlock->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
  852. DEBUG_ASSERTCRASH(*pHead != this, ("bad linkage"));
  853. this->m_prevBlock->m_nextBlock = this->m_nextBlock;
  854. }
  855. else
  856. {
  857. DEBUG_ASSERTCRASH(*pHead == this, ("bad linkage"));
  858. *pHead = this->m_nextBlock;
  859. }
  860. if (this->m_nextBlock)
  861. {
  862. DEBUG_ASSERTCRASH(this->m_nextBlock->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
  863. this->m_nextBlock->m_prevBlock = this->m_prevBlock;
  864. }
  865. #else
  866. // this isn't very efficient, and may need upgrading... but to do so
  867. // would require adding a back link, so I'd rather do some testing
  868. // first to see if it's really a speed issue in practice. (the only place
  869. // this is used is when freeing 'raw' blocks allocated via the DMA).
  870. MemoryPoolSingleBlock *prev = NULL;
  871. for (MemoryPoolSingleBlock *cur = *pHead; cur; cur = cur->m_nextBlock)
  872. {
  873. DEBUG_ASSERTCRASH(cur->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
  874. if (cur == this)
  875. {
  876. if (prev)
  877. {
  878. prev->m_nextBlock = this->m_nextBlock;
  879. }
  880. else
  881. {
  882. *pHead = this->m_nextBlock;
  883. }
  884. break;
  885. }
  886. prev = cur;
  887. }
  888. #endif
  889. }
  890. //-----------------------------------------------------------------------------
  891. #ifdef MEMORYPOOL_DEBUG
  892. Int MemoryPoolSingleBlock::debugSingleBlockReportLeak(const char* owner)
  893. {
  894. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  895. // if allocated before main... just ignore the leak.
  896. if (m_debugFlags & IGNORE_LEAKS)
  897. return 0;
  898. // it's free, ergo, not leaked.
  899. if (m_debugLiteralTagString == FREE_SINGLEBLOCK_TAG_STRING)
  900. return 0;
  901. if (strcmp(m_debugLiteralTagString, "STR_AsciiString::ensureUniqueBufferOfSize") == 0)
  902. {
  903. /** @todo srj -- we leak a bunch of these for some reason (probably due to leaking Win32LocalFile)
  904. so just ignore 'em for now... figure out later. */
  905. }
  906. else if (strstr(m_debugLiteralTagString, "Win32LocalFileSystem.cpp") != NULL)
  907. {
  908. /** @todo srj -- we leak a bunch of these for some reason
  909. so just ignore 'em for now... figure out later. */
  910. }
  911. else
  912. {
  913. DEBUG_LOG(("Leaked a block of size %d, tagstring %s, from pool/dma %s\n",m_logicalSize,m_debugLiteralTagString,owner));
  914. }
  915. #ifdef MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
  916. if (!TheGlobalData || TheGlobalData->m_checkForLeaks)
  917. ::doStackDump(m_stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth));
  918. #endif
  919. return 1;
  920. }
  921. #endif
  922. //-----------------------------------------------------------------------------
  923. #ifdef MEMORYPOOL_DEBUG
  924. /**
  925. Verify internal consistency of this block.
  926. */
  927. void MemoryPoolSingleBlock::debugVerifyBlock()
  928. {
  929. USE_PERF_TIMER(MemoryPoolDebugging)
  930. DEBUG_ASSERTCRASH(this, ("null this"));
  931. DEBUG_ASSERTCRASH(m_magicCookie == SINGLEBLOCK_MAGIC_COOKIE, ("wrong cookie"));
  932. DEBUG_ASSERTCRASH(m_debugLiteralTagString != NULL, ("bad tagstring"));
  933. /// @todo Put this check back in after the AI memory usage is under control (MSB)
  934. //DEBUG_ASSERTCRASH(m_logicalSize>0 && m_logicalSize < 0x00ffffff, ("unlikely value for m_logicalSize"));
  935. DEBUG_ASSERTCRASH(!m_nextBlock || m_nextBlock->m_owningBlob == m_owningBlob, ("owning blob mismatch..."));
  936. #ifdef MPSB_DLINK
  937. DEBUG_ASSERTCRASH(!m_prevBlock || m_prevBlock->m_owningBlob == m_owningBlob, ("owning blob mismatch..."));
  938. #endif
  939. debugCheckUnderrun();
  940. debugCheckOverrun();
  941. }
  942. #endif
  943. //-----------------------------------------------------------------------------
  944. #ifdef MEMORYPOOL_DEBUG
  945. /**
  946. Fill block with bogus values and mark other internal fields for debugging purposes.
  947. */
  948. void MemoryPoolSingleBlock::debugMarkBlockAsFree()
  949. {
  950. USE_PERF_TIMER(MemoryPoolDebugging)
  951. ::memset32(getUserDataNoDbg(), GARBAGE_FILL_VALUE, m_logicalSize);
  952. m_debugLiteralTagString = FREE_SINGLEBLOCK_TAG_STRING;
  953. #ifdef MEMORYPOOL_INTENSE_VERIFY
  954. debugVerifyBlock();
  955. #endif
  956. }
  957. #endif
  958. //-----------------------------------------------------------------------------
  959. #ifdef MEMORYPOOL_DEBUG
  960. /**
  961. Returns true iff someone overwrote part of the first bounding wall
  962. (ie, tromped on memory just before the block)
  963. */
  964. Bool MemoryPoolSingleBlock::debugCheckUnderrun()
  965. {
  966. USE_PERF_TIMER(MemoryPoolDebugging)
  967. #ifdef MEMORYPOOL_BOUNDINGWALL
  968. Int *p = (Int*)(((char*)getUserDataNoDbg()) - WALLSIZE);
  969. for (Int i = 0; i < WALLCOUNT; i++, p++)
  970. {
  971. if (*p != m_wallPattern+i)
  972. {
  973. DEBUG_CRASH(("memory underrun for block \"%s\" (expected %08x, got %08x)\n",m_debugLiteralTagString,m_wallPattern+i,*p));
  974. return true;
  975. }
  976. }
  977. #endif
  978. return false;
  979. }
  980. #endif
  981. //-----------------------------------------------------------------------------
  982. #ifdef MEMORYPOOL_DEBUG
  983. /**
  984. Returns true iff someone overwrote part of the second bounding wall
  985. (ie, tromped on memory just after the block)
  986. */
  987. Bool MemoryPoolSingleBlock::debugCheckOverrun()
  988. {
  989. USE_PERF_TIMER(MemoryPoolDebugging)
  990. #ifdef MEMORYPOOL_BOUNDINGWALL
  991. Int *p = (Int*)(((char*)getUserDataNoDbg()) + m_logicalSize);
  992. for (Int i = 0; i < WALLCOUNT; i++, p++)
  993. {
  994. if (*p != m_wallPattern-i)
  995. {
  996. DEBUG_CRASH(("memory overrun for block \"%s\" (expected %08x, got %08x)\n",m_debugLiteralTagString,m_wallPattern+i,*p));
  997. return true;
  998. }
  999. }
  1000. #endif
  1001. return false;
  1002. }
  1003. #endif
  1004. //-----------------------------------------------------------------------------
  1005. #ifdef MEMORYPOOL_BOUNDINGWALL
  1006. /**
  1007. Fill in the proper values for this block's bounding walls.
  1008. */
  1009. void MemoryPoolSingleBlock::debugFillInWalls()
  1010. {
  1011. Int *p;
  1012. Int i;
  1013. p = (Int*)(((char*)getUserDataNoDbg()) - WALLSIZE);
  1014. for (i = 0; i < WALLCOUNT; i++)
  1015. *p++ = m_wallPattern+i;
  1016. p = (Int*)(((char*)getUserDataNoDbg()) + m_logicalSize);
  1017. for (i = 0; i < WALLCOUNT; i++)
  1018. *p++ = m_wallPattern-i;
  1019. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1020. debugVerifyBlock();
  1021. #endif
  1022. }
  1023. #endif
  1024. //-----------------------------------------------------------------------------
  1025. // METHODS for MemoryPoolBlob
  1026. //-----------------------------------------------------------------------------
  1027. //-----------------------------------------------------------------------------
  1028. /**
  1029. fill in safe default values.
  1030. */
  1031. MemoryPoolBlob::MemoryPoolBlob() :
  1032. m_owningPool(NULL),
  1033. m_nextBlob(NULL),
  1034. m_prevBlob(NULL),
  1035. m_firstFreeBlock(NULL),
  1036. m_usedBlocksInBlob(0),
  1037. m_totalBlocksInBlob(0),
  1038. m_blockData(NULL)
  1039. {
  1040. }
  1041. //-----------------------------------------------------------------------------
  1042. /**
  1043. throw away the blob. free the block data, if any.
  1044. */
  1045. MemoryPoolBlob::~MemoryPoolBlob()
  1046. {
  1047. ::sysFree((void *)m_blockData);
  1048. }
  1049. //-----------------------------------------------------------------------------
  1050. /**
  1051. initialize a Blob; this is called just after the blob is allocated.
  1052. allocate space for the blocks in this blob and initialize all those blocks.
  1053. */
  1054. void MemoryPoolBlob::initBlob(MemoryPool *owningPool, Int allocationCount)
  1055. {
  1056. DEBUG_ASSERTCRASH(m_blockData == NULL, ("unlikely init call"));
  1057. m_owningPool = owningPool;
  1058. m_totalBlocksInBlob = allocationCount;
  1059. m_usedBlocksInBlob = 0;
  1060. Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
  1061. m_blockData = (char *)::sysAllocate(rawBlockSize * m_totalBlocksInBlob); // throws on failure
  1062. // set up the list of free blocks in the blob (namely, all of 'em)
  1063. MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)m_blockData;
  1064. MemoryPoolSingleBlock *next;
  1065. for (Int i = m_totalBlocksInBlob-1; i >= 0; i--)
  1066. {
  1067. next = (MemoryPoolSingleBlock *)(((char *)block) + rawBlockSize);
  1068. #ifdef MEMORYPOOL_DEBUG
  1069. block->initBlock(m_owningPool->getAllocationSize(), this, owningPool->getOwningFactory(), FREE_SINGLEBLOCK_TAG_STRING);
  1070. #else
  1071. block->initBlock(m_owningPool->getAllocationSize(), this, owningPool->getOwningFactory());
  1072. #endif
  1073. block->setNextFreeBlock((i > 0) ? next : NULL);
  1074. #ifdef MEMORYPOOL_DEBUG
  1075. block->debugMarkBlockAsFree();
  1076. #endif
  1077. block = next;
  1078. }
  1079. m_firstFreeBlock = (MemoryPoolSingleBlock *)m_blockData;
  1080. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1081. debugMemoryVerifyBlob();
  1082. #endif
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. /**
  1086. add this blob to a given pool's list-of-blobs
  1087. */
  1088. void MemoryPoolBlob::addBlobToList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail)
  1089. {
  1090. m_prevBlob = *ppTail;
  1091. m_nextBlob = NULL;
  1092. if (*ppTail != NULL)
  1093. (*ppTail)->m_nextBlob = this;
  1094. if (*ppHead == NULL)
  1095. *ppHead = this;
  1096. *ppTail = this;
  1097. }
  1098. //-----------------------------------------------------------------------------
  1099. /**
  1100. remove this blob from a given pool's list-of-blobs
  1101. */
  1102. void MemoryPoolBlob::removeBlobFromList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail)
  1103. {
  1104. if (*ppHead == this)
  1105. *ppHead = this->m_nextBlob;
  1106. else
  1107. this->m_prevBlob->m_nextBlob = this->m_nextBlob;
  1108. if (*ppTail == this)
  1109. *ppTail = this->m_prevBlob;
  1110. else
  1111. this->m_nextBlob->m_prevBlob = this->m_prevBlob;
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. /**
  1115. grab a free block from this blob, mark it as taken, and return it.
  1116. this method assumes that there is at least one free block in the blob!
  1117. */
  1118. MemoryPoolSingleBlock *MemoryPoolBlob::allocateSingleBlock(DECLARE_LITERALSTRING_ARG1)
  1119. {
  1120. DEBUG_ASSERTCRASH(m_firstFreeBlock, ("no free blocks available in MemoryPoolBlob"));
  1121. MemoryPoolSingleBlock *block = m_firstFreeBlock;
  1122. m_firstFreeBlock = block->getNextFreeBlock();
  1123. ++m_usedBlocksInBlob;
  1124. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1125. block->debugVerifyBlock();
  1126. #endif
  1127. #ifdef MEMORYPOOL_DEBUG
  1128. // this is debug-only because it only serves to update the debugLiteralTagString.
  1129. block->initBlock(m_owningPool->getAllocationSize(), this, m_owningPool->getOwningFactory(), debugLiteralTagString);
  1130. #endif
  1131. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1132. debugMemoryVerifyBlob();
  1133. #endif
  1134. // don't need to zero this out... the caller will do that, if necessary
  1135. // memset(block->getUserData(), 0, m_owningPool->getAllocationSize());
  1136. return block;
  1137. }
  1138. //-----------------------------------------------------------------------------
  1139. /**
  1140. make this block available for future allocations. it is assumed that the block
  1141. belongs to this blob, and is not already free.
  1142. */
  1143. void MemoryPoolBlob::freeSingleBlock(MemoryPoolSingleBlock *block)
  1144. {
  1145. DEBUG_ASSERTCRASH(block->getOwningBlob() == this, ("block does not belong to this blob"));
  1146. block->setNextFreeBlock(m_firstFreeBlock);
  1147. m_firstFreeBlock = block;
  1148. --m_usedBlocksInBlob;
  1149. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1150. block->debugVerifyBlock();
  1151. #endif
  1152. #ifdef MEMORYPOOL_DEBUG
  1153. block->debugMarkBlockAsFree();
  1154. #endif
  1155. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1156. debugMemoryVerifyBlob();
  1157. #endif
  1158. }
  1159. //-----------------------------------------------------------------------------
  1160. #ifdef MEMORYPOOL_DEBUG
  1161. /**
  1162. Perform internal consistency checking on this blob and all its blocks.
  1163. */
  1164. void MemoryPoolBlob::debugMemoryVerifyBlob()
  1165. {
  1166. USE_PERF_TIMER(MemoryPoolDebugging)
  1167. DEBUG_ASSERTCRASH(m_owningPool != NULL, ("bad owner"));
  1168. DEBUG_ASSERTCRASH(m_usedBlocksInBlob >= 0 && m_usedBlocksInBlob <= m_totalBlocksInBlob, ("unlikely m_usedBlocksInBlob"));
  1169. DEBUG_ASSERTCRASH(m_totalBlocksInBlob > 0, ("unlikely m_totalBlocksInBlob"));
  1170. Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
  1171. char *blockData = m_blockData;
  1172. for (Int i = m_totalBlocksInBlob-1; i >= 0; i--, blockData += rawBlockSize)
  1173. {
  1174. MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)blockData;
  1175. block->debugVerifyBlock();
  1176. }
  1177. }
  1178. #endif
  1179. //-----------------------------------------------------------------------------
  1180. #ifdef MEMORYPOOL_DEBUG
  1181. Int MemoryPoolBlob::debugBlobReportLeaks(const char* owner)
  1182. {
  1183. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  1184. Int any = 0;
  1185. Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
  1186. char *blockData = m_blockData;
  1187. for (Int i = m_totalBlocksInBlob-1; i >= 0; i--, blockData += rawBlockSize)
  1188. {
  1189. MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)blockData;
  1190. any += block->debugSingleBlockReportLeak(owner);
  1191. }
  1192. return any;
  1193. }
  1194. #endif
  1195. //-----------------------------------------------------------------------------
  1196. #ifdef MEMORYPOOL_DEBUG
  1197. /**
  1198. return true iff this block belongs to this blob.
  1199. */
  1200. Bool MemoryPoolBlob::debugIsBlockInBlob(void *pBlockPtr)
  1201. {
  1202. USE_PERF_TIMER(MemoryPoolDebugging)
  1203. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  1204. Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
  1205. char *blockData = m_blockData;
  1206. for (Int i = m_totalBlocksInBlob-1; i >= 0; i--)
  1207. {
  1208. if ((char *)block == blockData)
  1209. return true;
  1210. blockData += rawBlockSize;
  1211. }
  1212. return false;
  1213. }
  1214. #endif
  1215. //-----------------------------------------------------------------------------
  1216. #ifdef MEMORYPOOL_CHECKPOINTING
  1217. /**
  1218. set all the checkpointinfos to null for all the blocks in this blob.
  1219. this does NOT free the checkpointinfos; that is presumed to happen elsewhere.
  1220. */
  1221. void MemoryPoolBlob::debugResetCheckpoints()
  1222. {
  1223. Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
  1224. char *blockData = m_blockData;
  1225. for (Int i = m_totalBlocksInBlob-1; i >= 0; i--, blockData += rawBlockSize)
  1226. {
  1227. MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)blockData;
  1228. block->debugResetCheckpoint();
  1229. }
  1230. }
  1231. #endif
  1232. //-----------------------------------------------------------------------------
  1233. // METHODS for Checkpointable
  1234. //-----------------------------------------------------------------------------
  1235. #ifdef MEMORYPOOL_CHECKPOINTING
  1236. //-----------------------------------------------------------------------------
  1237. /**
  1238. init fields of Checkpointable to safe values.
  1239. */
  1240. Checkpointable::Checkpointable() :
  1241. m_firstCheckpointInfo(NULL),
  1242. m_cpiEverFailed(false)
  1243. {
  1244. }
  1245. #endif
  1246. #ifdef MEMORYPOOL_CHECKPOINTING
  1247. //-----------------------------------------------------------------------------
  1248. /**
  1249. destroy the object. discard any remaining checkpointinfo.
  1250. */
  1251. Checkpointable::~Checkpointable()
  1252. {
  1253. BlockCheckpointInfo::freeList(&m_firstCheckpointInfo);
  1254. m_firstCheckpointInfo = NULL;
  1255. m_cpiEverFailed = false;
  1256. }
  1257. #endif
  1258. //-----------------------------------------------------------------------------
  1259. #ifdef MEMORYPOOL_CHECKPOINTING
  1260. /**
  1261. create a new checkpointinfo and fill it in appropriately. this does NOT
  1262. throw an exception on failure; it quietly returns null if there is not
  1263. enough memory, and sets a flag to indicate our checkpointinfo is not complete.
  1264. */
  1265. BlockCheckpointInfo *Checkpointable::debugAddCheckpointInfo(
  1266. const char *debugLiteralTagString,
  1267. Int allocCheckpoint,
  1268. Int blockSize
  1269. )
  1270. {
  1271. BlockCheckpointInfo *bi = BlockCheckpointInfo::addToList(&m_firstCheckpointInfo, debugLiteralTagString,
  1272. allocCheckpoint, blockSize);
  1273. if (bi)
  1274. {
  1275. #ifdef MEMORYPOOL_STACKTRACE
  1276. void **stacktrace = bi->getStacktraceInfo();
  1277. if (theStackTraceDepth > 0 && !TheGlobalData || TheGlobalData->m_checkForLeaks)
  1278. {
  1279. memset(stacktrace, 0, MEMORYPOOL_STACKTRACE_SIZE_BYTES);
  1280. ::FillStackAddresses(stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth), MEMORYPOOL_STACKTRACE_SKIP_SIZE);
  1281. }
  1282. else
  1283. {
  1284. stacktrace[0] = NULL;
  1285. }
  1286. #endif
  1287. }
  1288. else
  1289. {
  1290. m_cpiEverFailed = true;
  1291. }
  1292. return bi;
  1293. }
  1294. #endif
  1295. //-----------------------------------------------------------------------------
  1296. #ifdef MEMORYPOOL_CHECKPOINTING
  1297. /**
  1298. print a report on the checkpointinfos belonging to this pool/dma.
  1299. */
  1300. void Checkpointable::debugCheckpointReport( Int flags, Int startCheckpoint, Int endCheckpoint, const char *poolName )
  1301. {
  1302. DEBUG_ASSERTCRASH(startCheckpoint >= 0 && startCheckpoint <= endCheckpoint, ("bad checkpoints"));
  1303. DEBUG_ASSERTCRASH((flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0, ("bad flags: must set at least one alloc flag"));
  1304. DEBUG_ASSERTCRASH((flags & _REPORT_CP_FREED_DONTCARE) != 0, ("bad flags: must set at least one freed flag"));
  1305. if (m_cpiEverFailed)
  1306. {
  1307. DEBUG_LOG((" *** WARNING *** info on freed blocks may be inaccurate or incomplete!\n"));
  1308. }
  1309. for (BlockCheckpointInfo *bi = m_firstCheckpointInfo; bi; bi = bi->getNext())
  1310. {
  1311. BlockCheckpointInfo::doBlockCheckpointReport( bi, poolName, flags, startCheckpoint, endCheckpoint );
  1312. }
  1313. }
  1314. #endif
  1315. //-----------------------------------------------------------------------------
  1316. #ifdef MEMORYPOOL_CHECKPOINTING
  1317. /**
  1318. throw away all the checkpointinfos. this frees the memory, but blocks might still
  1319. refer to the discarded infos; you must zero those elsewhere.
  1320. */
  1321. void Checkpointable::debugResetCheckpoints()
  1322. {
  1323. BlockCheckpointInfo::freeList(&m_firstCheckpointInfo);
  1324. }
  1325. #endif
  1326. //-----------------------------------------------------------------------------
  1327. // METHODS for MemoryPool
  1328. //-----------------------------------------------------------------------------
  1329. //-----------------------------------------------------------------------------
  1330. /**
  1331. init to safe values.
  1332. */
  1333. MemoryPool::MemoryPool() :
  1334. m_factory(NULL),
  1335. m_nextPoolInFactory(NULL),
  1336. m_poolName(""),
  1337. m_allocationSize(0),
  1338. m_initialAllocationCount(0),
  1339. m_overflowAllocationCount(0),
  1340. m_usedBlocksInPool(0),
  1341. m_totalBlocksInPool(0),
  1342. m_peakUsedBlocksInPool(0),
  1343. m_firstBlob(NULL),
  1344. m_lastBlob(NULL),
  1345. m_firstBlobWithFreeBlocks(NULL)
  1346. {
  1347. }
  1348. //-----------------------------------------------------------------------------
  1349. /**
  1350. initialize the memory pool with the given parameters. allocate the initial
  1351. set of blocks.
  1352. */
  1353. void MemoryPool::init(MemoryPoolFactory *factory, const char *poolName, Int allocationSize, Int initialAllocationCount, Int overflowAllocationCount)
  1354. {
  1355. m_factory = factory;
  1356. m_poolName = poolName;
  1357. m_allocationSize = ::roundUpMemBound(allocationSize); // round up to four-byte boundary
  1358. m_initialAllocationCount = initialAllocationCount;
  1359. m_overflowAllocationCount = overflowAllocationCount;
  1360. m_usedBlocksInPool = 0;
  1361. m_totalBlocksInPool = 0;
  1362. m_peakUsedBlocksInPool = 0;
  1363. m_firstBlob = NULL;
  1364. m_lastBlob = NULL;
  1365. m_firstBlobWithFreeBlocks = NULL;
  1366. // go ahead and init the initial block here (will throw on failure)
  1367. createBlob(m_initialAllocationCount);
  1368. }
  1369. //-----------------------------------------------------------------------------
  1370. /**
  1371. throw away the pool, and all blocks/blobs associated with it.
  1372. */
  1373. MemoryPool::~MemoryPool()
  1374. {
  1375. // toss everything. we could do this slightly more efficiently,
  1376. // but not really worth the extra code to do so.
  1377. while (m_firstBlob)
  1378. {
  1379. freeBlob(m_firstBlob);
  1380. }
  1381. }
  1382. //-----------------------------------------------------------------------------
  1383. /**
  1384. create a new blob for this pool. if you set up good values for initialAllocationCount,
  1385. this should rarely (if ever) be called (though during development it will be called
  1386. frequently).
  1387. */
  1388. MemoryPoolBlob* MemoryPool::createBlob(Int allocationCount)
  1389. {
  1390. DEBUG_ASSERTCRASH(allocationCount > 0 && allocationCount%MEM_BOUND_ALIGNMENT==0, ("bad allocationCount (must be >0 and evenly divisible by %d)",MEM_BOUND_ALIGNMENT));
  1391. MemoryPoolBlob* blob = new (::sysAllocate(sizeof MemoryPoolBlob)) MemoryPoolBlob; // will throw on failure
  1392. blob->initBlob(this, allocationCount); // will throw on failure
  1393. blob->addBlobToList(&m_firstBlob, &m_lastBlob);
  1394. DEBUG_ASSERTCRASH(m_firstBlobWithFreeBlocks == NULL, ("DO NOT IGNORE. Please call John McD - x36872 (m_firstBlobWithFreeBlocks != NULL)"));
  1395. m_firstBlobWithFreeBlocks = blob;
  1396. // bookkeeping
  1397. m_totalBlocksInPool += allocationCount;
  1398. #ifdef MEMORYPOOL_DEBUG
  1399. m_factory->adjustTotals("", 0, allocationCount*getAllocationSize());
  1400. #endif
  1401. return blob;
  1402. }
  1403. //-----------------------------------------------------------------------------
  1404. /**
  1405. throw away a given blob, and all its blocks. it's assumed that the blob belongs
  1406. to this pool.
  1407. */
  1408. Int MemoryPool::freeBlob(MemoryPoolBlob* blob)
  1409. {
  1410. DEBUG_ASSERTCRASH(blob, ("null blob"));
  1411. DEBUG_ASSERTCRASH(blob->getOwningPool() == this, ("blob does not belong to this pool"));
  1412. // save these for later...
  1413. Int totalBlocksInBlob = blob->getTotalBlockCount();
  1414. Int usedBlocksInBlob = blob->getUsedBlockCount();
  1415. DEBUG_ASSERTCRASH(usedBlocksInBlob == 0, ("freeing a nonempty blob (%d)\n",usedBlocksInBlob));
  1416. // this is really just an estimate... will be too small in debug mode.
  1417. Int amtFreed = totalBlocksInBlob * getAllocationSize() + sizeof(MemoryPoolBlob);
  1418. // de-link it from our list
  1419. blob->removeBlobFromList(&m_firstBlob, &m_lastBlob);
  1420. // ensure that the 'first free' blob is still a valid blob.
  1421. // (doesn't need to actually have free blocks, just be a valid blob)
  1422. if (m_firstBlobWithFreeBlocks == blob)
  1423. m_firstBlobWithFreeBlocks = m_firstBlob;
  1424. // this is evil... since there is no 'placement delete' we must do this the hard way
  1425. // and call the dtor directly. ordinarily this is heinous, but in this case we'll
  1426. // make an exception.
  1427. blob->~MemoryPoolBlob();
  1428. ::sysFree((void *)blob);
  1429. // finally... bookkeeping
  1430. m_usedBlocksInPool -= usedBlocksInBlob;
  1431. m_totalBlocksInPool -= totalBlocksInBlob;
  1432. #ifdef MEMORYPOOL_DEBUG
  1433. m_factory->adjustTotals("", -usedBlocksInBlob*getAllocationSize(), -totalBlocksInBlob*getAllocationSize());
  1434. #endif
  1435. return amtFreed;
  1436. }
  1437. //-----------------------------------------------------------------------------
  1438. /**
  1439. allocate a block from this pool and return it, but don't bother zeroing
  1440. out the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
  1441. function will never return null.
  1442. */
  1443. void* MemoryPool::allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG1)
  1444. {
  1445. ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
  1446. if (m_firstBlobWithFreeBlocks != NULL && !m_firstBlobWithFreeBlocks->hasAnyFreeBlocks())
  1447. {
  1448. // hmm... the current 'free' blob has nothing available. look and see if there
  1449. // are any other existing blobs with freespace.
  1450. for (MemoryPoolBlob *blob = m_firstBlob; blob != NULL; blob = blob->getNextInList())
  1451. {
  1452. if (blob->hasAnyFreeBlocks())
  1453. break;
  1454. }
  1455. // note that if we walk thru the list without finding anything, this will
  1456. // reset m_firstBlobWithFreeBlocks to null and fall thru.
  1457. m_firstBlobWithFreeBlocks = blob;
  1458. }
  1459. // OK, if we are here then we have no blobs with freespace... darn.
  1460. // allocate an overflow block.
  1461. if (m_firstBlobWithFreeBlocks == NULL)
  1462. {
  1463. if (m_overflowAllocationCount == 0)
  1464. {
  1465. throw ERROR_OUT_OF_MEMORY; // this pool is not allowed to grow
  1466. }
  1467. else
  1468. {
  1469. createBlob(m_overflowAllocationCount); // throws on failure
  1470. }
  1471. }
  1472. MemoryPoolBlob *blob = m_firstBlobWithFreeBlocks;
  1473. DEBUG_ASSERTCRASH(blob, ("no blob with free blocks available in MemoryPool::allocate"));
  1474. MemoryPoolSingleBlock *block = blob->allocateSingleBlock(PASS_LITERALSTRING_ARG1);
  1475. DEBUG_ASSERTCRASH(block, ("should not fail here"));
  1476. #ifdef MEMORYPOOL_CHECKPOINTING
  1477. BlockCheckpointInfo *bi = debugAddCheckpointInfo(block->debugGetLiteralTagString(), m_factory->getCurCheckpoint(), getAllocationSize());
  1478. if (bi)
  1479. block->debugSetCheckpointInfo(bi);
  1480. #endif
  1481. // bookkeeping
  1482. ++m_usedBlocksInPool;
  1483. if (m_peakUsedBlocksInPool < m_usedBlocksInPool)
  1484. m_peakUsedBlocksInPool = m_usedBlocksInPool;
  1485. #ifdef MEMORYPOOL_DEBUG
  1486. m_factory->adjustTotals(debugLiteralTagString, 1*getAllocationSize(), 0);
  1487. #ifdef USE_FILLER_VALUE
  1488. {
  1489. USE_PERF_TIMER(MemoryPoolInitFilling)
  1490. ::memset32(block->getUserData(), s_initFillerValue, getAllocationSize());
  1491. }
  1492. #endif
  1493. #endif
  1494. return block->getUserData();
  1495. }
  1496. //-----------------------------------------------------------------------------
  1497. /**
  1498. allocate a block from this pool and return it, and zero out the contents
  1499. of the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
  1500. function will never return null.
  1501. */
  1502. void* MemoryPool::allocateBlockImplementation(DECLARE_LITERALSTRING_ARG1)
  1503. {
  1504. void* p = allocateBlockDoNotZeroImplementation(PASS_LITERALSTRING_ARG1); // throws on failure
  1505. memset(p, 0, getAllocationSize());
  1506. return p;
  1507. }
  1508. //-----------------------------------------------------------------------------
  1509. /**
  1510. free a block allocated by this pool. it's ok to pass null.
  1511. */
  1512. void MemoryPool::freeBlock(void* pBlockPtr)
  1513. {
  1514. if (!pBlockPtr)
  1515. return; // my, that was easy
  1516. ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
  1517. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  1518. MemoryPoolBlob *blob = block->getOwningBlob();
  1519. #ifdef MEMORYPOOL_DEBUG
  1520. const char* tagString = block->debugGetLiteralTagString();
  1521. #endif
  1522. DEBUG_ASSERTCRASH(blob && blob->getOwningPool() == this, ("block does not belong to this pool"));
  1523. #ifdef MEMORYPOOL_CHECKPOINTING
  1524. BlockCheckpointInfo *bi = block->debugGetCheckpointInfo();
  1525. DEBUG_ASSERTCRASH(bi, ("hmm, no checkpoint info"));
  1526. if (bi)
  1527. bi->debugSetFreepoint(m_factory->getCurCheckpoint());
  1528. #endif
  1529. blob->freeSingleBlock(block);
  1530. // if we want to free the blobs as they become empty, do that here.
  1531. // normally we don't bother, but just in case this is ever desired, here's how you'd do it...
  1532. //
  1533. // if (blob->m_usedBlocksInBlob == 0)
  1534. // {
  1535. // freeBlob(blob);
  1536. // return;
  1537. //}
  1538. if (!m_firstBlobWithFreeBlocks)
  1539. m_firstBlobWithFreeBlocks = blob;
  1540. // bookkeeping
  1541. --m_usedBlocksInPool;
  1542. #ifdef MEMORYPOOL_DEBUG
  1543. m_factory->adjustTotals(tagString, -1*getAllocationSize(), 0);
  1544. #endif
  1545. }
  1546. //-----------------------------------------------------------------------------
  1547. Int MemoryPool::countBlobsInPool()
  1548. {
  1549. Int blobs = 0;
  1550. for (MemoryPoolBlob* blob = m_firstBlob; blob;)
  1551. {
  1552. ++blobs;
  1553. blob = blob->getNextInList();
  1554. }
  1555. return blobs;
  1556. }
  1557. //-----------------------------------------------------------------------------
  1558. /**
  1559. if the pool has any blobs that are completely unused, they are released back to the
  1560. operating system. this will rarely, if ever, be called, but may be useful
  1561. in odd situations.
  1562. */
  1563. Int MemoryPool::releaseEmpties()
  1564. {
  1565. ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
  1566. Int released = 0;
  1567. for (MemoryPoolBlob* blob = m_firstBlob; blob;)
  1568. {
  1569. MemoryPoolBlob* pNext = blob->getNextInList();
  1570. if (blob->getUsedBlockCount() == 0)
  1571. released += freeBlob(blob);
  1572. blob = pNext;
  1573. }
  1574. return released;
  1575. }
  1576. //-----------------------------------------------------------------------------
  1577. /**
  1578. throw away everything in the pool, but keep the pool itself valid.
  1579. */
  1580. void MemoryPool::reset()
  1581. {
  1582. ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
  1583. // toss everything. we could do this slightly more efficiently,
  1584. // but not really worth the extra code to do so.
  1585. while (m_firstBlob)
  1586. {
  1587. freeBlob(m_firstBlob);
  1588. }
  1589. m_firstBlob = NULL;
  1590. m_lastBlob = NULL;
  1591. m_firstBlobWithFreeBlocks = NULL;
  1592. init(m_factory, m_poolName, m_allocationSize, m_initialAllocationCount, m_overflowAllocationCount); // will throw on failure
  1593. }
  1594. //-----------------------------------------------------------------------------
  1595. /**
  1596. add this pool to the factory's list-of-pools.
  1597. */
  1598. void MemoryPool::addToList(MemoryPool **pHead)
  1599. {
  1600. this->m_nextPoolInFactory = *pHead;
  1601. *pHead = this;
  1602. }
  1603. //-----------------------------------------------------------------------------
  1604. /**
  1605. remove this pool from the factory's list-of-pools.
  1606. */
  1607. void MemoryPool::removeFromList(MemoryPool **pHead)
  1608. {
  1609. // this isn't very efficient, but then, we rarely remove pools...
  1610. // usually only at shutdown. so don't bother optimizing.
  1611. MemoryPool *prev = NULL;
  1612. for (MemoryPool *cur = *pHead; cur; cur = cur->m_nextPoolInFactory)
  1613. {
  1614. if (cur == this)
  1615. {
  1616. if (prev)
  1617. {
  1618. prev->m_nextPoolInFactory = this->m_nextPoolInFactory;
  1619. }
  1620. else
  1621. {
  1622. *pHead = this->m_nextPoolInFactory;
  1623. }
  1624. break;
  1625. }
  1626. prev = cur;
  1627. }
  1628. }
  1629. //-----------------------------------------------------------------------------
  1630. #ifdef MEMORYPOOL_DEBUG
  1631. /**
  1632. print a report about per-pool allocation statistics to the debug log.
  1633. if the pool is null, print column headers.
  1634. */
  1635. /*static*/ void MemoryPool::debugPoolInfoReport( MemoryPool *pool, FILE *fp )
  1636. {
  1637. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  1638. const char *PREPEND = "POOLINFO"; // allows grepping more easily
  1639. if (!pool)
  1640. {
  1641. DEBUG_LOG(("%s,%32s,%6s,%6s,%6s,%6s,%6s,%6s\n",PREPEND,"POOLNAME","BLKSZ","INIT","OVRFL","USED","TOTAL","PEAK"));
  1642. if( fp )
  1643. fprintf( fp, "%s,%32s,%6s,%6s,%6s,%6s,%6s,%6s\n",PREPEND,"POOLNAME","BLKSZ","INIT","OVRFL","USED","TOTAL","PEAK" );
  1644. }
  1645. else
  1646. {
  1647. DEBUG_LOG(("%s,%32s,%6d,%6d,%6d,%6d,%6d,%6d\n",PREPEND,
  1648. pool->m_poolName,pool->m_allocationSize,pool->m_initialAllocationCount,pool->m_overflowAllocationCount,
  1649. pool->m_usedBlocksInPool,pool->m_totalBlocksInPool,pool->m_peakUsedBlocksInPool));
  1650. if( fp )
  1651. {
  1652. fprintf( fp, "%s,%32s,%6d,%6d,%6d,%6d,%6d,%6d\n",PREPEND,
  1653. pool->m_poolName,pool->m_allocationSize,pool->m_initialAllocationCount,pool->m_overflowAllocationCount,
  1654. pool->m_usedBlocksInPool,pool->m_totalBlocksInPool,pool->m_peakUsedBlocksInPool );
  1655. }
  1656. }
  1657. }
  1658. #endif
  1659. //-----------------------------------------------------------------------------
  1660. #ifdef MEMORYPOOL_DEBUG
  1661. Int MemoryPool::debugPoolReportLeaks( const char* owner )
  1662. {
  1663. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  1664. Int any = 0;
  1665. for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
  1666. {
  1667. any += blob->debugBlobReportLeaks(owner);
  1668. }
  1669. return any;
  1670. }
  1671. #endif
  1672. //-----------------------------------------------------------------------------
  1673. #ifdef MEMORYPOOL_DEBUG
  1674. /**
  1675. perform internal consistency checking on the memory pool.
  1676. */
  1677. void MemoryPool::debugMemoryVerifyPool()
  1678. {
  1679. USE_PERF_TIMER(MemoryPoolDebugging)
  1680. Int used = 0;
  1681. Int total = 0;
  1682. for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
  1683. {
  1684. blob->debugMemoryVerifyBlob();
  1685. used += blob->getUsedBlockCount();
  1686. total += blob->getTotalBlockCount();
  1687. }
  1688. DEBUG_ASSERTCRASH(m_usedBlocksInPool == used, ("used mismatch %d %d",m_usedBlocksInPool,used));
  1689. DEBUG_ASSERTCRASH(m_totalBlocksInPool == total, ("total mismatch %d %d",m_totalBlocksInPool,total));
  1690. }
  1691. #endif
  1692. //-----------------------------------------------------------------------------
  1693. #ifdef MEMORYPOOL_DEBUG
  1694. /**
  1695. return true iff the block is a valid block in this pool.
  1696. */
  1697. Bool MemoryPool::debugIsBlockInPool(void *pBlockPtr)
  1698. {
  1699. USE_PERF_TIMER(MemoryPoolDebugging)
  1700. if (!pBlockPtr)
  1701. return false;
  1702. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1703. debugMemoryVerifyPool();
  1704. #endif
  1705. Bool check1 = false, check2 = false;
  1706. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  1707. MemoryPoolBlob *ownerBlob = block->getOwningBlob();
  1708. for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
  1709. {
  1710. if (blob->debugIsBlockInBlob(pBlockPtr))
  1711. check1 = true;
  1712. if (blob == ownerBlob)
  1713. check2 = true;
  1714. }
  1715. DEBUG_ASSERTCRASH(check1 == check2, ("mismatch checks in debugIsBlockInPool"));
  1716. return check1 && check2;
  1717. }
  1718. #endif
  1719. //-----------------------------------------------------------------------------
  1720. #ifdef MEMORYPOOL_DEBUG
  1721. /**
  1722. return the tagstring for the block. this will never return null; if
  1723. the block is null or invalid, "FREE_SINGLEBLOCK_TAG_STRING" will be returned.
  1724. it is assumed that the block was allocated by this pool.
  1725. */
  1726. const char *MemoryPool::debugGetBlockTagString(void *pBlockPtr)
  1727. {
  1728. USE_PERF_TIMER(MemoryPoolDebugging)
  1729. if (!pBlockPtr)
  1730. return FREE_SINGLEBLOCK_TAG_STRING;
  1731. #ifdef MEMORYPOOL_INTENSE_VERIFY
  1732. debugMemoryVerifyPool();
  1733. #endif
  1734. if (!debugIsBlockInPool(pBlockPtr))
  1735. {
  1736. DEBUG_CRASH(("block is not in this pool"));
  1737. return FREE_SINGLEBLOCK_TAG_STRING;
  1738. }
  1739. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  1740. return block->debugGetLiteralTagString();
  1741. }
  1742. #endif
  1743. //-----------------------------------------------------------------------------
  1744. #ifdef MEMORYPOOL_CHECKPOINTING
  1745. /**
  1746. free all checkpointinfo for this pool, and reset all ptrs to checkpointinfo.
  1747. */
  1748. void MemoryPool::debugResetCheckpoints()
  1749. {
  1750. Checkpointable::debugResetCheckpoints();
  1751. for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
  1752. {
  1753. blob->debugResetCheckpoints();
  1754. }
  1755. }
  1756. #endif
  1757. //-----------------------------------------------------------------------------
  1758. // METHODS for DynamicMemoryAllocator
  1759. //-----------------------------------------------------------------------------
  1760. //-----------------------------------------------------------------------------
  1761. /**
  1762. init the DMA to safe values.
  1763. */
  1764. DynamicMemoryAllocator::DynamicMemoryAllocator() :
  1765. m_factory(NULL),
  1766. m_nextDmaInFactory(NULL),
  1767. m_numPools(0),
  1768. m_usedBlocksInDma(0),
  1769. m_rawBlocks(NULL)
  1770. {
  1771. for (Int i = 0; i < MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS; i++)
  1772. m_pools[i] = 0;
  1773. }
  1774. //-----------------------------------------------------------------------------
  1775. /**
  1776. Initialize the dma and its subpools.
  1777. */
  1778. void DynamicMemoryAllocator::init(MemoryPoolFactory *factory, Int numSubPools, const PoolInitRec pParms[])
  1779. {
  1780. const PoolInitRec defaultDMA[7] =
  1781. {
  1782. { "dmaPool_16", 16, 64, 64 },
  1783. { "dmaPool_32", 32, 64, 64 },
  1784. { "dmaPool_64", 64, 64, 64 },
  1785. { "dmaPool_128", 128, 64, 64 },
  1786. { "dmaPool_256", 256, 64, 64 },
  1787. { "dmaPool_512", 512, 64, 64 },
  1788. { "dmaPool_1024", 1024, 64, 64 }
  1789. };
  1790. if (numSubPools == 0 || pParms == NULL)
  1791. {
  1792. // use the defaults...
  1793. numSubPools = 7;
  1794. pParms = defaultDMA;
  1795. }
  1796. m_factory = factory;
  1797. m_numPools = numSubPools;
  1798. if (m_numPools > MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS)
  1799. m_numPools = MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS;
  1800. m_usedBlocksInDma = 0;
  1801. for (Int i = 0; i < m_numPools; i++)
  1802. {
  1803. DEBUG_ASSERTCRASH(i == 0 || pParms[i].allocationSize > pParms[i-1].allocationSize, ("alloc size must increase monotonically for DMA"));
  1804. m_pools[i] = m_factory->createMemoryPool(&pParms[i]);
  1805. }
  1806. }
  1807. //-----------------------------------------------------------------------------
  1808. /**
  1809. destroy the dma and its subpools.
  1810. */
  1811. DynamicMemoryAllocator::~DynamicMemoryAllocator()
  1812. {
  1813. DEBUG_ASSERTCRASH(m_usedBlocksInDma == 0, ("destroying a nonempty dma"));
  1814. /// @todo this may cause double-destruction of the subpools -- test & fix
  1815. for (Int i = 0; i < m_numPools; i++)
  1816. {
  1817. m_factory->destroyMemoryPool(m_pools[i]);
  1818. m_pools[i] = NULL;
  1819. }
  1820. while (m_rawBlocks)
  1821. {
  1822. freeBytes(m_rawBlocks->getUserData());
  1823. }
  1824. }
  1825. //-----------------------------------------------------------------------------
  1826. /**
  1827. find the best-fitting subpool in this dma for a given allocation size.
  1828. if no subpool can satisfy the size, return null.
  1829. */
  1830. MemoryPool *DynamicMemoryAllocator::findPoolForSize(Int allocSize)
  1831. {
  1832. for (Int i = 0; i < m_numPools; i++)
  1833. {
  1834. DEBUG_ASSERTCRASH(m_pools[i], ("null pool"));
  1835. if (allocSize <= m_pools[i]->getAllocationSize())
  1836. return m_pools[i];
  1837. }
  1838. return NULL;
  1839. }
  1840. //-----------------------------------------------------------------------------
  1841. /**
  1842. add this DMA to the factory's list of dmas.
  1843. */
  1844. void DynamicMemoryAllocator::addToList(DynamicMemoryAllocator **pHead)
  1845. {
  1846. this->m_nextDmaInFactory = *pHead;
  1847. *pHead = this;
  1848. }
  1849. //-----------------------------------------------------------------------------
  1850. /**
  1851. remove this DMA from the factory's list of dmas.
  1852. */
  1853. void DynamicMemoryAllocator::removeFromList(DynamicMemoryAllocator **pHead)
  1854. {
  1855. // this isn't very efficient, but then, we rarely remove these...
  1856. // usually only at shutdown. so don't bother optimizing.
  1857. DynamicMemoryAllocator *prev = NULL;
  1858. for (DynamicMemoryAllocator *cur = *pHead; cur; cur = cur->m_nextDmaInFactory)
  1859. {
  1860. if (cur == this)
  1861. {
  1862. if (prev)
  1863. {
  1864. prev->m_nextDmaInFactory = this->m_nextDmaInFactory;
  1865. }
  1866. else
  1867. {
  1868. *pHead = this->m_nextDmaInFactory;
  1869. }
  1870. break;
  1871. }
  1872. prev = cur;
  1873. }
  1874. }
  1875. //-----------------------------------------------------------------------------
  1876. #ifdef MEMORYPOOL_DEBUG
  1877. void DynamicMemoryAllocator::debugIgnoreLeaksForThisBlock(void* pBlockPtr)
  1878. {
  1879. USE_PERF_TIMER(MemoryPoolDebugging)
  1880. if (!pBlockPtr)
  1881. return;
  1882. #ifdef MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
  1883. DEBUG_ASSERTCRASH(debugIsBlockInDma(pBlockPtr), ("block is not in this dma"));
  1884. #endif
  1885. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  1886. if (block->getOwningBlob())
  1887. {
  1888. #ifdef MEMORYPOOL_DEBUG
  1889. DEBUG_ASSERTCRASH(findPoolForSize(block->debugGetLogicalSize()) == block->getOwningBlob()->getOwningPool(), ("pool mismatch"));
  1890. #endif
  1891. block->debugIgnoreLeaksForThisBlock();
  1892. }
  1893. else
  1894. {
  1895. DEBUG_CRASH(("cannot currently ignore leaks for raw blocks (allocation too large)\n"));
  1896. }
  1897. }
  1898. #endif
  1899. //-----------------------------------------------------------------------------
  1900. /**
  1901. allocate a chunk-o-bytes from this DMA and return it, but don't bother zeroing
  1902. out the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
  1903. function will never return null.
  1904. */
  1905. void *DynamicMemoryAllocator::allocateBytesDoNotZeroImplementation(Int numBytes DECLARE_LITERALSTRING_ARG2)
  1906. {
  1907. ScopedCriticalSection scopedCriticalSection(TheDmaCriticalSection);
  1908. void *result = NULL;
  1909. #ifdef MEMORYPOOL_DEBUG
  1910. DEBUG_ASSERTCRASH(debugLiteralTagString != NULL, ("bad tagstring"));
  1911. Int waste = 0;
  1912. #endif
  1913. MemoryPool *pool = findPoolForSize(numBytes);
  1914. if (pool != NULL)
  1915. {
  1916. result = pool->allocateBlockDoNotZeroImplementation(PASS_LITERALSTRING_ARG1);
  1917. #ifdef MEMORYPOOL_DEBUG
  1918. {
  1919. USE_PERF_TIMER(MemoryPoolDebugging)
  1920. waste = pool->getAllocationSize() - numBytes;
  1921. MemoryPoolSingleBlock *wblock = MemoryPoolSingleBlock::recoverBlockFromUserData(result);
  1922. wblock->debugSetWastedSize(waste);
  1923. #ifdef INTENSE_DMA_BOOKKEEPING
  1924. if (doingIntenseDMA == 0)
  1925. #endif
  1926. {
  1927. theWastedDMA += (waste);
  1928. if (thePeakWastedDMA < theWastedDMA)
  1929. thePeakWastedDMA = theWastedDMA;
  1930. }
  1931. }
  1932. #endif MEMORYPOOL_DEBUG
  1933. }
  1934. else
  1935. {
  1936. // too big for our pools -- just go right to the metal.
  1937. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::rawAllocateSingleBlock(&m_rawBlocks, numBytes, m_factory PASS_LITERALSTRING_ARG2);
  1938. #ifdef MEMORYPOOL_CHECKPOINTING
  1939. BlockCheckpointInfo *bi = debugAddCheckpointInfo(block->debugGetLiteralTagString(), m_factory->getCurCheckpoint(), numBytes);
  1940. if (bi)
  1941. block->debugSetCheckpointInfo(bi);
  1942. #endif
  1943. result = block->getUserData();
  1944. #ifdef MEMORYPOOL_DEBUG
  1945. m_factory->adjustTotals(debugLiteralTagString, numBytes, numBytes);
  1946. theTotalLargeBlocks += numBytes;
  1947. if (thePeakLargeBlocks < theTotalLargeBlocks)
  1948. thePeakLargeBlocks = theTotalLargeBlocks;
  1949. #endif
  1950. }
  1951. #ifdef MEMORYPOOL_DEBUG
  1952. {
  1953. USE_PERF_TIMER(MemoryPoolDebugging)
  1954. theTotalDMA += numBytes;
  1955. if (thePeakDMA < theTotalDMA)
  1956. thePeakDMA = theTotalDMA;
  1957. #ifdef INTENSE_DMA_BOOKKEEPING
  1958. if (isMemoryManagerOfficiallyInited() && doingIntenseDMA == 0)
  1959. {
  1960. ++doingIntenseDMA;
  1961. UsedNPeak& up = TheUsedNPeakMap[debugLiteralTagString];
  1962. up.used += numBytes;
  1963. if (up.peak < up.used)
  1964. up.peak = up.used;
  1965. up.waste += waste;
  1966. if (up.peakwaste < up.waste)
  1967. up.peakwaste = up.waste;
  1968. --doingIntenseDMA;
  1969. }
  1970. #endif
  1971. }
  1972. #endif MEMORYPOOL_DEBUG
  1973. ++m_usedBlocksInDma;
  1974. DEBUG_ASSERTCRASH(m_usedBlocksInDma >= 0, ("negative count for m_usedBlocksInDma"));
  1975. #ifdef MEMORYPOOL_DEBUG
  1976. #ifdef USE_FILLER_VALUE
  1977. {
  1978. USE_PERF_TIMER(MemoryPoolInitFilling)
  1979. ::memset32(result, s_initFillerValue, numBytes);
  1980. }
  1981. #endif
  1982. #endif
  1983. return result;
  1984. }
  1985. //-----------------------------------------------------------------------------
  1986. /**
  1987. allocate a chunk-o-bytes from this DMA and return it, and zero out the contents first.
  1988. if unable to allocate, throw ERROR_OUT_OF_MEMORY.
  1989. this function will never return null.
  1990. */
  1991. void *DynamicMemoryAllocator::allocateBytesImplementation(Int numBytes DECLARE_LITERALSTRING_ARG2)
  1992. {
  1993. void* p = allocateBytesDoNotZeroImplementation(numBytes PASS_LITERALSTRING_ARG2); // throws on failure
  1994. memset(p, 0, numBytes);
  1995. return p;
  1996. }
  1997. //-----------------------------------------------------------------------------
  1998. /**
  1999. free a chunk-o-bytes allocated by this dma. it's ok to pass null.
  2000. */
  2001. void DynamicMemoryAllocator::freeBytes(void* pBlockPtr)
  2002. {
  2003. if (!pBlockPtr)
  2004. return;
  2005. ScopedCriticalSection scopedCriticalSection(TheDmaCriticalSection);
  2006. #ifdef MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
  2007. DEBUG_ASSERTCRASH(debugIsBlockInDma(pBlockPtr), ("block is not in this dma"));
  2008. #endif
  2009. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  2010. #ifdef MEMORYPOOL_DEBUG
  2011. Int waste = 0, used = 0;
  2012. {
  2013. USE_PERF_TIMER(MemoryPoolDebugging)
  2014. waste = 0;
  2015. used = block->debugGetLogicalSize();
  2016. theTotalDMA -= used;
  2017. if (thePeakDMA < theTotalDMA)
  2018. thePeakDMA = theTotalDMA;
  2019. #ifdef INTENSE_DMA_BOOKKEEPING
  2020. const char* tagString = block->debugGetLiteralTagString();
  2021. #endif
  2022. }
  2023. #endif MEMORYPOOL_DEBUG
  2024. if (block->getOwningBlob())
  2025. {
  2026. #ifdef MEMORYPOOL_DEBUG
  2027. {
  2028. USE_PERF_TIMER(MemoryPoolDebugging)
  2029. DEBUG_ASSERTCRASH(findPoolForSize(used) == block->getOwningBlob()->getOwningPool(), ("pool mismatch"));
  2030. #ifdef INTENSE_DMA_BOOKKEEPING
  2031. if (doingIntenseDMA == 0)
  2032. #endif
  2033. {
  2034. waste = block->debugGetWastedSize();
  2035. theWastedDMA -= waste;
  2036. if (thePeakWastedDMA < theWastedDMA)
  2037. thePeakWastedDMA = theWastedDMA;
  2038. }
  2039. }
  2040. #endif MEMORYPOOL_DEBUG
  2041. block->getOwningBlob()->getOwningPool()->freeBlock(pBlockPtr);
  2042. }
  2043. else
  2044. {
  2045. // was allocated via sysAllocate.
  2046. #ifdef MEMORYPOOL_CHECKPOINTING
  2047. BlockCheckpointInfo *bi = block->debugGetCheckpointInfo();
  2048. DEBUG_ASSERTCRASH(bi, ("hmm, no checkpoint info"));
  2049. if (bi)
  2050. bi->debugSetFreepoint(m_factory->getCurCheckpoint());
  2051. #endif
  2052. #ifdef MEMORYPOOL_DEBUG
  2053. m_factory->adjustTotals(block->debugGetLiteralTagString(), -used, -used);
  2054. theTotalLargeBlocks -= used;
  2055. if (thePeakLargeBlocks < theTotalLargeBlocks)
  2056. thePeakLargeBlocks = theTotalLargeBlocks;
  2057. block->debugMarkBlockAsFree();
  2058. #endif
  2059. block->removeBlockFromList(&m_rawBlocks);
  2060. ::sysFree((void *)block);
  2061. }
  2062. --m_usedBlocksInDma;
  2063. DEBUG_ASSERTCRASH(m_usedBlocksInDma >= 0, ("negative count for m_usedBlocksInDma"));
  2064. #ifdef INTENSE_DMA_BOOKKEEPING
  2065. if (isMemoryManagerOfficiallyInited() && doingIntenseDMA == 0)
  2066. {
  2067. ++doingIntenseDMA;
  2068. UsedNPeak& up = TheUsedNPeakMap[tagString];
  2069. up.used -= used;
  2070. if (up.peak < up.used)
  2071. up.peak = up.used;
  2072. up.waste -= waste;
  2073. if (up.peakwaste < up.waste)
  2074. up.peakwaste = up.waste;
  2075. --doingIntenseDMA;
  2076. }
  2077. #endif
  2078. }
  2079. //-----------------------------------------------------------------------------
  2080. Int DynamicMemoryAllocator::getActualAllocationSize(Int numBytes)
  2081. {
  2082. MemoryPool *pool = findPoolForSize(numBytes);
  2083. return pool ? pool->getAllocationSize() : numBytes;
  2084. }
  2085. //-----------------------------------------------------------------------------
  2086. /**
  2087. throw away everything in the DMA, but keep the DMA itself valid.
  2088. */
  2089. void DynamicMemoryAllocator::reset()
  2090. {
  2091. for (Int i = 0; i < m_numPools; i++)
  2092. {
  2093. if (m_pools[i])
  2094. {
  2095. m_pools[i]->reset();
  2096. }
  2097. }
  2098. while (m_rawBlocks)
  2099. freeBytes(m_rawBlocks->getUserData());
  2100. m_usedBlocksInDma = 0;
  2101. }
  2102. //-----------------------------------------------------------------------------
  2103. #ifdef MEMORYPOOL_DEBUG
  2104. /**
  2105. return true iff the given pool is a subpool of this dma.
  2106. */
  2107. Bool DynamicMemoryAllocator::debugIsPoolInDma(MemoryPool *pool)
  2108. {
  2109. USE_PERF_TIMER(MemoryPoolDebugging)
  2110. if (!pool)
  2111. return false;
  2112. for (Int i = 0; i < m_numPools; i++)
  2113. {
  2114. if (m_pools[i] == pool)
  2115. return true;
  2116. }
  2117. return false;
  2118. }
  2119. #endif
  2120. //-----------------------------------------------------------------------------
  2121. #ifdef MEMORYPOOL_DEBUG
  2122. /**
  2123. return true iff the block was allocated by this dma
  2124. (either from a subpool or as a raw block).
  2125. */
  2126. Bool DynamicMemoryAllocator::debugIsBlockInDma(void *pBlockPtr)
  2127. {
  2128. USE_PERF_TIMER(MemoryPoolDebugging)
  2129. if (!pBlockPtr)
  2130. return false;
  2131. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  2132. if (block->getOwningBlob())
  2133. {
  2134. MemoryPool *pool = block->getOwningBlob()->getOwningPool();
  2135. return pool && pool->debugIsBlockInPool(pBlockPtr) && debugIsPoolInDma(pool);
  2136. }
  2137. else
  2138. {
  2139. for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
  2140. {
  2141. if (b == block)
  2142. return true;
  2143. }
  2144. return false;
  2145. }
  2146. }
  2147. #endif
  2148. //-----------------------------------------------------------------------------
  2149. #ifdef MEMORYPOOL_DEBUG
  2150. /**
  2151. return the tagstring for the block. this will never return null; if
  2152. the block is null or invalid, "FREE_SINGLEBLOCK_TAG_STRING" will be returned.
  2153. it is assumed that the block was allocated by this dma.
  2154. */
  2155. const char *DynamicMemoryAllocator::debugGetBlockTagString(void *pBlockPtr)
  2156. {
  2157. USE_PERF_TIMER(MemoryPoolDebugging)
  2158. if (!pBlockPtr)
  2159. return FREE_SINGLEBLOCK_TAG_STRING;
  2160. if (!debugIsBlockInDma(pBlockPtr))
  2161. {
  2162. DEBUG_CRASH(("block is not in this dma"));
  2163. return FREE_SINGLEBLOCK_TAG_STRING;
  2164. }
  2165. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  2166. return block->debugGetLiteralTagString();
  2167. }
  2168. #endif
  2169. //-----------------------------------------------------------------------------
  2170. #ifdef MEMORYPOOL_DEBUG
  2171. /**
  2172. perform internal consistency checking on this DMA.
  2173. */
  2174. void DynamicMemoryAllocator::debugMemoryVerifyDma()
  2175. {
  2176. USE_PERF_TIMER(MemoryPoolDebugging)
  2177. for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
  2178. {
  2179. b->debugVerifyBlock();
  2180. }
  2181. }
  2182. #endif
  2183. //-----------------------------------------------------------------------------
  2184. #ifdef MEMORYPOOL_CHECKPOINTING
  2185. /**
  2186. free all checkpointinfo for this dma, and reset all ptrs to checkpointinfo.
  2187. */
  2188. void DynamicMemoryAllocator::debugResetCheckpoints()
  2189. {
  2190. Checkpointable::debugResetCheckpoints();
  2191. for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
  2192. {
  2193. b->debugResetCheckpoint();
  2194. }
  2195. }
  2196. #endif
  2197. //-----------------------------------------------------------------------------
  2198. #ifdef MEMORYPOOL_DEBUG
  2199. /**
  2200. calculate the total number of raw blocks allocated by this dma,
  2201. and the total number of bytes (logical) used by those raw blocks.
  2202. */
  2203. Int DynamicMemoryAllocator::debugCalcRawBlockBytes(Int *numBlocks)
  2204. {
  2205. USE_PERF_TIMER(MemoryPoolDebugging)
  2206. if (numBlocks)
  2207. *numBlocks = 0;
  2208. Int bytes = 0;
  2209. for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
  2210. {
  2211. if (numBlocks)
  2212. *numBlocks += 1;
  2213. bytes += b->debugGetLogicalSize();
  2214. }
  2215. return bytes;
  2216. }
  2217. #endif
  2218. //-----------------------------------------------------------------------------
  2219. #ifdef MEMORYPOOL_DEBUG
  2220. Int DynamicMemoryAllocator::debugDmaReportLeaks()
  2221. {
  2222. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  2223. Int any = false;
  2224. for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
  2225. {
  2226. any += b->debugSingleBlockReportLeak("(DMA)");
  2227. }
  2228. return any;
  2229. }
  2230. #endif
  2231. //-----------------------------------------------------------------------------
  2232. #ifdef MEMORYPOOL_DEBUG
  2233. /**
  2234. print a report about raw block allocations to the debug log.
  2235. */
  2236. void DynamicMemoryAllocator::debugDmaInfoReport( FILE *fp )
  2237. {
  2238. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  2239. const char *PREPEND = "POOLINFO"; // allows grepping more easily
  2240. Int numBlocks;
  2241. Int bytes = debugCalcRawBlockBytes(&numBlocks);
  2242. DEBUG_LOG(("%s,Total Raw Blocks = %d\n",PREPEND,numBlocks));
  2243. DEBUG_LOG(("%s,Total Raw Block Bytes = %d\n",PREPEND,bytes));
  2244. DEBUG_LOG(("%s,Average Raw Block Size = %d\n",PREPEND,numBlocks?bytes/numBlocks:0));
  2245. DEBUG_LOG(("%s,Raw Blocks:\n",PREPEND));
  2246. if( fp )
  2247. {
  2248. fprintf( fp, "%s,Total Raw Blocks = %d\n",PREPEND,numBlocks );
  2249. fprintf( fp, "%s,Total Raw Block Bytes = %d\n",PREPEND,bytes );
  2250. fprintf( fp, "%s,Average Raw Block Size = %d\n",PREPEND,numBlocks?bytes/numBlocks:0 );
  2251. fprintf( fp, "%s,Raw Blocks:\n",PREPEND );
  2252. }
  2253. for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
  2254. {
  2255. DEBUG_LOG(("%s, Blocksize=%d\n",PREPEND,b->debugGetLogicalSize()));
  2256. //if( fp )
  2257. //{
  2258. // fprintf( fp, "%s, Blocksize=%d\n",PREPEND,b->debugGetLogicalSize() );
  2259. //}
  2260. }
  2261. }
  2262. #endif
  2263. //-----------------------------------------------------------------------------
  2264. // METHODS for MemoryPoolFactory
  2265. //-----------------------------------------------------------------------------
  2266. //-----------------------------------------------------------------------------
  2267. /**
  2268. init the factory to safe values.
  2269. */
  2270. MemoryPoolFactory::MemoryPoolFactory() :
  2271. m_firstPoolInFactory(NULL),
  2272. m_firstDmaInFactory(NULL)
  2273. #ifdef MEMORYPOOL_CHECKPOINTING
  2274. , m_curCheckpoint(0)
  2275. #endif
  2276. #ifdef MEMORYPOOL_DEBUG
  2277. , m_usedBytes(0)
  2278. , m_physBytes(0)
  2279. , m_peakUsedBytes(0)
  2280. , m_peakPhysBytes(0)
  2281. #endif
  2282. {
  2283. #ifdef MEMORYPOOL_DEBUG
  2284. for (int i = 0; i < MAX_SPECIAL_USED; ++i)
  2285. {
  2286. m_usedBytesSpecial[i] = 0;
  2287. m_usedBytesSpecialPeak[i] = 0;
  2288. m_physBytesSpecial[i] = 0;
  2289. m_physBytesSpecialPeak[i] = 0;
  2290. }
  2291. #ifdef USE_FILLER_VALUE
  2292. calcFillerValue(GameClientRandomValue(0, MAX_INIT_FILLER_COUNT-1));
  2293. #endif
  2294. #endif
  2295. }
  2296. //-----------------------------------------------------------------------------
  2297. /**
  2298. initialize the factory.
  2299. */
  2300. void MemoryPoolFactory::init()
  2301. {
  2302. // my, that was easy
  2303. }
  2304. //-----------------------------------------------------------------------------
  2305. /**
  2306. destroy the factory, and all its pools and dmas.
  2307. */
  2308. MemoryPoolFactory::~MemoryPoolFactory()
  2309. {
  2310. while (m_firstPoolInFactory)
  2311. {
  2312. destroyMemoryPool(m_firstPoolInFactory);
  2313. }
  2314. while (m_firstDmaInFactory)
  2315. {
  2316. destroyDynamicMemoryAllocator(m_firstDmaInFactory);
  2317. }
  2318. }
  2319. //-----------------------------------------------------------------------------
  2320. /**
  2321. create a new memory pool.
  2322. */
  2323. MemoryPool *MemoryPoolFactory::createMemoryPool(const PoolInitRec *parms)
  2324. {
  2325. return createMemoryPool(parms->poolName, parms->allocationSize, parms->initialAllocationCount, parms->overflowAllocationCount);
  2326. }
  2327. //-----------------------------------------------------------------------------
  2328. /**
  2329. create a new memory pool. (alternate argument list)
  2330. */
  2331. MemoryPool *MemoryPoolFactory::createMemoryPool(const char *poolName, Int allocationSize, Int initialAllocationCount, Int overflowAllocationCount)
  2332. {
  2333. MemoryPool *pool = findMemoryPool(poolName);
  2334. if (pool)
  2335. {
  2336. DEBUG_ASSERTCRASH(allocationSize == pool->getAllocationSize(), ("pool size mismatch"));
  2337. return pool;
  2338. }
  2339. userMemoryAdjustPoolSize(poolName, initialAllocationCount, overflowAllocationCount);
  2340. if (initialAllocationCount <= 0 || overflowAllocationCount < 0)
  2341. {
  2342. DEBUG_CRASH(("illegal pool size: %d %d\n",initialAllocationCount,overflowAllocationCount));
  2343. throw ERROR_OUT_OF_MEMORY;
  2344. }
  2345. pool = new (::sysAllocate(sizeof MemoryPool)) MemoryPool; // will throw on failure
  2346. pool->init(this, poolName, allocationSize, initialAllocationCount, overflowAllocationCount); // will throw on failure
  2347. pool->addToList(&m_firstPoolInFactory);
  2348. return pool;
  2349. }
  2350. //-----------------------------------------------------------------------------
  2351. /**
  2352. find a memory pool with the given name; return null if no such pool exists,
  2353. return null. note that this function isn't particularly fast (it just does
  2354. a linear search), so you should probably cache the result.
  2355. */
  2356. MemoryPool *MemoryPoolFactory::findMemoryPool(const char *poolName)
  2357. {
  2358. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2359. {
  2360. if (!strcmp(poolName, pool->getPoolName()))
  2361. {
  2362. DEBUG_ASSERTCRASH(poolName == pool->getPoolName(), ("hmm, ptrs should probably match here"));
  2363. return pool;
  2364. }
  2365. }
  2366. return NULL;
  2367. }
  2368. //-----------------------------------------------------------------------------
  2369. /**
  2370. destroy the given memory pool. you normally will never need to call this directly.
  2371. */
  2372. void MemoryPoolFactory::destroyMemoryPool(MemoryPool *pMemoryPool)
  2373. {
  2374. if (!pMemoryPool)
  2375. return;
  2376. DEBUG_ASSERTCRASH(pMemoryPool->getUsedBlockCount() == 0, ("destroying a nonempty pool"));
  2377. pMemoryPool->removeFromList(&m_firstPoolInFactory);
  2378. // this is evil... since there is no 'placement delete' we must do this the hard way
  2379. // and call the dtor directly. ordinarily this is heinous, but in this case we'll
  2380. // make an exception.
  2381. pMemoryPool->~MemoryPool();
  2382. ::sysFree((void *)pMemoryPool);
  2383. }
  2384. //-----------------------------------------------------------------------------
  2385. /**
  2386. create a new dynamicMemoryAllocator. You normally will never need to call this directly.
  2387. */
  2388. DynamicMemoryAllocator *MemoryPoolFactory::createDynamicMemoryAllocator(Int numSubPools, const PoolInitRec pParms[])
  2389. {
  2390. DynamicMemoryAllocator *dma;
  2391. dma = new (::sysAllocate(sizeof DynamicMemoryAllocator)) DynamicMemoryAllocator; // will throw on failure
  2392. dma->init(this, numSubPools, pParms); // will throw on failure
  2393. dma->addToList(&m_firstDmaInFactory);
  2394. return dma;
  2395. }
  2396. //-----------------------------------------------------------------------------
  2397. /**
  2398. destroy the given dynamicMemoryAllocator. You normally will never need to call this directly.
  2399. */
  2400. void MemoryPoolFactory::destroyDynamicMemoryAllocator(DynamicMemoryAllocator *dma)
  2401. {
  2402. if (!dma)
  2403. return;
  2404. dma->removeFromList(&m_firstDmaInFactory);
  2405. // this is evil... since there is no 'placement delete' we must do this the hard way
  2406. // and call the dtor directly. ordinarily this is heinous, but in this case we'll
  2407. // make an exception.
  2408. dma->~DynamicMemoryAllocator();
  2409. ::sysFree((void *)dma);
  2410. }
  2411. //-----------------------------------------------------------------------------
  2412. /**
  2413. throw away everything in all pools/dmas owned by this factory, but keep the factory
  2414. and pools/dmas themselves valid.
  2415. */
  2416. void MemoryPoolFactory::reset()
  2417. {
  2418. #ifdef MEMORYPOOL_CHECKPOINTING
  2419. debugResetCheckpoints();
  2420. #endif
  2421. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2422. {
  2423. pool->reset();
  2424. }
  2425. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2426. {
  2427. dma->reset();
  2428. }
  2429. #ifdef MEMORYPOOL_DEBUG
  2430. m_usedBytes = 0;
  2431. m_physBytes = 0;
  2432. m_peakUsedBytes = 0;
  2433. m_peakPhysBytes = 0;
  2434. for (int i = 0; i < MAX_SPECIAL_USED; ++i)
  2435. {
  2436. m_usedBytesSpecial[i] = 0;
  2437. m_usedBytesSpecialPeak[i] = 0;
  2438. m_physBytesSpecial[i] = 0;
  2439. m_physBytesSpecialPeak[i] = 0;
  2440. }
  2441. #ifdef USE_FILLER_VALUE
  2442. calcFillerValue(GameClientRandomValue(0, MAX_INIT_FILLER_COUNT-1));
  2443. #endif
  2444. #endif
  2445. }
  2446. //-----------------------------------------------------------------------------
  2447. #ifdef MEMORYPOOL_DEBUG
  2448. static const char* s_specialPrefixes[MAX_SPECIAL_USED] =
  2449. {
  2450. "Misc", // the catchall for stuff that doesn't match others
  2451. "W3D_",
  2452. "W3A_",
  2453. "STL_",
  2454. "STR_",
  2455. NULL
  2456. };
  2457. #endif
  2458. //-----------------------------------------------------------------------------
  2459. #ifdef MEMORYPOOL_DEBUG
  2460. /**
  2461. perform bookkeeping on memory usage statistics.
  2462. */
  2463. void MemoryPoolFactory::adjustTotals(const char* tagString, Int usedDelta, Int physDelta)
  2464. {
  2465. USE_PERF_TIMER(MemoryPoolDebugging)
  2466. m_usedBytes += usedDelta;
  2467. m_physBytes += physDelta;
  2468. if (m_peakUsedBytes < m_usedBytes)
  2469. m_peakUsedBytes = m_usedBytes;
  2470. if (m_peakPhysBytes < m_physBytes)
  2471. m_peakPhysBytes = m_physBytes;
  2472. int found = 0; // if no matches found, goes into slot zero
  2473. for (int i = 1; i < MAX_SPECIAL_USED; ++i) // start at 1, not zero
  2474. {
  2475. if (s_specialPrefixes[i] == NULL)
  2476. break;
  2477. if (strncmp(tagString, s_specialPrefixes[i], strlen(s_specialPrefixes[i])) == 0)
  2478. {
  2479. found = i;
  2480. break;
  2481. }
  2482. }
  2483. m_usedBytesSpecial[found] += usedDelta;
  2484. m_physBytesSpecial[found] += physDelta;
  2485. if (m_usedBytesSpecialPeak[found] < m_usedBytesSpecial[found])
  2486. m_usedBytesSpecialPeak[found] = m_usedBytesSpecial[found];
  2487. if (m_physBytesSpecialPeak[found] < m_physBytesSpecial[found])
  2488. m_physBytesSpecialPeak[found] = m_physBytesSpecial[found];
  2489. }
  2490. #endif
  2491. //-----------------------------------------------------------------------------
  2492. #ifdef MEMORYPOOL_DEBUG
  2493. void MemoryPoolFactory::debugSetInitFillerIndex(Int index)
  2494. {
  2495. #ifdef USE_FILLER_VALUE
  2496. if (index < 0 || index >= MAX_INIT_FILLER_COUNT)
  2497. index = GameClientRandomValue(0, MAX_INIT_FILLER_COUNT-1);
  2498. calcFillerValue(index);
  2499. #endif
  2500. }
  2501. #endif
  2502. //-----------------------------------------------------------------------------
  2503. #ifdef MEMORYPOOL_DEBUG
  2504. /**
  2505. perform internal consistency checking on the factory, and all of its
  2506. pools and dmas.
  2507. */
  2508. void MemoryPoolFactory::debugMemoryVerify()
  2509. {
  2510. USE_PERF_TIMER(MemoryPoolDebugging)
  2511. Int used = 0, phys = 0;
  2512. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2513. {
  2514. pool->debugMemoryVerifyPool();
  2515. used += pool->getUsedBlockCount()*pool->getAllocationSize();
  2516. phys += pool->getTotalBlockCount()*pool->getAllocationSize();
  2517. }
  2518. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2519. {
  2520. dma->debugMemoryVerifyDma();
  2521. Int tmp = dma->debugCalcRawBlockBytes(NULL);
  2522. used += tmp;
  2523. phys += tmp;
  2524. }
  2525. DEBUG_ASSERTCRASH(used == m_usedBytes, ("used count mismatch"));
  2526. DEBUG_ASSERTCRASH(phys == m_physBytes, ("phys count mismatch"));
  2527. }
  2528. #endif
  2529. //-----------------------------------------------------------------------------
  2530. #ifdef MEMORYPOOL_DEBUG
  2531. /**
  2532. return true iff the block was allocated by any of the pools/dmas owned
  2533. by this factory.
  2534. */
  2535. Bool MemoryPoolFactory::debugIsBlockInAnyPool(void *pBlock)
  2536. {
  2537. USE_PERF_TIMER(MemoryPoolDebugging)
  2538. #ifdef MEMORYPOOL_INTENSE_VERIFY
  2539. debugMemoryVerify();
  2540. #endif
  2541. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2542. {
  2543. if (pool->debugIsBlockInPool(pBlock))
  2544. return true;
  2545. }
  2546. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2547. {
  2548. if (dma->debugIsBlockInDma(pBlock))
  2549. return true;
  2550. }
  2551. return false;
  2552. }
  2553. #endif
  2554. //-----------------------------------------------------------------------------
  2555. #ifdef MEMORYPOOL_DEBUG
  2556. /**
  2557. return the tagstring for this block. this will never return null; if
  2558. the block is null or invalid, "FREE_SINGLEBLOCK_TAG_STRING" will be returned.
  2559. it is assumed that the block was allocated by this factory.
  2560. */
  2561. const char *MemoryPoolFactory::debugGetBlockTagString(void *pBlockPtr)
  2562. {
  2563. USE_PERF_TIMER(MemoryPoolDebugging)
  2564. if (!pBlockPtr)
  2565. return FREE_SINGLEBLOCK_TAG_STRING;
  2566. #ifdef MEMORYPOOL_INTENSE_VERIFY
  2567. debugMemoryVerify();
  2568. #endif
  2569. if (!debugIsBlockInAnyPool(pBlockPtr))
  2570. {
  2571. DEBUG_CRASH(("block is not in this factory"));
  2572. return FREE_SINGLEBLOCK_TAG_STRING;
  2573. }
  2574. MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
  2575. return block->debugGetLiteralTagString();
  2576. }
  2577. #endif
  2578. //-----------------------------------------------------------------------------
  2579. #ifdef MEMORYPOOL_CHECKPOINTING
  2580. /**
  2581. set a new checkpoint for all future blocks allocated/freed by this factory's pools/dmas.
  2582. */
  2583. Int MemoryPoolFactory::debugSetCheckpoint()
  2584. {
  2585. return ++m_curCheckpoint;
  2586. }
  2587. #endif
  2588. //-----------------------------------------------------------------------------
  2589. #ifdef MEMORYPOOL_CHECKPOINTING
  2590. /**
  2591. throw away all checkpoint info for all pools/dmas.
  2592. */
  2593. void MemoryPoolFactory::debugResetCheckpoints()
  2594. {
  2595. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2596. {
  2597. pool->debugResetCheckpoints();
  2598. }
  2599. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2600. {
  2601. dma->debugResetCheckpoints();
  2602. }
  2603. m_curCheckpoint = 0;
  2604. }
  2605. #endif
  2606. //-----------------------------------------------------------------------------
  2607. void MemoryPoolFactory::memoryPoolUsageReport( const char* filename, FILE *appendToFileInstead )
  2608. {
  2609. #ifdef MEMORYPOOL_DEBUG
  2610. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  2611. FILE* perfStatsFile = NULL;
  2612. Int totalNamedPoolPeak = 0;
  2613. if( !appendToFileInstead )
  2614. {
  2615. char tmp[256];
  2616. strcpy(tmp,filename);
  2617. strcat(tmp,".csv");
  2618. perfStatsFile = fopen(tmp, "w");
  2619. }
  2620. else
  2621. {
  2622. perfStatsFile = appendToFileInstead;
  2623. }
  2624. if (perfStatsFile == NULL)
  2625. {
  2626. DEBUG_CRASH(("could not open/create perf file %s -- is it open in another app?",filename));
  2627. return;
  2628. }
  2629. Int lineIdx = 0;
  2630. MemoryPool *pool = m_firstPoolInFactory;
  2631. #ifdef INTENSE_DMA_BOOKKEEPING
  2632. UsedNPeakMap::const_iterator it = TheUsedNPeakMap.begin();
  2633. #endif
  2634. for (;;)
  2635. {
  2636. Bool keepGoing = false;
  2637. if (pool)
  2638. {
  2639. if (lineIdx == 0)
  2640. {
  2641. fprintf(perfStatsFile, "%s,%d","Unpooled Large Blocks (>1024 bytes)",thePeakLargeBlocks/1024);
  2642. }
  2643. else
  2644. {
  2645. Int sz = pool->getAllocationSize();
  2646. Int initial = pool->getInitialBlockCount()*sz;
  2647. Int peak = pool->getPeakBlockCount()*sz;
  2648. Int waste = initial - peak;
  2649. if (waste < 0) waste = 0;
  2650. fprintf(perfStatsFile, "%s,%d,%d",pool->getPoolName(),peak/1024,waste/1024);
  2651. totalNamedPoolPeak += peak;
  2652. pool = pool->getNextPoolInList();
  2653. }
  2654. keepGoing = true;
  2655. }
  2656. else
  2657. {
  2658. fprintf(perfStatsFile, ",,");
  2659. }
  2660. #ifdef INTENSE_DMA_BOOKKEEPING
  2661. if (it != TheUsedNPeakMap.end())
  2662. {
  2663. Int wastepct = (it->second.peakwaste * 100) / (it->second.peak + it->second.peakwaste);
  2664. fprintf(perfStatsFile, ",,,,%s,%d,%d,%d",it->first,it->second.peak/1024,it->second.peakwaste/1024,wastepct);
  2665. ++it;
  2666. keepGoing = true;
  2667. }
  2668. else
  2669. {
  2670. fprintf(perfStatsFile, ",,,,,,,");
  2671. }
  2672. #endif
  2673. if (lineIdx < MAX_SPECIAL_USED && s_specialPrefixes[lineIdx] != NULL)
  2674. {
  2675. fprintf(perfStatsFile, ",,,%s,%d",s_specialPrefixes[lineIdx],m_usedBytesSpecialPeak[lineIdx]/1024);
  2676. keepGoing = true;
  2677. }
  2678. fprintf(perfStatsFile, "\n");
  2679. ++lineIdx;
  2680. if (!keepGoing)
  2681. break;
  2682. }
  2683. fflush(perfStatsFile);
  2684. if( !appendToFileInstead )
  2685. {
  2686. fclose(perfStatsFile);
  2687. }
  2688. #endif
  2689. }
  2690. //-----------------------------------------------------------------------------
  2691. #ifdef MEMORYPOOL_DEBUG
  2692. /**
  2693. send a memory reports (based on the flags/checkpoints) to the debug log.
  2694. */
  2695. void MemoryPoolFactory::debugMemoryReport(Int flags, Int startCheckpoint, Int endCheckpoint, FILE *fp )
  2696. {
  2697. //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
  2698. Int oldFlags = DebugGetFlags();
  2699. DebugSetFlags(oldFlags & ~DEBUG_FLAG_PREPEND_TIME);
  2700. #ifdef MEMORYPOOL_CHECKPOINTING
  2701. Bool doBlockReport = (flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0 && (flags & _REPORT_CP_FREED_DONTCARE) != 0;
  2702. DEBUG_ASSERTCRASH(startCheckpoint >= 0 && startCheckpoint <= endCheckpoint && endCheckpoint <= m_curCheckpoint, ("bad checkpoints"));
  2703. DEBUG_ASSERTCRASH(((flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0) == ((flags & _REPORT_CP_FREED_DONTCARE) != 0), ("bad flags: must set at both alloc and free flag"));
  2704. #endif
  2705. debugMemoryVerify();
  2706. if (flags & REPORT_FACTORYINFO)
  2707. {
  2708. DEBUG_LOG(("------------------------------------------\n"));
  2709. DEBUG_LOG(("Begin Factory Info Report\n"));
  2710. DEBUG_LOG(("------------------------------------------\n"));
  2711. DEBUG_LOG(("Bytes in use (logical) = %d\n",m_usedBytes));
  2712. DEBUG_LOG(("Bytes in use (physical) = %d\n",m_physBytes));
  2713. DEBUG_LOG(("PEAK Bytes in use (logical) = %d\n",m_peakUsedBytes));
  2714. DEBUG_LOG(("PEAK Bytes in use (physical) = %d\n",m_peakPhysBytes));
  2715. DEBUG_LOG(("------------------------------------------\n"));
  2716. DEBUG_LOG(("End Factory Info Report\n"));
  2717. DEBUG_LOG(("------------------------------------------\n"));
  2718. if( fp )
  2719. {
  2720. fprintf( fp, "------------------------------------------\n" );
  2721. fprintf( fp, "Begin Factory Info Report\n" );
  2722. fprintf( fp, "------------------------------------------\n" );
  2723. fprintf( fp, "Bytes in use (logical) = %d\n",m_usedBytes );
  2724. fprintf( fp, "Bytes in use (physical) = %d\n",m_physBytes );
  2725. fprintf( fp, "PEAK Bytes in use (logical) = %d\n",m_peakUsedBytes );
  2726. fprintf( fp, "PEAK Bytes in use (physical) = %d\n",m_peakPhysBytes );
  2727. fprintf( fp, "------------------------------------------\n" );
  2728. fprintf( fp, "End Factory Info Report\n" );
  2729. fprintf( fp, "------------------------------------------\n" );
  2730. }
  2731. }
  2732. if (flags & REPORT_POOLINFO)
  2733. {
  2734. DEBUG_LOG(("------------------------------------------\n"));
  2735. DEBUG_LOG(("Begin Pool Info Report\n"));
  2736. DEBUG_LOG(("------------------------------------------\n"));
  2737. if( fp )
  2738. {
  2739. fprintf( fp, "------------------------------------------\n" );
  2740. fprintf( fp, "Begin Pool Info Report\n" );
  2741. fprintf( fp, "------------------------------------------\n" );
  2742. }
  2743. MemoryPool::debugPoolInfoReport( NULL, fp );
  2744. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2745. {
  2746. MemoryPool::debugPoolInfoReport( pool, fp );
  2747. }
  2748. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2749. {
  2750. dma->debugDmaInfoReport( fp );
  2751. }
  2752. DEBUG_LOG(("------------------------------------------\n"));
  2753. DEBUG_LOG(("End Pool Info Report\n"));
  2754. DEBUG_LOG(("------------------------------------------\n"));
  2755. if( fp )
  2756. {
  2757. fprintf( fp, "------------------------------------------\n" );
  2758. fprintf( fp, "End Pool Info Report\n" );
  2759. fprintf( fp, "------------------------------------------\n" );
  2760. }
  2761. }
  2762. if (flags & REPORT_POOL_OVERFLOW)
  2763. {
  2764. DEBUG_LOG(("------------------------------------------\n"));
  2765. DEBUG_LOG(("Begin Pool Overflow Report\n"));
  2766. DEBUG_LOG(("------------------------------------------\n"));
  2767. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2768. {
  2769. if (pool->getPeakBlockCount() > pool->getInitialBlockCount())
  2770. {
  2771. DEBUG_LOG(("*** Pool %s overflowed initial allocation of %d (peak allocation was %d)\n",pool->getPoolName(),pool->getInitialBlockCount(),pool->getPeakBlockCount()));
  2772. }
  2773. }
  2774. DEBUG_LOG(("------------------------------------------\n"));
  2775. DEBUG_LOG(("End Pool Overflow Report\n"));
  2776. DEBUG_LOG(("------------------------------------------\n"));
  2777. DEBUG_LOG(("------------------------------------------\n"));
  2778. DEBUG_LOG(("Begin Pool Underflow Report\n"));
  2779. DEBUG_LOG(("------------------------------------------\n"));
  2780. for (pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2781. {
  2782. Int peak = pool->getPeakBlockCount()*pool->getAllocationSize();
  2783. Int initial = pool->getInitialBlockCount()*pool->getAllocationSize();
  2784. if (peak < initial/2 && (initial - peak) > 4096)
  2785. {
  2786. DEBUG_LOG(("*** Pool %s used less than half its initial allocation of %d (peak allocation was %d, wasted %dk)\n",
  2787. pool->getPoolName(),pool->getInitialBlockCount(),pool->getPeakBlockCount(),(initial - peak)/1024));
  2788. }
  2789. }
  2790. DEBUG_LOG(("------------------------------------------\n"));
  2791. DEBUG_LOG(("End Pool Underflow Report\n"));
  2792. DEBUG_LOG(("------------------------------------------\n"));
  2793. }
  2794. if( flags & REPORT_SIMPLE_LEAKS )
  2795. {
  2796. DEBUG_LOG(("------------------------------------------\n"));
  2797. DEBUG_LOG(("Begin Simple Leak Report\n"));
  2798. DEBUG_LOG(("------------------------------------------\n"));
  2799. Int any = 0;
  2800. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2801. {
  2802. any += pool->debugPoolReportLeaks( pool->getPoolName() );
  2803. }
  2804. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2805. {
  2806. any += dma->debugDmaReportLeaks();
  2807. }
  2808. DEBUG_ASSERTCRASH(!any, ("There were %d memory leaks. Please fix them.\n",any));
  2809. DEBUG_LOG(("------------------------------------------\n"));
  2810. DEBUG_LOG(("End Simple Leak Report\n"));
  2811. DEBUG_LOG(("------------------------------------------\n"));
  2812. }
  2813. #ifdef MEMORYPOOL_CHECKPOINTING
  2814. if (doBlockReport)
  2815. {
  2816. const char* nm = (this == TheMemoryPoolFactory) ? "TheMemoryPoolFactory" : "*** UNKNOWN *** MemoryPoolFactory";
  2817. DEBUG_LOG(("\n"));
  2818. DEBUG_LOG(("------------------------------------------\n"));
  2819. DEBUG_LOG(("Begin Block Report for %s\n", nm));
  2820. DEBUG_LOG(("------------------------------------------\n"));
  2821. char buf[256] = "";
  2822. if (flags & _REPORT_CP_ALLOCATED_BEFORE) strcat(buf, "AllocBefore ");
  2823. if (flags & _REPORT_CP_ALLOCATED_BETWEEN) strcat(buf, "AllocBetween ");
  2824. if (flags & _REPORT_CP_FREED_BEFORE) strcat(buf, "FreedBefore ");
  2825. if (flags & _REPORT_CP_FREED_BETWEEN) strcat(buf, "FreedBetween ");
  2826. if (flags & _REPORT_CP_FREED_NEVER) strcat(buf, "StillExisting ");
  2827. DEBUG_LOG(("Options: Between checkpoints %d and %d, report on (%s)\n",startCheckpoint,endCheckpoint,buf));
  2828. DEBUG_LOG(("------------------------------------------\n"));
  2829. BlockCheckpointInfo::doBlockCheckpointReport( NULL, "", 0, 0, 0 );
  2830. for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
  2831. {
  2832. pool->debugCheckpointReport(flags, startCheckpoint, endCheckpoint, pool->getPoolName());
  2833. }
  2834. for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
  2835. {
  2836. dma->debugCheckpointReport(flags, startCheckpoint, endCheckpoint, "(Oversized)");
  2837. }
  2838. DEBUG_LOG(("------------------------------------------\n"));
  2839. DEBUG_LOG(("End Block Report for %s\n", nm));
  2840. DEBUG_LOG(("------------------------------------------\n"));
  2841. }
  2842. #endif
  2843. DebugSetFlags(oldFlags);
  2844. }
  2845. #endif
  2846. //-----------------------------------------------------------------------------
  2847. // GLOBAL FUNCTIONS
  2848. //-----------------------------------------------------------------------------
  2849. /*
  2850. This is a trick that is intended to force MSVC to link this file (and thus,
  2851. these definitions of new/delete) ahead of all others. (We do debug checking
  2852. to ensure that's the case)
  2853. */
  2854. #if defined(_DEBUG)
  2855. #pragma comment(lib, "GameEngineDebug")
  2856. #elif defined(_INTERNAL)
  2857. #pragma comment(lib, "GameEngineInternal")
  2858. #else
  2859. #pragma comment(lib, "GameEngine")
  2860. #endif
  2861. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  2862. #pragma comment(linker, "/force:multiple")
  2863. #endif
  2864. static int theLinkTester = 0;
  2865. //-----------------------------------------------------------------------------
  2866. void* STLSpecialAlloc::allocate(size_t __n)
  2867. {
  2868. ++theLinkTester;
  2869. preMainInitMemoryManager();
  2870. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
  2871. return TheDynamicMemoryAllocator->allocateBytes(__n, "STL_");
  2872. }
  2873. //-----------------------------------------------------------------------------
  2874. void STLSpecialAlloc::deallocate(void* __p, size_t)
  2875. {
  2876. ++theLinkTester;
  2877. preMainInitMemoryManager();
  2878. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
  2879. TheDynamicMemoryAllocator->freeBytes(__p);
  2880. }
  2881. //-----------------------------------------------------------------------------
  2882. /**
  2883. overload for global operator new; send requests to TheDynamicMemoryAllocator.
  2884. */
  2885. void *operator new(size_t size)
  2886. {
  2887. ++theLinkTester;
  2888. preMainInitMemoryManager();
  2889. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
  2890. return TheDynamicMemoryAllocator->allocateBytes(size, "global operator new");
  2891. }
  2892. //-----------------------------------------------------------------------------
  2893. /**
  2894. overload for global operator new[]; send requests to TheDynamicMemoryAllocator.
  2895. */
  2896. void *operator new[](size_t size)
  2897. {
  2898. ++theLinkTester;
  2899. preMainInitMemoryManager();
  2900. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
  2901. return TheDynamicMemoryAllocator->allocateBytes(size, "global operator new[]");
  2902. }
  2903. //-----------------------------------------------------------------------------
  2904. /**
  2905. overload for global operator delete; send requests to TheDynamicMemoryAllocator.
  2906. */
  2907. void operator delete(void *p)
  2908. {
  2909. ++theLinkTester;
  2910. preMainInitMemoryManager();
  2911. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
  2912. TheDynamicMemoryAllocator->freeBytes(p);
  2913. }
  2914. //-----------------------------------------------------------------------------
  2915. /**
  2916. overload for global operator delete[]; send requests to TheDynamicMemoryAllocator.
  2917. */
  2918. void operator delete[](void *p)
  2919. {
  2920. ++theLinkTester;
  2921. preMainInitMemoryManager();
  2922. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
  2923. TheDynamicMemoryAllocator->freeBytes(p);
  2924. }
  2925. //-----------------------------------------------------------------------------
  2926. /**
  2927. overload for global operator new (MFC debug version); send requests to TheDynamicMemoryAllocator.
  2928. */
  2929. void* operator new(size_t size, const char * fname, int)
  2930. {
  2931. ++theLinkTester;
  2932. preMainInitMemoryManager();
  2933. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
  2934. #ifdef MEMORYPOOL_DEBUG
  2935. return TheDynamicMemoryAllocator->allocateBytesImplementation(size, fname);
  2936. #else
  2937. return TheDynamicMemoryAllocator->allocateBytesImplementation(size);
  2938. #endif
  2939. }
  2940. //-----------------------------------------------------------------------------
  2941. /**
  2942. overload for global operator delete (MFC debug version); send requests to TheDynamicMemoryAllocator.
  2943. */
  2944. void operator delete(void * p, const char *, int)
  2945. {
  2946. ++theLinkTester;
  2947. preMainInitMemoryManager();
  2948. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
  2949. TheDynamicMemoryAllocator->freeBytes(p);
  2950. }
  2951. //-----------------------------------------------------------------------------
  2952. /**
  2953. overload for global operator new (MFC debug version); send requests to TheDynamicMemoryAllocator.
  2954. */
  2955. void* operator new[](size_t size, const char * fname, int)
  2956. {
  2957. ++theLinkTester;
  2958. preMainInitMemoryManager();
  2959. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
  2960. #ifdef MEMORYPOOL_DEBUG
  2961. return TheDynamicMemoryAllocator->allocateBytesImplementation(size, fname);
  2962. #else
  2963. return TheDynamicMemoryAllocator->allocateBytesImplementation(size);
  2964. #endif
  2965. }
  2966. //-----------------------------------------------------------------------------
  2967. /**
  2968. overload for global operator delete (MFC debug version); send requests to TheDynamicMemoryAllocator.
  2969. */
  2970. void operator delete[](void * p, const char *, int)
  2971. {
  2972. ++theLinkTester;
  2973. preMainInitMemoryManager();
  2974. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
  2975. TheDynamicMemoryAllocator->freeBytes(p);
  2976. }
  2977. //-----------------------------------------------------------------------------
  2978. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  2979. void *calloc(size_t a, size_t b)
  2980. {
  2981. ++theLinkTester;
  2982. preMainInitMemoryManager();
  2983. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager"));
  2984. return TheDynamicMemoryAllocator->allocateBytes(a * b, "calloc");
  2985. }
  2986. #endif
  2987. //-----------------------------------------------------------------------------
  2988. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  2989. void free(void * p)
  2990. {
  2991. ++theLinkTester;
  2992. preMainInitMemoryManager();
  2993. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager"));
  2994. TheDynamicMemoryAllocator->freeBytes(p);
  2995. }
  2996. #endif
  2997. //-----------------------------------------------------------------------------
  2998. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  2999. void *malloc(size_t a)
  3000. {
  3001. ++theLinkTester;
  3002. preMainInitMemoryManager();
  3003. DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager"));
  3004. return TheDynamicMemoryAllocator->allocateBytesDoNotZero(a, "malloc");
  3005. }
  3006. #endif
  3007. //-----------------------------------------------------------------------------
  3008. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  3009. void *realloc(void *p, size_t s)
  3010. {
  3011. DEBUG_CRASH(("realloc is evil. do not call it."));
  3012. throw ERROR_OUT_OF_MEMORY;
  3013. }
  3014. #endif
  3015. //-----------------------------------------------------------------------------
  3016. /**
  3017. Initialize the memory manager, and create TheMemoryPoolFactory and TheDynamicMemoryAllocator.
  3018. */
  3019. void initMemoryManager()
  3020. {
  3021. if (TheMemoryPoolFactory == NULL)
  3022. {
  3023. Int numSubPools;
  3024. const PoolInitRec *pParms;
  3025. userMemoryManagerGetDmaParms(&numSubPools, &pParms);
  3026. TheMemoryPoolFactory = new (::sysAllocate(sizeof MemoryPoolFactory)) MemoryPoolFactory; // will throw on failure
  3027. TheMemoryPoolFactory->init(); // will throw on failure
  3028. TheDynamicMemoryAllocator = TheMemoryPoolFactory->createDynamicMemoryAllocator(numSubPools, pParms); // will throw on failure
  3029. userMemoryManagerInitPools();
  3030. thePreMainInitFlag = false;
  3031. }
  3032. else
  3033. {
  3034. if (thePreMainInitFlag)
  3035. {
  3036. // quietly ignore the call
  3037. }
  3038. else
  3039. {
  3040. DEBUG_CRASH(("memory manager is already inited"));
  3041. }
  3042. }
  3043. char* linktest;
  3044. theLinkTester = 0;
  3045. linktest = new char;
  3046. delete linktest;
  3047. linktest = new char[8];
  3048. delete [] linktest;
  3049. linktest = new char("",1);
  3050. delete linktest;
  3051. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  3052. linktest = (char*)malloc(1);
  3053. free(linktest);
  3054. linktest = (char*)calloc(1,1);
  3055. free(linktest);
  3056. #endif
  3057. #ifdef MEMORYPOOL_OVERRIDE_MALLOC
  3058. if (theLinkTester != 10)
  3059. #else
  3060. if (theLinkTester != 6)
  3061. #endif
  3062. {
  3063. DEBUG_CRASH(("Wrong operator new/delete linked in! Fix this...\n"));
  3064. exit(-1);
  3065. }
  3066. theMainInitFlag = true;
  3067. }
  3068. //-----------------------------------------------------------------------------
  3069. Bool isMemoryManagerOfficiallyInited()
  3070. {
  3071. return theMainInitFlag;
  3072. }
  3073. //-----------------------------------------------------------------------------
  3074. /**
  3075. Initialize the memory manager, and create TheMemoryPoolFactory and TheDynamicMemoryAllocator.
  3076. This is only called if memory is allocated prior to the normal call to initMemoryManager
  3077. (generally via a static C++ ctor).
  3078. */
  3079. static void preMainInitMemoryManager()
  3080. {
  3081. if (TheMemoryPoolFactory == NULL)
  3082. {
  3083. DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
  3084. DEBUG_LOG(("*** Initing Memory Manager prior to main!\n"));
  3085. Int numSubPools;
  3086. const PoolInitRec *pParms;
  3087. userMemoryManagerGetDmaParms(&numSubPools, &pParms);
  3088. TheMemoryPoolFactory = new (::sysAllocate(sizeof MemoryPoolFactory)) MemoryPoolFactory; // will throw on failure
  3089. TheMemoryPoolFactory->init(); // will throw on failure
  3090. TheDynamicMemoryAllocator = TheMemoryPoolFactory->createDynamicMemoryAllocator(numSubPools, pParms); // will throw on failure
  3091. userMemoryManagerInitPools();
  3092. thePreMainInitFlag = true;
  3093. }
  3094. }
  3095. //-----------------------------------------------------------------------------
  3096. /**
  3097. shutdown the memory manager and discard all memory. Note: if preMainInitMemoryManager()
  3098. was called prior to initMemoryManager(), this call will do nothing.
  3099. */
  3100. void shutdownMemoryManager()
  3101. {
  3102. if (thePreMainInitFlag)
  3103. {
  3104. #ifdef MEMORYPOOL_DEBUG
  3105. DEBUG_LOG(("*** Memory Manager was inited prior to main -- skipping shutdown!\n"));
  3106. #endif
  3107. }
  3108. else
  3109. {
  3110. if (TheDynamicMemoryAllocator)
  3111. {
  3112. DEBUG_ASSERTCRASH(TheMemoryPoolFactory, ("hmm, no factory"));
  3113. if (TheMemoryPoolFactory)
  3114. TheMemoryPoolFactory->destroyDynamicMemoryAllocator(TheDynamicMemoryAllocator);
  3115. TheDynamicMemoryAllocator = NULL;
  3116. }
  3117. if (TheMemoryPoolFactory)
  3118. {
  3119. // this is evil... since there is no 'placement delete' we must do this the hard way
  3120. // and call the dtor directly. ordinarily this is heinous, but in this case we'll
  3121. // make an exception.
  3122. TheMemoryPoolFactory->~MemoryPoolFactory();
  3123. ::sysFree((void *)TheMemoryPoolFactory);
  3124. TheMemoryPoolFactory = NULL;
  3125. }
  3126. #ifdef MEMORYPOOL_DEBUG
  3127. DEBUG_LOG(("Peak system allocation was %d bytes\n",thePeakSystemAllocationInBytes));
  3128. DEBUG_LOG(("Wasted DMA space (peak) was %d bytes\n",thePeakWastedDMA));
  3129. DEBUG_ASSERTCRASH(theTotalSystemAllocationInBytes == 0, ("Leaked a total of %d raw bytes\n", theTotalSystemAllocationInBytes));
  3130. #endif
  3131. }
  3132. theMainInitFlag = false;
  3133. }
  3134. //-----------------------------------------------------------------------------
  3135. void* createW3DMemPool(const char *poolName, int allocationSize)
  3136. {
  3137. ++theLinkTester;
  3138. preMainInitMemoryManager();
  3139. MemoryPool* pool = TheMemoryPoolFactory->createMemoryPool(poolName, allocationSize, 0, 0);
  3140. DEBUG_ASSERTCRASH(pool && pool->getAllocationSize() == allocationSize, ("bad w3d pool"));
  3141. return pool;
  3142. }
  3143. //-----------------------------------------------------------------------------
  3144. void* allocateFromW3DMemPool(void* pool, int allocationSize)
  3145. {
  3146. DEBUG_ASSERTCRASH(pool, ("pool is null\n"));
  3147. DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName()));
  3148. return ((MemoryPool*)pool)->allocateBlock("allocateFromW3DMemPool");
  3149. }
  3150. //-----------------------------------------------------------------------------
  3151. void* allocateFromW3DMemPool(void* pool, int allocationSize, const char* msg, int unused)
  3152. {
  3153. DEBUG_ASSERTCRASH(pool, ("pool is null\n"));
  3154. DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName()));
  3155. return ((MemoryPool*)pool)->allocateBlock(msg);
  3156. }
  3157. //-----------------------------------------------------------------------------
  3158. void freeFromW3DMemPool(void* pool, void* p)
  3159. {
  3160. DEBUG_ASSERTCRASH(pool, ("pool is null\n"));
  3161. ((MemoryPool*)pool)->freeBlock(p);
  3162. }