Fastest pure Euphoria CPU
- Posted by jeremy (admin) Dec 24, 2010
- 1186 views
I just wanted to point out a new feature of Euphoria 4.0, the pre-processor. In the CPU contest there was an entry, cpu-pp-fun.ex that was written by me. It is the fastest CPU entry for Euphoria. Now, to be fair, it is not an emulator like most of the other entries. It, instead, uses the pre-processor built into Euphoria 4.0 to convert CPU instructions into direct Euphoria code. Once the pre-processor is done with its work, Euphoria then executes the resulting post-processed file as pure Euphoria code.
An example input file:
205 ; Put 5 into register 0 325 ; Add 5 to register 0 ?0 ; Print register 5
Now, to execute this program with Euphoria, you simply use:
% eui -p cpu:cpu-pp-fun.ex add.cpu
For most people, when using a pre-processor, they will simply add the -p cpu... line to their eu.cfg file, thus the real command to execute any CPU file becomes:
% eui add.cpu
cpu-pp-fun.ex converts the the above program into the following euphoria program:
-- individual integer registers for speed integer jump=0, r0=0, r1=0, r2=0, r3=0, r4=0, r5=0, r6=0, r7=0, r8=0, r9=0 sequence ram = -1 & repeat(0, 999) goto "1" label "jump" switch jump do case 1 then goto "1" case 2 then goto "2" case 3 then goto "3" case else abort(0) end switch label "1" r0 = 5 label "2" r2 += 5 label "3" ? r0
Euphoria then writes this to a cache file and next time add.cpu is executed, it checks to see if it has been modified since the cache file was created. If not, it does not attempt to pre-process the source again, it simply calls the cached file. If, of course, it has been updated then the file is pre-processed again.
What is the scoring differences between the pre-processor version and those that took a more traditional eumulator inside of Euphoria? This is the speed.cpu program:
Name | Interpreted | Translated |
---|---|---|
Pre-processor cpu | 5.460 | 0.687 |
Matt's cpu-brute | 30.280 | 3.027 |
Derek's cpu | 48.751 | 7.535 |
Pete's cpu | 78.188 | 11.216 |
Now, as you can see the pre-processor gave a huge advantage in this area. Matt wrote a CPU that wrote out Euphoria source file for the CPU that was close to the timing of the pre-processor but not quite as fast. He also wrote a program that wrote a C version of the pre-processor, which, interestingly was only slightly faster than the pure Euphoria pre-processor CPU when translated! Interpreted: 1.5290 vs Inteperpreted Euphoria: 5.460, Translated: 0.468 vs. Translated Euphoria: 0.687.
One could argue in the spirit of the contest that the pre-processor gave an unfair advantage because it does not emulate the CPU, it actually translates the CPU program into valid code and then executes. While this is true, the contest did not say it had to be an emulator. This, however, in regards to what most people did was indeed unfair thus the cpu-pp was marked as a "fun" entry, i.e. it didn't count. But, I felt it deserved a little special attention in that it uses a very valid new feature of 4.0 to accomplish a task at lightning speed. But wait, how big was it compared to the others? The very maintainable pre-processor was 150 tokens. This is how I would have wrote the program if I were making it for long term maintenance. Only one CPU submission (non-cheat) was smaller and it was coded in a style for reducing token count, i.e. not something you would do for long term maintenance. It's token count was 136. Thus, small, easy to understand, maintainable and fast. What's not to like?
Taking this one step further, I wrote the cpi-pp.ex entry. What does this do? It converts (on the fly using Euphoria's pre-processor) a .cpu file into a Euphoria function. You can then include a .cpu file right in your Euphoria code as if it were a Euphoria source file itself (because after the pre-processor it is!). Here is an example:
include add.cpi include fib.cpi ? add(10,20) -- Result is 30 ? fib(10) -- Result is 55
The add.cpi file?
; ; Add r1 and r2 placing the resulting value ; into r0, the return register ; 612 ; r1 += r2 501 ; r0 = r1 100 ; halt
I am hoping that through these two examples some will get interested in the pre-processor and begin to play with it to see what it really can do.
Source for the cpu-pp, cpi-pp and various files are available on the hg:contest Mercurial repo. Directly at: hg:ontest/file/c97963e5f55c/2010-12-15-cpu/entries/jeremy. You can play around and have fun. To avoid having to do any -p xyz/abc lines, be sure you grab the eu.cfg file as well.
Have fun!
Jeremy