I'm bringing my PS4 Handmade Hero port up to speed with the last few weeks' changes, and ran into a problem where none of the bitmaps were loading at runtime. I traced it to a consequence of the busy-wait added on Days 166-167 in LoadBitmap(). Quick recap: if two or more worker threads try to simultaneously load the same bitmap with Immediate=1, only one thread actually loads the bitmap; the others busy-wait until Asset->State is no longer AssetState_Queued.
What seems to be happening in my case is that the thread that's actually loading the asset from disk is continuously preempted by the other threads, all of which are just busy-waiting for the first thread to finish. It's kind of like priority inversion, except that all the threads in each queue have the same priority.
Anyway, this is most likely a problem with the OS's thread scheduler, which I'll be mentioning to our kernel team. For Handmade Hero purposes, though, I was able to work around the problem by inserting an intrinsic (our equivalent of
__yield or _mm_pause) inside the busy-wait loop, which forces a context switch to another thread of equal or lower priority. It's still not a perfect solution -- two __yield()ing threads could potentially ping-pong back and forth while a third thread starves. But it's better than nothing.
Casey: would you consider adding something like a portable yield() equivalent to the official code? I know you never claimed the multi-threaded asset loading system was anything more than "probably theoretically working" and would need further testing down the line, but this would certainly help in the meantime. Besides, busy-waiting isn't a great idea in general, for
a variety of compelling reasons.
Thanks!
- cort