This project is dedicated to the memory of William Morris (aka Frags), who was the main contributor to the bounty but was unable to see the final result.

Showing posts with label x86. Show all posts
Showing posts with label x86. Show all posts

Thursday, August 30, 2012

Optimize It

I am back from the holidays for sometime now, but I got swamped instantly by the work in my daytime job. I had very little energy on the project in the nights, which was spent on two things: chasing that #@!% bug which is killing me and implementing the data-flow optimization.

Needless to say that I failed to track down the bug again, just like every time I spent hours on looking at couple megabytes of log dumps. Next time I will try a new approach, suggested by Stephen Fellner: reducing the code complexity while the bug can be reproduced.
We will see how it goes. The processor cache emulation is certainly complicates things, that can be eliminated at least.

While I acknowledged the failure again, I gathered all my previous thoughts and implemented the data-flow based optimization which does a really nice job.

The update is small, but highly important again:
  • Implementation of code optimization.
  • New configuration was introduced: comp_optimize to turn it on/off.
  • Bugs in the register input/output flag specifications are fixed.
  • Fixed too small string buffer in the 68k disassembler, previously the debugger crashed every time when memory was disassembled to the screen.
  • Implementation of MOVEM.x regs,-(Ay)

What, how and why?

As I tried to explain earlier in this post some of the compiled code is completely useless. The emulated instruction consists of the following parts usually:
  • Initialization of certain temporary registers;
  • Executing the actual operation;
  • Alter the arithmetic flags according to the result;
  • Save the result somewhere (into memory)
Some of these operations are not common or can be done for a series of instructions ahead, like loading the previous data for the emulated registers into temporary registers, but there are parts that cannot be avoided if we examine the emulated instruction out of its context.

For example the arithmetic flags are overwritten quite often by the following instructions, what means: if the next instruction(s) are not depending directly on the flag results then we can remove the code that generates these.

Typically, if we (as mighty humans) look at the instructions in a block we can easily identify the context, we can tell mostly which instructions produce usable results and what is not important. Like in most of the cases simple for a human, but it is a really complex job for the code compiler.

As I previously described: the emulated code is broken up into macroblocks by the precompiling. These blocks represent an "atomic" operation, like load data into temporary register, compare two registers or calculate certain arithmetic flags from the previous result.
When I started working on this concept I figured out that if I would be able to identify exactly for each macroblocks the previous result(s) that it is depending on and the result(s) that it produces then I can evaluate the dependencies between the subsequent macroblocks.

Going with the flow

For Petunia I already implemented a similar concept, but that was limited to the flag usage and it is not able to split up the emulation of the arithmetic flags into individual flag registers: it is either emulated completely or removed completely. (Which means that even if we needed only the C register later the rarely used X register will be calculated too, usually after the C register was already done. If you don't understand the reason behind this: don't worry - you need to know more about 68k assembly.)

For E-UAE the implementation is radically different. For any macroblock there is the possibility of specifying each and every emulated register, flag or temporary register as dependecy (input) and/or as result (output).

In the recent changes I implemented the rather simple solution for calculating the data-flow for each registers after all macroblocks are collected for a block of instructions.

It is capable of finding out for each macroblock whether the produced results are relevant for the following instructions in the block or not. If not then that macroblock can be eliminated from the compiled code because no instruction is depending on its results.

 

How to use it

