Live data from Hacker News

The time the x86 emulator team found code so bad they fixed it during emulation

devblogs.microsoft.com

161–170 of 179 posts

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#161

256 KB of code to zero 64 KB of memory is the kind of optimization that makes you question every life choice that led to it.

I blame Intel. It took them 33 years (ERMSB) to finally standardize REP MOVSB as _the_ fast path. Another 10 years passed and someone discovered https://lock.cmpxchg8b.com/reptar.html

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#162

Earlier quoted context omitted.

There are many, many, cases like this, including correctness fixes. One recent example I remember had a shader that computed: x = a / b * b The optimizer was allowed, but not obligated, to transform that into: x = a However, in this case, b was sometimes 0. And if so, the unoptimized version computed: x = a / 0 * 0 = Inf * 0 = NaN So badness ensued if the that particular path didn't get optimized, which could happen…

I'm curious, what's the ratio of: - deciding to inform the game developer & wait for reply vs not waiting for reply vs just fixing it yourself without informing the developer; and - if informed: developer actually fixing it vs only saying they would fix it vs no reply whatsoever (not counting automated "thank you for your inquiry" replies, in cases where you don't already have more direct channels to the dev than ema…

We always try to inform game devs about correctness issues, but generally we can push out a driver fix before the devs can fix things on their side, so that pretty much always happens. Many things can be fixed quickly by app profile (detecting executable name). And we have a pretty good relationship with most game devs and usually get some feedback. Of course, we don't have infinite resources, so bigger game devs get more attention to tiny ones.

I'm not sure what fraction of devs actually fix things on their side, though. Once there's a driver workaround, and we've informed the devs, it's off our plate.

Performance is more of a gray area. We contact devs if there's something we can't work around, of course. And if there's something truly breaking. But for things that aren't exactly bugs, just things that could be improved, and we can improve on our own... well, we'll probably keep that for the competitive advantage.

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#163
post #55

Earlier quoted context omitted.

I've seen a lot of code that just assumes fread / fwrite succeeded without bothering to check the return value... But in this case if the code was calling fread 65536 times in a loop and getting 64KiB each time it wouldn't be good either! Sounds like the parent comment had to fix this with the internal cache thing to speed up the small freads. I think they meant the easy fix would have been swapping the args in the o…

There are no small freads in the story, whatever implements those freads supposedly split them up into many calls. But that sound more like a problem of that implementation than the fread callers as size == 1 is correct when you are reading a bag of bytes.

Ah you're right, I misread it.

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#164
post #159
post #26

Earlier quoted context omitted.

I used to be a graphics card/chip architect for macs in the early/mid 90s - our chips were the fastest, but some programs were resistant because they did stupid stuff: pagemaker invalidated the font cache every time it went thru its main loop, quark with ATM did an n*2 thing every time it wrote text etc etc. We had special hardware to accelerate text drawing and it did nothing because the software pissed it away. We…

In my 68K Mac emulator running on modern (or even decade-old) hardware, performance in the traditional sense is less of a concern, but other issues arise. The big ones include CPU-burning loops that wait for a length of time or for an interrupt-decremented counter to reach zero, as well as invalid memory accesses (which I've made crash — no NULL deref for you). > We considered creating a plugin that fixed all these t…

Yeah those low core global system variables (including a readable/writeable 0) at fixed addresses were very much a thing, they were a bad design decision made for the original Macs with almost no memory, and made running more than one app (switcher/multifinder) a difficult transition back in the day. Someone wasn't planning ahead

I also worked on the original A/UX port for the Mac II, some hardware (like the IWM) required tiny buzzy loops, we ran into one bug where using the floppy caused ADB to freeze, but only on the release machines, not the prototypes all our engineers had, turned out there was hardware that made access to the VIA faster by pulling the clock in for 1 cycle, if you sat in a loop reading the timer in the via to measure a sector time for the IWM in too tight a loop it upped the output clock from the VIA to the ADB chip and over clocked it ....

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#165
post #160

Earlier quoted context omitted.

Its slowness is also a function of security software or any other file system "filters" (I believe they're called) are installed. For example, I run TortoiseGit which has a caching feature which is supposed to make it faster at showing what to commit. Disabling it increases the number of items I can delete per second in my Windows Explorer from about 1000 to about 3000 while making not making TortoiseGit operations m…

>slowness is also a function of security software or any other file system "filters" nah, its equally slow on system with everything ripped out (defender, filters, even logging).

Your dismissive tone implies you think I’m lying or something about my stated (and reproduceable) experience that deletions absolutely run a 1/3rd slower with certain software installed.

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#166
post #122

Earlier quoted context omitted.

This is a horrible and yet not unexpected insight into the internals of Excel

There's a good chance it was Excel's workaround for some other GPU's buggy behavior.

there were no GPUs at that time. What we were building in the late 80s/early 90s were the first generation of Mac graphics accelerators, really just glorified blit engines, a class of things that eventually grew into what we now call GPUs as people started to push CPUs into them

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#168

Earlier quoted context omitted.

Is this why Windows takes so long to delete things?? Presumably those reads aren't done when using del from a console as that always seems a bit faster.

Its slowness is also a function of security software or any other file system "filters" (I believe they're called) are installed. For example, I run TortoiseGit which has a caching feature which is supposed to make it faster at showing what to commit. Disabling it increases the number of items I can delete per second in my Windows Explorer from about 1000 to about 3000 while making not making TortoiseGit operations m…

`rmdir /s /q` in a command prompt is significantly faster than Windows Explorer.

Yes C: is slow due to filters and Dev Drive is faster; but this difference can only be felt when using the command line; Windows Explorer has so much additional overhead that the overhead from file filters is insignificant in comparison.

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#169
post #124
post #54

Earlier quoted context omitted.

> Which basically expanded back in the day to 65k reads of 1 byte for several MB file. Each fread translated to 65k reads of ReadFile Windows API What software did that that badly? If the code asks for (up to) 65,536 single byte items, why would you split that into 65,536 calls? Also, that change changes behavior. The old call could read anything from zero to 65,536 bytes, the new one only can read zero or 65,536 byt…

The standard says that fread calls fgetc multiple times for each object: > For each object, size calls are made to the fgetc function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object (wording unchanged since C99) If the file is unbuffered, depending on how the implementation handles buffering, and how it interprets the standard, then perhaps it does end up hitting…

> The standard says that fread calls fgetc multiple times for each object:

>> For each object, size calls are made to the fgetc function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object

Aha! That phrase led me to https://man7.org/linux/man-pages/man3/fread.3p.html. I consulted https://man7.org/linux/man-pages/man3/fread.3.html and https://man.openbsd.org/fread.3. Neither mentions that.

Now, I checked https://cplusplus.com/reference/cstdio/fread/. It doesn’t mention it, either.

⇒ this appears to be POSIX-specific.

Finally, if somebody implements fread as “For each object, size calls are made to the fgetc function”, it doesn’t matter whether you ask for 1 object of size 65,536 or 65,536 objects of size 1; both would call fgetc 65,536 times.

Re: The time the x86 emulator team found code so bad they fixed it during emulation

#170
post #124

Earlier quoted context omitted.

The standard says that fread calls fgetc multiple times for each object: > For each object, size calls are made to the fgetc function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object (wording unchanged since C99) If the file is unbuffered, depending on how the implementation handles buffering, and how it interprets the standard, then perhaps it does end up hitting…

> The standard says that fread calls fgetc multiple times for each object: >> For each object, size calls are made to the fgetc function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object Aha! That phrase led me to https://man7.org/linux/man-pages/man3/fread.3p.html . I consulted https://man7.org/linux/man-pages/man3/fread.3.html and https://man.openbsd.org/fread.3 .…

Shouldn't you be using cppreference.com instead of cplusplus.com? Because the former [0] actually has this language:

    Reads up to "count" objects into the array "buffer" from the given input stream "stream"
    as if by calling fgetc "size" times for each object, and storing the results, in the order
    obtained, into the successive positions of buffer, which is reinterpreted as an array of
    "unsigned char".
This whole fread/fwrite's interface is hailing from the time where some OSes used record-based filesystems and were literally unable to read/write less than a record at a time.

[0] https://en.cppreference.com/c/io/fread

Post reply on HN