[video output=day351 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Optimizing Multithreaded Simulation Regions" vod_platform=youtube id=6mTkcOlaUUc annotator=Miblo]
[0:35][A few words on the new format]
[1:41][Recap and set the stage for the day]
[2:43][Run the game, consult the profiler and assess our current situation]
[9:32][handmade_entity.cpp: Stop profiling the entity system, run the game and consult the event count]
[11:48][handmade_world.cpp: Stop profiling GetWorldChunkInternal(), run the game and consult the profiler]
[13:22][handmade_world_mode.cpp: Make PlayWorld() set the WorldChunkDimInMeters larger, run the game and consider drawing the bounds of those chunks]
[16:46][handmade_world.cpp: Introduce GetWorldChunkBounds()]
[21:25][handmade_world_mode.cpp: Make UpdateAndRenderWorld() call GetWorldChunkBounds() and draw them]
[23:22][Run the game and view that debug visualisation for the chunk]
[26:52][handmade_world_mode.cpp: Make PlayWorld() set the chunk size roughly equal to the room size, run the game and view the visualisation]
[29:31][handmade_sim_region.cpp: Change BeginWorldChange() to only simulate one room's worth]
[31:20][Run the game and note how our simulation region erroneously splits entities]
[32:29][handmade_world_mode.cpp: Make UpdateAndRenderWorld() operate on the eight rooms above, below and around the player]
[36:33][Run the game to take a look at how that's working]
[38:46][handmade_platform.h: Add BeginTicketMutex() to the profiler, run the game to consult the profiler and consider how to improve the multithreading]
[42:11][handmade_sim_region.cpp: Enable BeginWorldChange() to do a bunch of work without needing to be in a mutex]
[46:17][handmade_world.cpp: Enable AddToFreeList() to insert the whole list in one go]
[48:05][Run the game and consult the profiler]
[50:27][handmade_world.cpp: Make RemoveWorldChunk() and AddToFreeList() themselves begin and end the mutex]
[52:54][handmade_world.cpp: Consider what UseChunkSpace() does, make it begin and end a mutex, run the game and consult the profiler]
[56:22][handmade_sim_region.cpp: Consider how to improve the ticket-taking in BeginWorldChange()]
[59:38][Run the game and consult the profiler until we hit a deadlock and investigate why]
[1:02:43][handmade_world.cpp: Make the correct version of UseChunkSpace() begin and end a mutex, run the game and consult the profiler again]
[1:04:40][handmade_world.cpp: Add RemoveWorldChunk() and AddToFreeList() to the profiler, run the game and consult it]
[1:06:00][handmade_sim_region.cpp: Add more timing blocks and functions to the profiler, running the game and consulting that profiler]
[1:10:04][handmade_sim_region.cpp: Establish that the PushStruct() call in BeginWorldChange() is taking half our time]
[1:10:37][Note that the timer totally failed]
[1:11:09][handmade_memory.h: Investigate why that PushStruct() is so expensive]
[1:13:11][handmade_sim_region.cpp: Add a timing block around that PushStruct() call in BeginWorldChange(), run the game and inspect the profiler]
[1:14:11][Consider why we are clearing this buffer]
[1:16:20][Break]
[1:21:35][Return and wonder if the chat figured out what's wrong with the code]
[1:23:30][handmade_sim_region.cpp: Make BeginWorldChange() pass NoClear to that PushStruct() call and run the game to consult the profiler]
[1:25:11][handmade_sim_region.cpp: Time the ZeroStruct() call, run the game to consult the profiler and consider how to optimise this routine]
[1:28:27][handmade_debug_ui.cpp: Enable DrawTopClocksList() to print out the cycles per invocation]
[1:29:58][handmade_math.h: Introduce a 64-bit version of SafeRatio0()]
[1:30:24][Run the game and consult the profiler]
[1:31:12][Break into the ZeroStruct() call in BeginWorldChange() and determine that the clear is costing 7 cycles per byte]
[1:33:55][handmade_sim_region.cpp: Verify that the clear's cycle-time is reasonable]
[1:37:21][Consider ways to minimise the memory footprint]
[1:40:55][handmade_sim_region.h: Add EntityHashOccupancy and BrainHashOccupancy to the sim_region struct in order to enable doing the clear with a bitfield]
[1:44:03][handmade_sim_region.cpp: Introduce MarkOccupied(), MarkBit() and IsEmpty()]
[1:49:03][Run the game, hit the assert in AddEntityToHash(), and fix that assertion to handle the new scheme]
[1:51:12][handmade_sim_region.cpp: Fix the sense of IsEmpty(), run the game and crash in ExecuteBrain()]
[1:52:02][Build and run in -Od and investigate what's happening]
[1:54:18][handmade_sim_region.cpp: Add an assert in AddEntityToHash() to validate the hash, run the game and do not hit that assertion]
[1:55:07][Step through AddEntityToHash() and investigate what's happening]
[1:56:30][handmade_sim_region.cpp: Walk through GetOrAddBrain()]
[1:57:38][handmade_sim_region.cpp: Make GetOrAddBrain() set the Hash->ID, run the game and crash in FreeFrame()]
[1:58:31][handmade_sim_region.h: Remove the ID from the entity_hash and brain_hash and instead use their Ptr to identify them]
[1:59:36][Run the game and note that "our brains are still not working properly"][quote 535]
[2:03:55][handmade_sim_region.cpp: Add assertions to GetOrAddBrain() in order to verify ID resolution]
[2:06:51][handmade_sim_region.cpp: Make BeginWorldChange() and GetOrAddBrain() clear the Brains, run the game and note that we're still getting weird behaviour]
[2:08:06][handmade_memory.h: Enable overflow checking in PushSize_(), run the game and...]
[2:08:41]["So we don't seem to be having any overflow problems at the moment... *stream crashes*"][quote 536]
[2:09:43][Wait for Windows to decide to suspend the process]
[2:13:23][Run the game normally having removed that overflow checking, and watch the memory counter]
[2:14:30][handmade_sim_region.cpp: Make BeginWorldChange() clear the SimRegion, run the game and watch the profiler]
[2:15:40][handmade_sim_region.cpp: Temporarily make BeginWorldChange() clear the EntityHash and BrainHash, run the game and watch the profiler]
[2:17:39][handmade_sim_region.cpp: Make GetHashFromID() clear upon encountering an empty Entry for now]
[2:18:42][Run the game successfully and consult the profiler]
[2:19:52][Q&A][:speech]
[2:20:17][@AsafGartner][The stream is down]
[2:22:51][@AsafGartner][Did you fix the bug?]
[2:23:45][@AsafGartner][There's a TODO in ZeroSize. Not sure if you noticed it]
[2:24:07][handmade_memory.h: Remove the TODO from ZeroSize()]
[2:24:23][@uplinkcoder][What was the bug?]
[2:25:26][@longboolean][We should have something built into the build script that won't let you compile if the stream has gone down. Is this possible to do in a batch script?]
[2:27:17][Update the TODO list]
[2:28:01][@mtsmox][Is it an option to never clear to zero for arenas, and maybe only clear when resetting temporary memory?]
[2:30:30][ctray.cpp: Investigate why the overlay disappeared]
[2:33:17][@AsafGartner][Is there a still a benefit to using the sim region? Since chunks are room-sized, and simulation is room-based, why not use the chunks directly?]
[2:35:52][Wrap it up][:speech]
[2:36:33][Anticipate HandmadeCon 2016][:speech]
[/video]
