[video output=day540 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Adding Memory Usage Visualization" vod_platform=youtube id=akkA5FrGfgU annotator=Miblo]
[0:03][Welcome to the stream][:speech]
[0:55][@kim_jorgensen][Q: There is a small compile error with Clang: "extra tokens at end of #endif" in handmade_import.cpp (#endif HANDMADE_INTERNAL). Could you fix this?]
[1:49][Remove HANDMADE_INTERNAL from the #endif]
[2:11][@kim_jorgensen][Q. Yes]
[2:37][Recap our new debug-ready Push*() functions and set the stage for the day using their file and line number information and tracking :memory][:"debug system" :speech]
[8:28][Embark on :memory tracking, introducing DEBUG_RECORD_ALLOCATION(), DEBUG_RECORD_BLOCK_FREE(), DEBUG_RECORD_BLOCK_TRUNCATE() and DEBUG_ARENA_NAME()][:"debug system" :memory]
[16:40][Introduce debug_arena_allocation, debug_arena_block and debug_arena as a mirror of the real :memory arenas][:"debug system"]
[20:55][Consider cleaning up our :"debug system" in a more purpose-built way][:speech]
[21:24][The importance of thread-awareness in a :"debug system"][:speech :threading]
[23:21][#define internal and non-internal versions of DEBUG_RECORD_ALLOCATION(), DEBUG_RECORD_BLOCK_FREE(), DEBUG_RECORD_BLOCK_TRUNCATE() and DEBUG_ARENA_NAME()][:"debug system" :memory]
[26:45][Implement our :memory DEBUG*() macros, recording operations into the debug events stream, from which the :"debug system" may pull them]
[41:53][Change the Push*() functions to get their __FILE__ and __LINE__ from a DEBUG_NAME(), noting the differing treatment of string concatenation by GCC and Visual Studio[ref
    site="Handmade Hero"
    page="Making the Debug System CLANG Compatible"
    url=https://guide.handmadehero.org/code/day356/#348]][:"debug system" :language :memory]
[44:56][Fix up macro-related compile errors, and remove DebugType_memory_arena_p][:"debug system" :language :memory]
[53:31][Set up CollateDebugRecords() to handle our new :memory debug types][:"debug system"]
[54:56][Find that the game continues to play fine][:"debug system" :memory :run]
[55:17][Introduce DEBUGArenaSetName(), DEBUGArenaBlockFree(), DEBUGArenaBlockTruncate() and DEBUGArenaAllocate() for CollateDebugRecords() to call][:"debug system" :memory]
[1:09:25][Implement DEBUGArenaBlockTruncate(), introducing DEBUGMoveToFreeList()][:"debug system" :memory]
[1:20:30][Implement DEBUGArenaAllocate() and introduce DEBUG_RECORD_BLOCK_ALLOCATION()][:"debug system" :memory]
[1:35:11][Fix up compile errors][:"debug system" :memory]
[1:39:54][Implement DEBUGGetArenaByPointer()][:"debug system" :memory]
[1:42:58][Hit our Block->MemoryAddress == UMMFromPointer(Op->Block) assertion in DEBUGArenaAllocate() and investigate why][:"debug system" :memory :run]
[1:45:45][Try out ~remedybg's value locking functionality][:admin]
[1:47:49][~remedybg feature request: Savable variable values][:admin]
[1:49:28][Continue to investigate our debug :memory arena assertion hit][:"debug system" :run]
[1:58:20][Realise that :memory arenas move around upon growing, and consider how to handle such moves][:"debug system" :speech]
[2:01:48][Tentatively introduce MoveArena() and DEBUG_MEMORY_MOVE_ARENA()][:"debug system" :memory]
[2:03:56][Enable the :"debug system" to handle :memory reallocations by respecifying DEBUGGetArenaByPointer() as DEBUGGetArenaByLookupBlock(), and augmenting the debug_memory_op with an ArenaLookupBlock]
[2:18:48][Fix compile errors][:"debug system" :memory]
[2:22:29][Introduce DEBUGRemoveArena()][:"debug system" :memory]
[2:26:05][Hit our assertion in DEBUGMoveToFreeList() and investigate why][:"debug system" :memory :run]
[2:27:37][Fix typo in DEBUGArenaAllocate()][:"debug system" :memory]
[2:27:54][Hit our Block->MemoryAddress == UMMFromPointer(Op->Block) assertion in DEBUGArenaAllocate() due to the arena containing no blocks][:"debug system" :memory :run]
[2:28:47][Disallow creation of :memory blocks by all functions except DEBUGArenaBlockAllocate()][:"debug system"]
[2:29:55][Hit our new AllowCreation assertion in DEBUGGetArenaByLookupBlock() and investigate why][:"debug system" :memory :run]
[2:41:27][Fix DEBUGGetArenaByLookupBlock() to correctly set the state of a reused arena][:"debug system" :memory]
[2:41:48][Find that the game may be leaking :memory][:"debug system" :run]
[2:42:56][Scour the code for our apparent :memory leak][:"debug system" :research]
[2:51:59][Realise that, since the :"debug system" uses :memory arenas, it's just recording its own arena allocations][:research]
[2:53:40][Prevent the :"debug system" from recording its own allocations, introducing DEBUG_ARENA_SUPPRESS()][:memory]
[3:01:57][Hit our AllowCreation assertion in DEBUGGetArenaByLookupBlock() and investigate why][:"debug system" :memory :run]
[3:03:07][Let the :"debug system" only track :memory blocks, just not its own suppressed allocations][:memory]
[3:04:31][Find that the game now has more stable :memory usage][:"debug system" :run]
[3:06:18][Add a :memory group in DEBUGInit()][:"debug system" :ui]
[3:11:32][Check out our blank :memory viewer][:"debug system" :run :ui]
[3:13:05][Set up the :UI to display our :memory arenas, frames and sizes][:"debug system"]
[3:22:32][Add a "Top Memory" list to the :UI, introducing DrawTopMemList()][:"debug system" :memory]
[3:36:05][Find that we display nothing][:"debug system" :memory :run :ui]
[3:36:21][Make DEBUGDrawElement() call DrawTopMemList()][:"debug system" :memory :ui]
[3:37:36][Hit our "Unrecognized format specifier" assertion from DrawTopMemList()][:"debug system" :memory :run :ui]
[3:38:09][Fix format string in DrawTopMemList()][:"debug system" :memory :ui]
[3:38:20][Check out our :memory sizes viewer][:"debug system" :memory :run :ui]
[3:40:32][Change DEBUG_ARENA_SUPPRESS() to take a Name][:"debug system" :memory]
[3:41:47][Check out our named :"debug system" arena in the :UI][:memory :run]
[3:42:14][Add a :memory occupancy viewer to the :UI, introducing DrawArenaInterval()][:"debug system"]
[4:00:43][Crash ~4coder after switching to the left-hand pane and typing something][:admin]
[4:01:45][Retype and continue to implement DrawArenaInterval()][:"debug system" :memory :ui]
[4:12:15][Fail to see our :memory arena visualisation][:"debug system" :memory :run :ui]
[4:13:45][Fix DrawArenaInterval() to increment the BlockIndex and draw the block rectangles][:"debug system" :memory :ui]
[4:14:59][See our block rectangle][:"debug system" :memory :run :ui]
[4:15:10][Briefly scour DrawArenaInterval() for bugs][:"debug system" :memory :research :ui]
[4:16:32][Step in to DrawArenaInterval() and inspect its values][:"debug system" :memory :run :ui]
[4:19:24][Prevent DrawArenaInterval() from drawing suppressed blocks, and make it offset the BlockRect by the ProfileRect][:"debug system" :memory :ui]
[4:20:10][Find that we're properly sizing the block rectangle, but not moving it along][:"debug system" :memory :run :ui]
[4:21:01][Make DrawArenaInterval() apply an outline to the BlockRect][:"debug system" :memory :ui]
[4:22:39][Check out our two, outlined block rects, and step through DrawArenaInterval()][:"debug system" :memory :run :ui]
[4:24:08][Make DrawArenaInterval() compute the correct dimensions of the RegionRect][:"debug system" :geometry :memory :ui]
[4:26:19][Continue to step through DrawArenaInterval() to see that we Suppress :memory allocations for the Game Mode][:"debug system" :run :ui]
[4:27:48][Make DEBUG_ARENA_NAME() set the AllocatedSize to 0][:"debug system" :memory :ui]
[4:28:02][Check out our :memory Arenas viewer][:"debug system" :run :ui]
[4:29:52][Comment out the ground_cover from the entity struct][:"entity system"]
[4:30:33][Check out our :memory Arenas viewer, absent the ground_cover][:"debug system" :run :ui]
[4:31:00][Uncomment the ground_cover in the entity struct][:"entity system"]
[4:31:06][Check out our :memory Arenas viewer, including the ground_cover][:"debug system" :run :ui]
[4:32:15][Q&A][:speech]
[4:32:58][@thepr1ms][Q: Not on-topic at all but could you just say hi to my friend Thomas Grim who is a fervent follower of yours?]
[4:33:54][Close it down][:speech]
[/video]