Although, the optimization is completely safe (it won't remove any code that is essential) while the emulation is not stable enough there might be some bugs. So, I introduced a new configuration for turning it on/off, called: comp_optimize.
It replaces the comp_nf configuration from the x86 JIT implementation, because it is not just about the flags (nf = no flags).

If it was set to true then the data-flow calculation is done and some macroblocks will be removed. By setting it to false the emulation compiles all the instructions fully into the buffer.

 

The results

And finally some speed tests... Compared to the previously published Mandelbrot test results the actual numbers are:

Interpretive: 108 seconds;
JIT compiled without optimization: 52 seconds;
JIT compiled with optimization: 32 seconds.

That is roughly 40% speed increase in the case of this (heavily arithmetic) test.

The test system was: Micro AmigaOne (G3/800 MHz) - let's compare it to WinUAE that is running on my laptop (Intel Core i3 M350/2.27 GHz):

JIT compiled with all the possible optimizations turned on: 9 seconds.

It would be a tough job to compare these two computers, but I am pretty sure that my laptop is more than 3.5x faster than that poor old G3 machine.

I am really content with these results for now.

Tuesday, May 1, 2012

Deep-diving into memory

Since I just bought a new SSD and I am about to reinstall my laptop, it is time to do another update on the project: another batch is uploaded to the SourceForge repository. (I hope I won’t lose the sources… ;)

So, what was made into this update? A quick list about what happened in the last two weeks:

  • Direct memory writing support
  • Detecting of special memory accesses per instruction and calling the chipset emulation on memory writes from the compiled code
  • Implementation of some instructions:
    • ADDQ.L;
    • MOVE.x register to memory;
    • MOVE.x register to register;
  • Implementation of some addressing modes:
    • immediate quick, like: ADDQ.L #x,reg;
    • indirect addressing with post increment, like: MOVE.x reg,(Ay)+;
  • Misc fixed stuff:
    • proper logging for JIT (with a new configuration item: comp_log);
    • slightly reworked temporary register handling;
    • better handling of reloading/saving of flags and the base register;
    • reloading of the emulated PC before leaving the compiled code is added (probably this was responsible for the reboot-loop at booting the OS, see below).

The most important change was the handling of the memory writes. When I started to plan the project this was one of the concerns: how to figure out which memory access requires special handling and which one can hit directly the emulated memory. By overcome of this issue all three problems are resolved:

  • memory accesses are emulated as it is needed;
  • self-modifying code is handled by using the processor cache;
  • translated code lookup is managed by simulating the cache lines.
Luckily, the x86 JIT implementation already solved this issue (too): every instruction is executed by the interpretive emulator first for a couple times to prevent unnecessary translation of the code pieces that won’t be executed often (like initialization/cleanup code). While it is doing that it collects some information about the executed code that can be reused for the translation. One of these is the memory access type. Very clever solution, I must admit.

I am still chasing the ghost-bug that prevents the OS from booting. The recent fixes for the PC register (program counter) reloading changed the behaviour. Instead of running around in a reboot-loop, the OS is waiting for something to happen, most likely some hardware to trigger something. So, it is still no good, but looks a bit better.

Where to go from here: more addressing modes and instructions will be implemented before I start working on the implementation of the optimizing routines. First, I want to make sure that most of the Mandelbrot test is executed using compiled code, thus it will be easier to test the optimization and finally we can see how better the JIT performs than the interpretive. Exciting!

You have probably noticed that the state of the project on SourceForge is still pre-alpha. I don’t want to change it while the OS cannot be run on the emulation, so this is the other important goal.

So much for today. While you are enjoying the sunny, warm summer, don’t forget about us who are suffering from the cold, rainy days: Winter is coming… :/

Monday, November 7, 2011

While you are waiting (FAQ)

I know you can hardly wait to fire up the JIT-crafted UAE; still I need to ask for more patience. Things are improving, yet it is not as mature as this admired audience would deserve, so there is no pre-relase just yet.

Some of you is more excited than the others and asked interesting questions that worth answering. Questions are repeated all over again quite often, so let me save some time and pondering: here are the answers for the...

Frequently Asked Questions

Last updated on 11 January 2014.


Q: How can I help?
A: You can always show your support by sending a small donation to this project on AmigaBounty. You can also spread the word to users of other platforms; maybe they would like to hear about it too.
In case you feel the urge, you can fiddle with the sources. See the Q/A below related to getting the current sources.

Q: Will this JIT translation work on AmigaOS3.x PPC/MorphOS/Macintosh/Linux/game consoles? The bounty is about AmigaOS4!
A: Absolutely, I have no intention to limit the implementation to AmigaOS4.
However, I cannot promise that I will release any other specific builds from E-UAE other than the one for AmigaOS4. (Simply because I have no experience, neither too much time/intention to dig deep into development for different platforms.)
The sources are released under GPL license; you can do your own build or merge it into your favorite UAE derivation.

Q: Will you fix the bug XYZ in E-UAE? Will you improve the chipset emulation?
A: No. I never promised anything else than PowerPC JIT translation and I still intend to stick to this. I have fixed some minor things in the original E-UAE implementation that was related to AmigaOS4, but don’t expect any subtle changes.

I am not going to take over the maintenance of the E-UAE source code base. Somebody else has to stand up and accept this task.

Q: Will this JIT thing improve the speed of the emulation of my favorite (OCS) game?
A: Possible, but I must point out that similarly to the x86 implementation the JIT translation will only work on processors that have instruction (CPU) cache built in and turned on (68020 and up). So, if your game cannot cope with these processors and the turned on processor cache, then I am sorry, but it won’t help much.


Q: I tried to run Kickstart 1.3 and it crashed with the JIT enabled!

Why? I tried to run <some ancient Amiga 500 game> and it crashed with the JIT enabled! Why?
A: Before Kickstart 2.05 the OS was not aware of the processor (CPU) cache, essentially these Kickstart versions wouldn't work with 68020 processors at all.
The processor cache is disabled when the processor resets and starts executing the ROM, but since the OS is not aware of the cache flags it turns on the cache when it fiddles with the processor control registers.
Why was it working with the interpretive emulator when 68020 processor was selected: the processor cache is not emulated in the interpretive emulator, so basically it doesn't matter at all if it was on or off.


Q: Why is the JIT depending on the processor (CPU) cache?
A: Because it is very hard to detect the self-modifying code, code overwriting and similar situations without the help from the OS or the running program itself. When the cache is flushed then the previously compiled code can be recompiled.
The JIT implementation is depending on the processor (CPU) cache emulation to overcome of the issue of the self-modifying and the generated/copied code. The JIT compiled code behaves quite similar to the actual 68020 execution, so if an OS version or a game does not work on 68020 (caches enabled) then it won't work with JIT either. (I had my sweet time with this issue while I was developing Petunia, back in the days. Still not resolved
completely there, but it is good enough for now.)

