Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Perl 5 Optimizing Compiler, Part 2

by Will_the_Chill (Pilgrim)
on Aug 17, 2012 at 22:24 UTC ( #988109=perlquestion: print w/ replies, xml ) Need Help??
Will_the_Chill has asked for the wisdom of the Perl Monks concerning the following question:

Okay Monks, I've done a few days of recon. Now I'm talking to Nick Clark and Ingy and Reini and others. Below is my latest e-mail to Nick about the whole thing, with some links interspersed for your convenience.

Now, on the count of 3, everybody tell me EXACTLY HOW I'M WRONG!

1 ... 2 ... 3!

<<< BEGIN E-MAIL >>>

Howdy Nick,

I'm probably misunderstanding some technical aspect of the whole RPython vs Perlito vs everything, here's my take, please correct me:

http://perlito.org/

Perlito is a language translation system AKA compiler, written in Perl 5. Perlito can parse a subset of Perl 5. Perlito can generate Javascript from the parsed subset of Perl 5. The generated Javascript can run in a fast Javascript VM like Google Chrome's V8. Since the V8 Javascript VM aims to eventually run as fast as native C, and it has the full backing of Google, then it may be a good final VM target to make a subset of Perl 5 run very fast.

http://tratt.net/laurie/tech_articles/articles/fast_enough_vms_in_fast_enough_time

RPython is a subset of the Python programming language, written in Python (I guess). RPython was created to create the PyPy Python JIT, which now runs faster than the original CPython interpreter VM. Any program written in RPython has the benefit of receiving an automatically-generated optimizing & tracing JIT compiler for free. Comparisons of the Converge language's VM written in C vs RPython show orders of magnitude speed increase by RPython's generated JIT. We would use the RPython language to implement a VM supporting (at least) a subset of Perl 5, which would give us the free Perl-specific JIT as a result, and again make a subset (or all) of Perl 5 run very fast.

http://cdent.org/

Ingy's C'Dent is a language translation system akin to Perlito, also able to parse a subset of Perl 5, which Ingy calls Perl5i. Instead of generating Javascript from Ingy's subset-of-Perl5, he aims to generate XS code, although I'm not sure how close he is to achieving that just yet. Since XS is pretty much C using native Perl data structs like SV etc, then in theory again we could end up with a subset of Perl 5 running very fast.

http://search.cpan.org/~mlehmann/Faster-0.1/

I think Marc Lehmann's Faster module on CPAN is similar to Ingy's goal of compiling some portion of your Perl 5 into XS. Faster may or may not be using Ingy's old Inline::C modules, which can also be used for some incremental runtime performance increase.

https://github.com/rurban/perl-compiler

Reini's work with the B compiler system seems to have made him enemies in the Pumpking and P5P camps, too bad. From what Reini tells me, he is mostly focused on making some fundamental changes to the Perl 5 language (unlikely to be adopted), and boosting startup speed by compiling to Perl Bytecode, etc. Reini is the only one working with ALL of Perl 5, not just a subset of Perl 5. I'm afraid that just-a-subset-of-Perl5 is a bad general route to take, because then you'll always be trying to catch up with the "real" Perl 5. So my thoughts are to try and have the full Perl B compiler system as the frontend so we are never just-a-subset, then we just need to decide which backend(s) to use to run the not-just-a-subset Perl 5 code in its native B form.

I think to somehow combine Perlito/Perl5i and RPython would amount to manually translating the Perlito/Perl5i subset-of-Perl parser from Perl (or whatever) to RPython; or manually translating RPython's JIT-creating system from Python to Perl. Both of these would work I think?

I think to somehow combine Reini's not-a-subset-of-Perl5 frontend with one or more of the Perlito/RPython/Perl5i backends would amount to some new Perl 5 code gluing them all together in the grand old Perl tradition of TMTOWTDI. We can run some performance tests on Perlito and Perl5i to see if we also need RPython. If we need RPython's awesome magical JIT (which I suspect we may), then we will have 3 new backends, and don't forget we still have the "real" Perl 5 interpreter VM to fall back on when we have code that isn't within any of the backends' subsets-of-Perl. So we create some Perl glue to make Reini's B system decide which of the 3 or 4 backends to run for each code segment based on some hard-coded rules derived from our performance tests on each backend's subset-of-Perl. The only thing the Perl users would know is that now when they run the /usr/bin/perl executable, it runs almost as fast as C.

Please do keep telling me exactly how wrong I am, you are clearly the most receptive and knowledgeable person I've got at this point. :)

Thanks!

~ Will

<<< END E-MAIL >>>

Comment on Perl 5 Optimizing Compiler, Part 2
Re: Perl 5 Optimizing Compiler, Part 2
by chromatic (Archbishop) on Aug 17, 2012 at 22:47 UTC

    A JIT is not magical fairy dust you can sprinkle on code to make it go faster!

    "As fast as C" is a phrase almost entirely devoid of meaning!

    Any language implemented atop a VM will either work with the VM where the VM supports the semantics of the language or devolve into a multi-octopus wrestling match where the VM doesn't support the semantics of the language!

      Chromatic,

      A tracing & optimizing JIT that is Perl-specific, such as what would be created by RPython, should provide some amount of "magical fairy dust" in that it should make Perl 5 run faster. Please correct me on this particular point.

      "As fast as C" may be a bit tongue-in-cheek, we can stick with my original phrasing of "within an order of magnitude as fast as optimized C". This should have a very specific meaning to anyone running performance benchmarks. Write some code in C, then write the same code in Perl, then run them for comparison.

      I fully agree about the issue of making sure a VM is a suitable target for a particular language.

      RPython would generate a Perl-specific JIT. No multi-octopus wrestling match there.

      Flavio's Perlito generates Javascript to run in a Javascript VM, but from what little I understand about Javascript it is a high-enough-level language to emulate Perl 5 to some degree. (I've had complex code translated from Perl to Javascript in the past.) Perlito doesn't look like much of a multi-octopus wrestling match between Perl as an input language and the Javascript VM, but I could be wrong.

      Ingy's C'Dent and Perl5i are supposed to be generating XS code, so no new VM there, and no multi-octopus wrestling match that I can see.

      Reini's B system seems closely tied to the existing Perl 5 interpreter VM, so no multi-octopus wrestling match there, either.

      So what am I actually wrong about?

      Thanks,
      ~ Will
        Please correct me on this particular point.

        Here's a fun one: how do you ensure that the finalization semantics of Perl 5 (thanks to reference counting) are in effect on an RPython platform? How about operator types? Iterator aliasing?

        ... from what little I understand about Javascript it is a high-enough-level language to emulate Perl 5 to some degree.

        Does it support raw memory access, or do things that aren't hashes or floats have to be emulated with hashes and floats?

        JIT is only a real advantage when you can use things like type specialization and escape analysis to create straight-line code that can make a lot of assumptions because you've proven them. You have to get the boxing/unboxing semantics right, and you have to have a deep understanding of the memory model of the target and of the hosted language.

        (The same laws of physics apply when porting an existing language to a different VM. If you get dramatic speed improvements on all but a few benchmarks, it's a sign that the prior VM was pretty poor, not that JIT magic unicorn-flavored candy.)

Re: Perl 5 Optimizing Compiler, Part 2
by bulk88 (Priest) on Aug 18, 2012 at 04:58 UTC
    Can you answer what in these "subset of Perl 5" implementations was dropped?

    less seriously, is PHP a subset of Perl 5?
Re: Perl 5 Optimizing Compiler, Part 2
by bart (Canon) on Aug 18, 2012 at 07:29 UTC
    From what Reini tells me, he is mostly focused on making some fundamental changes to the Perl 5 language (unlikely to be adopted)
    and
    Reini is the only one working with ALL of Perl 5, not just a subset of Perl 5.
    *Bzzzt!* Does not compute! Does not compute!

    You can't be working for all of perl if, in the meantime, you're changing the language.

    So, what parts of Perl would he be changing, syntax-wise or semantics-wise?

    If you're trying to compile all of perl, then you may just have to rewrite the parts that it would like to handle differently. That rewrite should be done by the compiler or a precompiler, not by a programmer.

      Reini is the only one working with ALL of Perl 5, not just a subset of Perl 5. *Bzzzt!* Does not compute! Does not compute!

      Sure it does.

      You can't , if , what ...

      Did you read for yourself to see what he's doing? How would you describe the effort?

Re: Perl 5 Optimizing Compiler, Part 2
by flexvault (Parson) on Aug 18, 2012 at 10:00 UTC

    Will_the_Chill,

    Good Research!

    I hope you noticed my interest in the topic Perl 5 Compiler, Again! which was a direct result of your original post. If you did you may have noticed the answer from rurban of:

      perl5 opcodes change from release to release, there's no discipline. p5 devs do not want to have bytecode discipline.

      parrot was designed to have bytecode discipline originally (and be platform independent), but both of these goals were thrown away without discussion at v1.0. That's why I left the project in protest.


    clarified for me why the 'compiler' topic is near impossible to solve.

    This guarantees that each release of Perl requires a re-compile of all scripts or just keep all scripts as source-code. Until that explanation I just couldn't understand the real problem.

    Since both 'perl5' and 'perl6' have dropped the concept, maybe it's time for 'perl7' :-)

    Good Luck...Ed

    "Well done is better than well said." - Benjamin Franklin

      This guarantees that each release of Perl requires a re-compile of all scripts or just keep all scripts as source-code.

      ... only in as much as every C program needs to be recompiled whenever a new version of gcc is released.

      I would assume that a compiled Perl program includes all its constituents (modulo external, non-XS dynamic libraries), and thus is basically a stand-alone executable.

      But then again, I don't care much for either side of this argument, as for me the interpreter has been fast enough in the parts where I use it.

        Hello Corion,

        I think you're confusing my portability and scalability issues with others requirements for speed and/or obfuscation. I have stated on PM that 'Perl just gets better and better" and I meant it. I don't have issues with Perl's speed.

        Also I do have programs that were compiled in 1990 on pre-released IBM RS/6000 computers running AIX 3.0 beta ( AIX 3.1.5 was the official release in 1991 ) that can run today on 'power 7, p-series computers running AIX 7.1'. The computers are binary compatible even though the source code doesn't compile. K&R 'C' is considered traditional today, and most 'C' products no longer support traditional code.

        IMHO, if you ever have to authorize a '10 man-year' project to manually update source code on 2500+ computers, instead of remotely updated the compiled code over a weekend, then maybe you would see it as a little bigger and different problem.

        Thank you

        "Well done is better than well said." - Benjamin Franklin

      Python seems (I've never programmed in it) to cache compiled bytecode and keep it next to the original source code everwhere, http://docs.python.org/release/1.5.1p1/tut/node43.html. Maybe a similar concept should be added to Perl. If the version, or CRC or timestamps dont match it is recompiled and saved disk.

        bulk88,

        That would enhance Perl, but would not solve the lack of 'opcodes integrity' from release to release. Maybe the 'use 5.8.8;' could be enhanced to use/force the bytecode to be the same as used for release 5.8.8.

        As a programmer, Perl is a fantastic tool.

        From the perspective of upper management that authorized the salary for the programmer, it's a tool that end-users can change. We hear all the time on PM "I can't use CPAN" or "I don't have access to a compiler", or ...
        And then we get the tech answer of 'You too...' But that's not the answer?

        The question is coming from someone who is listening to his/her management, and management wants to control the use of the company's computer resources.

        A technical answer is not relevant.

        Upper management doesn't care how easy/hard it is for the programmer, they want to know that if the software gets deployed to the organization, then it will work the same everywhere.

        This isn't new, and it's not going to be solved on PM!

        Thanks...Ed

        "Well done is better than well said." - Benjamin Franklin

      flexvault, I've sent you an invitation to Trello using your e-mail address from the Chatterbox message (which I almost totally missed, please reply in these threads instead):
      BLANK

      Accept the invite and I will add you to the Trello board for this software development project.

        Will_the_Chill,

        That was a private message I sent you, so that the email address would not be on-line for spammers. Please remove the address.

        I've received your message.

        Thank you

        "Well done is better than well said." - Benjamin Franklin

      Ed, I'm no expert but I think you may be a bit confused. Your "Perl 5 Compiler, Again!" thread definitely did NOT prove that the "compiler topic is near impossible to solve". That thread was basically just one tit-for-tat between chromatic and Reini Urban, who are on opposite sides of the fence on this particular issue, and who are apparently also not the best of friends. Nothing solid can be deduced from that thread.

      The bytecode issue is only one aspect of the complicated optimizing problem. We may be able to produce a Perl 5 optimizing compiler without use of the Perl bytecode system at all. On the other hand, bytecode may turn out to be a critical component in optimizing, only time will tell.

      Perl 6 seems to be a pipe dream. Perl 5 seems to be stabilized and mostly in maintenance mode. I'm not interested in creating Perl 7, since Perl 6 needs to happen first, if ever. I'm interested in compiling & optimizing Perl 5, and this is what I will achieve. :-)

        Hello Will_the_Chill,

        Thanks for removing the email address.

        I don't think I'm confused about how to write a compiler, since I was very much involved in that in the past.

        What you are minimizing is the '...lack of bytecode integrity' on the impact of developing a compiler for Perl. This is a religious decision and not a technical issue. Your attempts will fail because the Perl developers don't want you to succeed. Each new version of Perl will need a unique compiler. So you come out with your Perl compiler 5.20.0 and the next week Perl 5.22.0 is released, and the Perl developers point out that you compiler 5.20.0 doesn't work with 5.22.0. True, because now you have to use the bytecode structure of 5.22.0 for your 'new/updated' compiler, and your always in catch up mode.

        Notice, how many are quick to point out that the early attempts at compilers were always 'out of date'.

        I wish you luck, but I was only half joking about Perl7. Perl's strength is The Programming Language, not that it's an interpretative language. Of course you need source code, and to develop the software product you need the power of running in an interpretor, but then you need a compiler to distribute the product. Perl5 has two of the three, and will alway have two of three.

        Thank you

        "Well done is better than well said." - Benjamin Franklin

        Nothing solid can be deduced from that thread.

        Indeed, and yet:

        That thread was basically just one tit-for-tat between chromatic and Reini Urban, who are on opposite sides of the fence on this particular issue, and who are apparently also not the best of friends.

        You're making another big assumption. Please stop.

      Since 'perl5' and 'perl6' have dropped the concept of bytecode generation

      Aiui it is, or would be, a monumental (I think that's an understatement) social and technical task to bring bytecode, and bytecode discipline, to the current Perl 5 compiler.

      But the story is different for Parrot. And different again for Perl 6. And different again for Perl 5 in the light of Perl 6.

      Parrot is a tough call. As others have said, bytecode stability was part of the original plan. It doesn't have that now, but that doesn't mean it couldn't, and won't ever. Otoh, to say they have more pressing concerns, and lack of tuits, is an understatement. Unless you are confident you could live for a few years without oxygen if you had to, I recommend you don't hold your breath waiting.

      Perl 6 also has more pressing concerns, and also has less resources than it needs, but it's a much more reasonable proposition regarding generation of bytecode and discipline to keep it forward compatible as they add or change opcodes.

      There are several Perl 6 compilers that generate bytecode. In particular, Niecza is pretty advanced and currently generates CLR bytecode and Rakudo is also pretty advanced and currently compiles down to Parrot bytecode. Aiui both these compilers are likely to be portable across different bytecode backends soonish; perhaps one will even manage that this year.

      And a few days ago someone spotted Larry Wall working on a Perl 5 parser written in Perl 6, something that's gotta be way easier than working on the current Perl 5 compiler...

        And a few days ago someone spotted Larry Wall working on a Perl 5 parser written in Perl 6

        Isn't that a bit like translating Welsh into Esparanto?


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

Re: Perl 5 Optimizing Compiler, Part 2
by dave_the_m (Parson) on Aug 18, 2012 at 13:41 UTC
    As regards RPython: using this would entail rewriting the entire perl runtime in rpython: somewhere between about 30-100K lines of C, depending on what bits are required. This would be very hard and time-consuming, and at the end, there's no guarantee that it would be any faster.

    You're basically replacing mature, tightly honed C code with python, then hoping that the tracing JIT will not only bring the python code back up to the speed of the original C, but past that point and even faster.

    You'd have to deal with impedance mismatches. For example, if python-style arrays and hashes provide a superset of the semantics of perl arrays and hashes then you may be able to use them directly; if not, you'd have to implement perlish hashes in python!

    Also, you'd have to say goodbye to XS. It's not clear to me whether the existing perl regex engine could still be used, but if it could, it wouldn't benefit from JIT.

    Etc etc.

    Dave.

      Dave, you're right, I was confused about this. We don't need to re-implement the Perl 5 interpreter VM into RPython, we only need to compile the Perl 5 applications into RPython. I will write more about this soon in my further postings.
Re: Perl 5 Optimizing Compiler, Part 2
by sundialsvc4 (Monsignor) on Aug 20, 2012 at 14:33 UTC

    Shrug...

    The gist of these ideas seems to be that the Perl5 implementors somehow got things desperately wrong, whereas the JS and/or Python implementors (who of course are doing much the same thing in much the same way) ... didn’t?

    All of these systems work by JIT translation of source-code into bytecode or into an internal data-structure that is then processed using an optimized interpreter loop.   Even “traditional” C++ compilers use that technique, and of course, Microsoft’s dot-Net framework is entirely based on it.   The overhead of a runtime interpreter loop is frankly negligible.   JIT compiling is also an affordable one-time overhead expense.

    “80% of the time is spent in 20% of the code.”   In many systems, those hot-spots are located in the language-common runtime libraries.   In Perl et al, the hot-spots once identified can be spun off into XS subroutines.   Those hot-spots will be hot-spots no matter how program-control is passed into them, and they (along with the fundamental design of the high-level program) will account for the human-visible performance impact no matter how the other 80% of the code is written.

    If this were not so, then Perl, Python, Java, dot-Net, PHP and so-on would never have been done this way, and billions of lines of source-code would not have been developed using them.   Before you pay to get something, be sure you’ll get what you paid for.   In this case, you won’t.

      Even “traditional” C++ compilers use that technique...

      What?

      JIT compiling is also an affordable one-time overhead expense.

      Not the tracing technique that's currently fashionable! Writing XS to do the same thing without the overhead of op dispatch won't optimize something that's slow because it uses more memory than necessary to provide more flexibility than necessary, especially if running that XS code adds a language barrier that you can't optimize across and which requires serialization and deserialization (or at least prevents you from using non-SVs).

      In Perl et al, the hot-spots once identified can be spun off into XS subroutines.

      In many cases that won't help.

      If this were not so, then Perl, Python, Java, dot-Net, PHP and so-on would never have been done this way....

      I'm sorry, but that's a non sequitur.

        Even “traditional” C++ compilers use that technique...

        What?



        Sundial is being vague again. I *think* he is talking about that all C compilers released in the last 20 have a "front end/back end" design with a non machine code bytecode in the middle. Or Sundial is talking about C++ string classes designed to sell new PCs since they perform a full heap walk/validation on each string catting to stop evil hackers and phishers.

        Not the tracing technique that's currently fashionable! Writing XS to do the same thing without the overhead of op dispatch won't optimize something that's slow because it uses more memory than necessary to provide more flexibility than necessary, especially if running that XS code adds a language barrier that you can't optimize across and which requires serialization and deserialization (or at least prevents you from using non-SVs).

        In Perl et al, the hot-spots once identified can be spun off into XS subroutines.

        In many cases that won't help.

        Turning perl opcodes into one XS always results in a faster runtime even if the data moved as SVs between C functions under 1 XS function. Mark, context and tmps stack swaps, pushmarks, PAD accessing, GV deferencing, wantarray context checks, are eliminated. Machine opcodes sit in RO memory rather than RW memory such as Perl opcodes so the CPU has more opportunity to optimize. In runops the next perl opcode (and next machine code function) can't be predicted since it sits in RW memory or the return register in the callee. For heavy cpu operations such as a regexp, or IO, of course there is no difference between XS and Perl bytecode. Very poorly written XS/C code (macro and inline abuse, and dumb compilers that don't merge character identical branch blocks together with jmps (Visual C cough cough)) can take more memory than the equivalent Perl bytecode. A C compiler can produce jumptables, the Perl Compiler doesn't produce jumptables, although I have seen some actual implementations of jumptables on PerlMonks that didn't result in a tree of conditional opcodes, IIRC it used goto. Perl has no C preprocessor although it has constant folding branch elimination that sort of is the same (although I think I'm the only one in the world who intentionally uses that). Perl encourages strings in general rather than numeric constants for settings and hash key names. I didn't research this, but I dont think Perl has any optimized to an array/AV implementation of restricted hashes (cough cough structs). As other have said, Perl's flexibility is its performance problems. If there is one candidate in Perl's standard library I would rewrite in XS, it is Exporter. 99.999% of Perl Modules use it. A distant 2nd is the pure perl portions of Dynaloader. I dont think there is anything else that deserves a rewrite in XS that would benefit the *whole* Perl community. Introducing new opcodes and reducing the opcode count by stuff more metadata into them (upto a couple bits of a pad offset, if offset is 1111 out of 4 bits, look for it on the "legacy" Perl stack), stuff GV's const char names into the de-gv opcode, not put a mark and a const string SV on the Perl stack. Desktop OS kernels don't allow time slices and inter thread signaling fine enough for automatic parallelism (list assign to list for example), plus perl's magic and tied monkeywrench would cause races. Writing a user mode inter thread synchronization and parallelism system with busy waiting on secondary CPUs is beyond the scope of the Perl project.

      All of these systems work by JIT translation of source-code into bytecode or into an internal data-structure that is then processed using an optimized interpreter loop.   Even “traditional” C++ compilers use that technique, and of course, Microsoft’s dot-Net framework is entirely based on it.   The overhead of a runtime interpreter loop is frankly negligible.   JIT compiling is also an affordable one-time overhead expense.

      Well Perl does do JIT translation already, see eval.
Re: Perl 5 Optimizing Compiler, Part 2
by Will_the_Chill (Pilgrim) on Aug 21, 2012 at 05:56 UTC
    I appreciate everyone who has replied to this thread. I am still making progress in my research and discussions. I will likely continue to post new updates with the title of "Perl 5 Optimizing Compiler, Part X".
    Thanks!

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://988109]
Approved by GrandFather
Front-paged by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (6)
As of 2014-07-11 22:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (235 votes), past polls