Dynarec before run-time?


ozzyfreakdude

Still Fresh
Joined
Feb 14, 2011
Messages
92
This is a purely conceptual question, as I have no experience coding emulators.


The way I understand it, most emulators use either pure interpretation (in which the entire inner workings, system calls, etc of the system being emulated are directly translated) or dynamic recompilation.


From what I gather, dynamic recompilation (dynarec) is where some/all of the code for the system being emulated is recompiled on the fly from code the native processor architecture (say for the N64/PSX) to code for the architecture of the system emulating it (x86, ARM, etc...), which produces a speed boost. From what I gather, the recompilation on the fly seems like it would take a substantial amount of CPU cycles. But if, even after those CPU cycles are used to recompile, a performance boost still occurs, then that just means that the recompiled code is just that much faster.


Here's what I'm proposing: Provided that my understanding of the recompilation is correct (which it may not be), it seems like one would be able to recompile the code BEFORE launching it, IE, not at runtime. Say, in the case of Mupen (where speed boost is a major issue), you could feed the rom file to the emulator, it could compile it all at once to a rom file which has been recompiled for the ARM architecture (which could then be saved on the SD card for future use), and then that already-recompiled rom could be run directly, thus saving the cpu time spent recompiling the rom. If this was possible, it would theoretically result in a large performance boost.


Like I said, I have no experience coding emulators (or even coding at all in anything other than Java or VB.net), so I don't know if that's even possible. But the inquisitive computer scientist (about to graduate with bachelors in 2 weeks) in me has to at least wonder.
 
The code is recompiled to ARM before running.


Yet, sometime code is dynamicly generated, thus the dynarec have to recompile the code that change and does that on the fly.


having the ARM code stored will give you some milliseconds boost at startup, that's it, that's all.
 
It's a great idea, but insanely difficult to do in practice - see the "Halting Problem" for a more complete reasoning.


D.
 
Recompiled code is translated once and executed many times. Asymptotically the amount of time spent in recompilation goes to zero as your playtime increases, so long as the code isn't modified or you don't run out of cache and it has to be flushed. The typical impact is somewhere in between startup time and intermittent load times, only usually more fine grained and distributed than that.


Recompilers in emulators don't have to perform most of the optimizations a high level language compiler does, so they don't necessarily take that long. Often it can be faster to recompile the code than load it off disk.


On the other hand, if the emulator somehow collects profiling data from somewhere that can be useful to store on disk (in order to recompile better).
 
Last edited by a moderator:
oh okay then, it sounds like my understanding of dynarec was a bit off, so what I was suggesting was based on an incorrect assumption.


Thanks for the input though
 
Translation before-running is generally called static recompilation; ie: dynarec and statrec are two sides of the coin.


It really depends on if the code is self modifying or on other many parts of the puzzle.. there are a number of static translations around in use on our various devices :)


jeff
 
one instance where static recomp's was used with the x86 dos apps by M_HT portions of the game code was converted and SDL code was used to tie them into the system, point being even if you can recompile something you still may need to supply current system compatible bits.
 
Recompiled code is translated once and executed many times. Asymptotically the amount of time spent in recompilation goes to zero as your playtime increases, so long as the code isn't modified or you don't run out of cache and it has to be flushed.
For N64 and PSX, it's going to be modified, or at least have different code loaded for different parts of the game. Some emulators handle this better than others.

On the other hand, if the emulator somehow collects profiling data from somewhere that can be useful to store on disk (in order to recompile better).
Or you could save the recompiled code. It tends to be kinda large though.
 
For N64 and PSX, it's going to be modified, or at least have different code loaded for different parts of the game. Some emulators handle this better than others.

Still asymptotically zero, this doesn't really scale with how long you play. Like I said, it's more like load times than a constant performance hit, and in the case of loading code from CD-ROM that'll dwarf the recompilation cost, especially if you're trying to emulate the PS1 CD-ROM speed at all.


And if code is either dynamically loaded or modified you can't compile it ahead of time anyway. Or at least, you'd have to match checksums of it to see if the thing you want is on disk.

Or you could save the recompiled code. It tends to be kinda large though.

I already addressed this. For a lot of recompilers it's faster to recompile again than to load it. Feel free to show some benchmarks to indicate this being an advantage, though.


Static recompilation isn't attractive because you save recompilation time, it's attractive because of increased opportunity for expensive and whole program style optimizations.. or at least that's what people think, it's again something I haven't seen a lot of evidence of (not least of all because I'm not aware of a fully automatic general purpose static recompiler that works on a large amount of software)
 
Last edited by a moderator:
For a lot of recompilers it's faster to recompile again than to load it. Feel free to show some benchmarks to indicate this being an advantage, though.

I would be willing to bet that any case where it is faster to load the information needed, the small gain in speed would still not be worth the amount of disk space needed for the compiled data.
 
Last edited by a moderator:
Exo -- no, you are correct regarding uses of static recomp --


1) Where the recompilation is 'hard' or expensive


2) Where you can do post-translation optimization .. ie: HLE or whatever.