Q: Will this JIT thing improve the speed of the emulation of my favorite (OS-friendly) 68k application?
A: Most likely yes. No promises, though.


Q: When will it be ready?
A: When it’s done… ;) If everything went very well then it will be finished around when the bounty deadline comes: 02/21/2012. (Maybe I should start a countdown, but it would be too embarrassing when I miss the deadline. ;) Well, the deadline is missed, so, let's say: when it's done.


Q: Is the implementation derived from Petunia?
A: No, it is a completely different code. Neither any C or assembly source code from nor any dependency on the JIT implementation in AmigaOS4 is used.
(Actually, this is not entirely true: I was way too lazy to create an instruction description table file again and the parsing tool for it, so these two pieces were borrowed from Petunia. My original plan was using the present file and parsing, but it was so tuned to the interpretive emulation and my JIT implementation is significantly different than the x86 version, so I just skipped this.
But apart from that two files the emulation itself is completely different.)

Q: Will it be faster than Petunia?
A: I have no idea. It is more likely that some apps will run faster with Petunia, others will run faster with the E-UAE JIT. There are too many factors that might have effect the results. We will see when it will be finished.


Q: Where can I get the sources?
A: Check out the SourceForge project: https://sourceforge.net/projects/euaeppcjit 

Q: Where can I get the executable?
A: There is no final release yet, the project is in Beta stage.

Q: I want to try the emulation RIGHT NOW! How can I get it?
A: Go ahead and download the beta from the SourceForge project page:
https://sourceforge.net/projects/euaeppcjit/files
Please note: it is still Beta. You can give it a try, but be prepared that it might not work as you might expect it.

Q: But... but... I don't know how to set up the JIT compiling. What would you suggest?
A: There are some crucial settings for the JIT in the E-UAE configuration file. Without these settings the JIT compiling won't work properly. I suggest to add the following block into your E-UAE configuration file:

cpu_speed=max
cpu_type=68020
cpu_compatible=false
cpu_cycle_exact=false
blitter_cycle_exact=false
comp_optimize=no
cachesize=8192
comp_constjump=yes
comp_trustbyte=indirect
comp_trustword=indirect
comp_trustlong=indirect

ppc.use_tbc=false

These are the necessary settings for now, might (or most likely will) change in the future. 


Q: How can I be sure that the JIT is working while I am running the program?
A: There is a LED for it! Yes, if you turn on the LED on-screen-display (OSD) then you will see a LED that says "JIT". If this LED is green (read: not completely black) then the JIT is on. The more bright green means more executed JIT code.
If the LED is red then the JIT compiling is not working at the moment.
To turn the LEDs on put this into your configuration file:

show_leds=true

If you are interested in the details of how the JIT LED works have a look on this post: http://euaejit.blogspot.com/2013/02/watch-for-led.html
The LED behavior is slightly changed in Beta01, so have a look on this page too:
http://euaejit.blogspot.com/2014/01/ppcjitbeta01-happy-new-year-2014.html

(Bonus questions, asked almost every time… :)
Q: Do you like to live in New Zealand?
A: Very much so. :)


