3 ms·
> 4% performance improvement for up to 800 threads. 800 threads on similar WaitForMultipleObject is already a horrific design if you even remotely care about p
by xxs 6y ago
> 4% performance improvement for up to 800 threads.
800 threads on similar WaitForMultipleObject is already a horrific design if you even remotely care about performance.
The only viable case for 800 threads (and wine) would be blocking IO which is an extremely boring one.
- usefulcat 6y agoSure, but that's irrelevant for wine, which doesn't get to choose how the things that it's running (e.g. games) are implemented.
- xxs 6y agoOf course. Yet, I am be massively surprised to see so heavily multithreaded games with massive contention on WaitForMultipleObjects. No one programs that way (again, save for blocking IO... and then it totally doesn't matter)
- monocasa 6y agoUnfortunately, people do program that way, and I've seen it way more in closed source Windows code than in the open source world where someone will (rightly) call them out. For instance, in a previous job, a C++ codebase existed where the architect had horrendously misunderstood the actor model and had instated a "all classes must extend company::Thread" rule in the coding standard. So close, yet so incredibly far away. At the end of the day, wine (like windows) still has to run these programs and do it's best with terrible choices that were made in the past.
- xxs 6y agoHaving a policy to have to extend something is proper bad already. For actors likely you need lock-free queue and much preferably a bounded one - so each message is a CAS (very likely uncontended) and there is an upper limit how much stuff can be enqueued. I do believe there are tons of incredible horrid code (esp. when it comes to concurrency) - but most games tend to use already established engines, less likely to have glaring concurrency design blunders.
- monocasa 6y agoI mean, yeah, you don't make a choice like that without making a lot of other terrible choices too. Like I said "horrendously misunderstood the actor model". And as you seem to be picking up on, they had a very C++98 view at best of how inheritance should work. In case it's not clear to anyone reading along: if you find yourself doing anything like this, take a long, deep look in the mirror; you're almost certainly making the wrong choice. Best I can say is that the architect learned from some of their choices in the years since from the resulting consequences. However, that code is still out there. The engineers have tried to rewrite since then, but it turns out that rewriting isn't adding new features. I don't agree with the company's calculus on the matter, but that's a tale as old as time. And you'd be surprised how many games aren't written well. Writing a game engine is a bit of a rite of passage among young coders, and a surprising subset of those actually ship. In my experience, a lack of maturity in the field and (we'll be courteous and say) 'questionable' threading models (and as you point out inheritance models too) go hand in hand. The point at the end of the day is that Wine users (like Windows users) expect the runtime to do the best it can even against terribly written applications. The users want to run that code, it isn't going to be fixed, so anything Wine can do better to paper over the (incredibly obvious to someone skilled in the art) deficiencies of that code is in their users' benefit.
- girvo 6y agoI wouldn’t be so certain with regards to game engine code quality. Game dev is about producing playable art; code “quality” isn’t a massive focus. In this particular example you’re probably right though, because performance does matter to game dev, and that would be a horrific architecture perf wise
- Matthias247 6y agoIt kind of makes sense for waiting on a single object, if the program uses it as a replacement for a condition variable. E.g. multiple threads could wait on a shared work queue, and wait on an object to get signaled when work is available. Now ideally just one thread should be woken, but with a bit of imagination and naive coding its easy to imagine someone wakes up a lot of worker threads which then just go to sleep again.
- asveikau 6y agoIIRC, WaitForMultipleObjects can only block on 63 handles. 800 threads blocked on 63 handles seems pretty weird.
- xxs 6y ago>IIRC, WaitForMultipleObjects can only block on 63 handles Yup (64 though), it's an extra annoying limitation. It has been there since the 90s, WinNT (cant recall win95 version as I never used it with win95). It's limited by MAXIMUM_WAIT_OBJECTS which is 64. For instance Java implements non-blocking IO (java.nio.Selector) by using multiple threads and sync between them to effectively achieve linux' epoll. ---- my point was mostly that the 'huge' 4% happens with massive amounts of threads and WaitForMultipleObjects won't see even that... so kind of click-baity. Flip note: sync. between threads can be done better than relying on OS primitives aside for real wait/notify stuff (which indeed it's implemented via futex)
- userbinator 6y agoLinux has a similar limitation with FD_SETSIZE and select() --- which I believe comes from the implementation using an array index operation instead of a more complex data structure due to performance reasons.
- throwaway2037 6y agoI'm confused by this comment. It appears to imply that FD_SETSIZE is also very small (63?) on Linux. To be clear: I am no an expert on Linux kernal params, nor select() and its friends. However, recent Linux kernels appears to have FD_SETSIZE about 1024. Red Hat says: <<FD_SETSIZE is hardcoded to 1024 in /usr/include/bits/typesizes.h and can not be changed.>> Source: https://access.redhat.com/solutions/488623 https://access.redhat.com/solutions/488623 If I misunderstand, please let me know.
- userbinator 6y agoI wasn't implying it's also small, but that it's a fixed value too.