I've done both for simpler ancient machines (68000, 6502 and Cinematronics type machines) - mostly for (2) where I wanted to translate _game code_ without worrying about _platform code_ -- translate it, yank out the entire display system and put in SDL or whatever. New input/output/timing code (disk I/O, change modem ports to use telnet, that sort of crazy stuff.) -- One project of mine was to staticly recompile old BBS games to run on telnet, with simulates BBS 'door' environment.


(In the end, due to volume of applications, it was 'more efficient' to just write a machine emulator and map the hardware to telnet ports, which is what I did .. but I did write a basic 68000 game translator, and later, a decompiler/interpreter for some odl dialects of BASIOC.. nasty ;)


Another case for (1) was .. sometimes your platform is plenty fast enough to run native code, but too slow/limited to run a dynarec; we were writign static recompielrs for games, to run on the old Palm devices (talking like 20mhz, even 100mhz..) -- dynarec seemed out of reach when you didn't even have more than a 4/8/16k stack to work with without a lot of trickery :)


--


Nowadays, static recomp is purely for (2) -- for wholesale optimization.


jeff
 
Interesting post skeezix.


Static recompilation is a useful technique for porting, but there's a world of difference between it as an approach applied to a specific game and an attempt to make it automated over some large set of software. The latter doesn't really work, and isn't really any more conducive to HLE-style optimizations than dynarec is.


If I were porting a specific game w/o source, like for a commercial project or something, my approach would probably be to write a traditional emulator (possibly interpretive), add support for hooks to native routines, profile it, and start replacing the hottest pieces of code with native routines until it's fast enough. I wouldn't be surprised at all if approaches like this were taken in the past. It has the same sort of flavor as what you're describing, but hopefully less overall work, and it's a lot easier to reverse engineer something as it's running than from raw disassemblies.
 
Still asymptotically zero, this doesn't really scale with how long you play. Like I said, it's more like load times than a constant performance hit, and in the case of loading code from CD-ROM that'll dwarf the recompilation cost, especially if you're trying to emulate the PS1 CD-ROM speed at all.
True for some games, though Majora's Mask is a counterexample. The code for the various events in clock town is rather large and complex. It's constantly running new code. With a large enough cache you can get most of it, but it requires a very large cache and playing through at least one day/night cycle.

And if code is either dynamically loaded or modified you can't compile it ahead of time anyway. Or at least, you'd have to match checksums of it to see if the thing you want is on disk.
You have to check for a match anyway to detect modifications. By the way, I used an exact match rather than checksums. It will stop comparing if the first few bytes don't match (the usual case for a non-match).

I already addressed this. For a lot of recompilers it's faster to recompile again than to load it. Feel free to show some benchmarks to indicate this being an advantage, though.
It's possible to load things from disk at >10MB/sec. A fast compiler can possibly beat this, but I doubt it's a huge advantage. I'm assuming that you would load this cache from disk at startup. I was thinking of something like loading a save state, where you load the recompiler state too.

I would be willing to bet that any case where it is faster to load the information needed, the small gain in speed would still not be worth the amount of disk space needed for the compiled data.
I'd agree, I was just noting that it's possible to do it.
 
True for some games, though Majora's Mask is a counterexample. The code for the various events in clock town is rather large and complex. It's constantly running new code. With a large enough cache you can get most of it, but it requires a very large cache and playing through at least one day/night cycle.

Unless it's generating code it's STILL asymptotically zero. It doesn't matter if it keeps encountering new code, those functions are only going to be so large. In the end you're loading a finite amount of code over an infinite amount of time, and if you're even on the crazy end of the load in the millions of instructions you'll still have a recompiler that's probably linear time against instructions and all the instructions will eventually be loaded.


The real thing limiting recompilation cache size is the range of branches on ARM.. on other platforms you don't necessarily have that problem and can have bigger translation caches, so that there's no way a 32MB game will exhaust it. Of course, this also depends on how optimized for size the output is..
 
Unless it's generating code it's STILL asymptotically zero. It doesn't matter if it keeps encountering new code, those functions are only going to be so large. In the end you're loading a finite amount of code over an infinite amount of time, and if you're even on the crazy end of the load in the millions of instructions you'll still have a recompiler that's probably linear time against instructions and all the instructions will eventually be loaded.


The real thing limiting recompilation cache size is the range of branches on ARM.. on other platforms you don't necessarily have that problem and can have bigger translation caches, so that there's no way a 32MB game will exhaust it. Of course, this also depends on how optimized for size the output is..
Majora's Mask definitely hits the 32MB limit. Recompiling 64-bit MIPS code to a 32-bit instruction set results in output that's not all that well optimized for size.


PowerPC has the same 32MB limit. MIPS can do 256MB jumps. The only platform where this isn't an issue is x86.
 
i have no idea what you are all talking about. but you all sound like geniuses to me!

I'll talk only about Ari64 and Exophase because they are the one I know the best
laugh.gif



They ARE geniuses! They made miracles happen on the Pandora!


And of course he's a genius, he is fucking Exophase!
biggrin.gif
 
Back
Top