Q: Have you met the hobbits yet?
A: No, not yet, but I am looking forward to meet them. But we already visited the Hobbiton, that was fun!


Q: Have you met any sheep yet?
A: Yes, a lot.


I will add more questions and answers to this post as soon as I got more.
It seems pretty boring for now. Maybe I should post some naked ladi^H^H^H^H facts to this page.

Comments? :)

Sunday, October 2, 2011

Let It Rip

I had spent lot of time on understanding and reshaping the x86 JIT compiling, and fit the PPC code emitter into it. No, no and no. The source code is so deeply convoluted, riddled with residue from debugging, useless functions and scary/cryptic workarounds that I had to give it up.
So, I finally decided: I will rip the x86 part out of the recent E-UAE sources. The PPC code emitter will come as a brand new part, won't depend on the x86 counterpart.

PS. I would like to thank Douglas McLaughlin for the Synergy client for OS4. Great work, it helps much.

Sunday, September 11, 2011

The Big X on the Map

Just a very quick update: things are slowly evolving, so DON'T PANIC.

Some more words about what has happened recently: I had some trouble with my Amiga, turned out as a PSU problem. Luckily it is already fixed with a "new" case for the poor girl.

I am fighting with the rather chaotic E-UAE sources, so I made a few steps to make it easier to edit the whole project: I managed to put together a cross-compiling environment from Windows. *booo-booo*
Compiling is much faster on the muscle x86 processor (*booo-booo*) and there are some advanced tools to do some heavy lifting when it comes to source code editing. I must also admit that since I use source version control at work, I barely can go on without it.

With the help of Cygwin, Eclipse CDT, TortoiseSVN, VisualSVN Server, FileZilla Server and a simple script on the Amiga side I was able to assemble a semi-automatic build and test deployment environment.

Thanks to Zerohero for the detailed cross-compiling setup description.

Monday, February 21, 2011

Hello and welcome on the E-UAE JIT developer blog!

The purpose of this blog is documenting the development of the extension of the E-UAE Amiga emulator with the possibility of making use of Just-In-Time compile based Motorola 680x0 processor emulation.
A short lesson of history
WinUAE, the Amiga emulator for Windows have JIT compiling for many years now. Unfortunately, it is closely tied to the intel x86 architecture, because the most efficient way of implementing the JIT compiling is kinda similar to an actual programming language compiler: the end result is machine code, which is executed directly. Although it is possible to implement a processor independent JIT compiler, but to squeeze more speed from the executed code in a general compiling model is much more complex.
Recent Amiga (like) computers are using PowerPC processors, porting the WinUAE solution to PPC processor would be closely as hard to do as implementing a brand new solution. Not to mention that there are special requirements from the environment of the emulation, that cannot be simply resolved.
Since not many coders have experience with JIT compiling on the whole world, the line of applicants for creating JIT compiling for PowerPC processor was pretty short for years.
On the other side, users needed the JIT compiling for UAE emulation for running all sorts of the legacy applications, which cannot be run on the recent incarnation of the AmigaOS systems (because those are buggy, not system-friendly, hitting the hardware directly, and a number of other reasons). The demand was so high that even a bounty was set up for this specific project on the AmigaBounty site, yet nobody wanted to take the job.
The insane with a rattle
You might ask why anybody would invest countless hours into this project. And I must say it is a valid question.
I have already experience in this field, I completed the similar component in AmigaOS4 (code name: Petunia). If you are interested in the fine details of the JIT compiling, then I suggest checking out my Project Petunia web page.
There are a few other reasons; some folks were bugging me with it for years and it is a bit of a challenge. Also there is this typical feeling in every coder’s head, when a project finished: trying to implement it second time the outcome would be much better because of the previous experience.
Well, here is the time to see how well it goes…
Principles to follow
There are some ground rules I will try to keep to make as many future users happy as possible. These are:
  • The source files will be freely available to anybody under GPL license or directly from me with a different license on request.
  • While the development will be done on AmigaOS4, I won’t use any AmigaOS4-related feature, which makes it harder to port the solution to any platform. (It means my previous project won’t be used directly in any form.)
  • I will try to keep the solution as flexible as possible, to let others make use of it without E-UAE.
  • I won’t sacrifice compatibility over speed.
  • I will implement some possible adjustments to let the user fine-tune the JIT and therefore improve compatibility with the old applications.
That is all for today, more technical details will follow in the next post.