GameMemory.cpp 109 KB

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