On 11/06/03 Leopold Toetsch wrote: > > because pmc as so much slower that native types i loose most of > > parrots > > brilliant speed due to the fact that i don't know the types at > > compile-time. > > When you get rid of all the temps and the clone[1], the loop with PMCs > runs at about 3 times the speed of perl5. So I'd not use the term > "slow". It would be faster with native types of course, but its hard to > impossible to decide at compile time, that native types do the same > thing. I don't know PHP but in perl the + operator could be overloaded > and calculate the phase of the moon instead of adding 5.5 ...
Yes, this is a very important point. Current dynamic languages can get a speedup in several ways: *) reducing opcode dispatch overhead (the various mechanisms parrot uses, like cgoto etc. and by jitting the code) *) better VM implementation (for example the use of the vtable instead of multiple checks trick that Dan mentions) *) code specialization The first two you get for free using parrot or another advanced VM with a JIT (well, the second item may require to properly design the language specific PMCs or classes, but that's not so difficult after so many years with the perl/python/php engines). The latter is what potentially gives the bigger benefit, but it requires lot of work in the compiler frontend (using typed variables make it easier, but to preserve a better feel something like pysco is needed). For example, in the sample code, the compiler could see that the constants are integers and doubles and that the '+' operator hasn't been overloaded, so it could do away with using PMCs (but, again, this is a lot of work). Parrot already helps with the first two items a lot and it provides most of the needed features for the last item: specialized registers and a JIT. What I think it's missing is a way to perform function/method calls very fast (maybe also allowing inlining). This is needed when mixing different languages that install their own vtable implementations and also inside a dynamic language that uses vtables to multiplex (like it would happen with perl's IV, NV etc variables). But this is a small concern: much more work needs to go into the compiler frontends for php/python/perl etc to take advantage of it. > # for ($i = 0; $i < 10_000_000; $i = $i + 5.5) { } > .sub _main > .sym var i > i = new PerlUndef > i = 0 > $P0 = new PerlUndef > $P0 = 10000000 > lp: > if i >= $P0 goto ex > i = i + 5.5 > goto lp > ex: > end > .end I couldn't resist writing an equivalent program that runs on the Mono VM:-) The Perl* classes implement just a few methods to support the sample code, but adding more is mostly an issue of cut&paste. I believe the code accurately simulates what would happen with perl or php: a scalar starts out as an integers and becomes a float mid-way. There are three different loops that simulate how smart a compiler frontend could be: one puts just $i in a 'PMC' (PerlSV in the C# code), the second puts the loop upper bound, too, to match with the above imcc code and the last puts the 5.5 constant in a PerlSV, too. The run times on my machine are: mono smart-compiler: 250 ms mono imcc-equiv: 340 ms mono little-dumber-compiler: 460 ms parrot -j -O 4: 580 ms parrot -j: 600 ms parrot: 635 ms perl: 1130 ms php4: 2150 ms The parrot build was configured with --optimize. Parrot has a very good startup time (~10 ms), while the startup time for mono (running the same program with the loop limit set to 10) is about 100 ms. We obviously need to improve this, but this also means that the actual time to execute the loops above is about 100 ms lower for mono and 10 ms lower for parrot (times were measured with time (1)). My *guess* is that mono executes the same code faster because of better register allocation and faster function calls, I expect parrot to improve on both counts as it matures, at least as long as the vtable functions are implemented in C: anyone with performance numbers for vtable functions implemented in parrot asm? Hope this helps in the discussion (I included the C# code below so that people can check if I missed something of the semantics). lupus -- ----------------------------------------------------------------- [EMAIL PROTECTED] debian/rules [EMAIL PROTECTED] Monkeys do it better using System; abstract class PerlBase { public abstract PerlBase Add (double v); public abstract PerlBase Add (int v); public abstract PerlBase Add (PerlBase v); public abstract bool LessThan (int v); public abstract bool LessThan (PerlBase v); public abstract PerlIV IsIV (); public abstract PerlNV IsNV (); } sealed class PerlIV: PerlBase { internal int value; public PerlIV (int v) { value = v; } public override PerlBase Add (double v) { PerlNV res = new PerlNV (v + (double)value); return res; } public override PerlBase Add (int v) { value += v; return this; } public override PerlBase Add (PerlBase v) { PerlIV iv = v.IsIV (); if (iv != null) return Add (iv.value); PerlNV nv = v.IsNV (); if (nv != null) return Add (nv.value); // warn: numeric add with non-numeric val return this; } public override bool LessThan (int v) { return value < v; } public override bool LessThan (PerlBase v) { PerlIV iv = v.IsIV (); if (iv != null) return value < iv.value; PerlNV nv = v.IsNV (); if (nv != null) return value < nv.value; // warn: numeric compare with non-numeric val return false; } public override PerlIV IsIV () { return this; } public override PerlNV IsNV () { return null; } } sealed class PerlNV: PerlBase { internal double value; public PerlNV (double v) { value = v; } public override PerlBase Add (int v) { value += v; // double + int gives a double return this; } public override PerlBase Add (double v) { value += v; return this; } public override PerlBase Add (PerlBase v) { PerlNV nv = v.IsNV (); if (nv != null) return Add (nv.value); PerlIV iv = v.IsIV (); if (iv != null) return Add (iv.value); // warn: numeric add with non-numeric val return this; } public override bool LessThan (int v) { return value < v; } public override bool LessThan (PerlBase v) { PerlNV nv = v.IsNV (); if (nv != null) return value < nv.value; PerlIV iv = v.IsIV (); if (iv != null) return value < iv.value; // warn: numeric compare with non-numeric val return false; } public override PerlIV IsIV () { return null; } public override PerlNV IsNV () { return this; } } class PerlSV: PerlBase { internal PerlBase value; public PerlSV (int v) { value = new PerlIV (v); } public PerlSV (double v) { value = new PerlNV (v); } public override PerlBase Add (double v) { value = value.Add (v); return this; } public override PerlBase Add (int v) { value = value.Add (v); return this; } public override PerlBase Add (PerlBase v) { value = value.Add (v); return this; } public override bool LessThan (int v) { return value.LessThan (v); } public override bool LessThan (PerlBase v) { return value.LessThan (v); } public override PerlIV IsIV () { return value.IsIV (); } public override PerlNV IsNV () { return value.IsNV (); } } class Test { static void Main () { /* * C# code representing: * for ($i = 0; $i < 10_000_000; $i = $i + 5.5) { } * Note: $i starts as an int and becomes a double midway */ PerlBase sv = new PerlSV (0); PerlBase limit = new PerlSV (10000000); // alternative small value to check startup cost // PerlBase limit = new PerlSV (10); // the upper bound is a constant in the source, so the compiler // could easily produce this code: // for (; sv.LessThan (10000000); sv = sv.Add (5.5)) { } // // but we're going with the slower version below, since // the imcc code uses the same 'pattern' and we don't want // to cheat:-) for (; sv.LessThan (limit); sv = sv.Add (5.5)) { } // // even slower version: all operands are objects (but we're faster // than parrot anyway) // PerlBase increment = new PerlSV (5.5); // for (; sv.LessThan (limit); sv = sv.Add (increment)) { } } }