Announcement

Collapse
No announcement yet.

GraalPHP Is A PHP JIT Implementation Built On GraalVM

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #11
    Not to discount in any way the amazing work done, but it seems that the current implementation does not yet support... strings! Which is arguably the most used variable type in php, given its heritage as text-processing language - text in (http request), text out (http response).

    I do applaud all work done to improve execution speed, but at the same time I'm not really that interested in writing heavy number-crunching apps in php, which seems to be what all the recent improvements are about, including the JIT stuff which will be in php8.
    Give me faster handling of strings, arrays, objects, lower memory usage, lower cpu usage, improved GC, quicker bootstrap and shutdown and I'll be a happier camper :-)

    Comment


    • #12
      Originally posted by cen1 View Post
      Throwing around general terms like "Java is slow" is just bad. Slow for what use case? You could probably write 90% of software in Java and nobody would notice anything has slowed down.
      Well, the majority of web developers switched to JS on the front-end side. JVM needed to launch and initialize a heavy virtual machine and also do a full load of the whole core library. JS does not have many standard libraries and used to perform interpretation which is faster.

      Comment


      • #13
        Originally posted by caligula View Post

        Well, the majority of web developers switched to JS on the front-end side. JVM needed to launch and initialize a heavy virtual machine and also do a full load of the whole core library. JS does not have many standard libraries and used to perform interpretation which is faster.
        Java launches a VM, loads the standard library, and runs "Hello World!" in 110ms on my machine and uses 39MB of RAM.

        Node launches and runs "Hello World!" in 70 ms on my machine and uses 31MB of RAM.

        Comment


        • #14
          Originally posted by mdedetrich View Post

          Disclaimer: Full Time Scala Programmer

          This isn't entirely true, the JVM is actually very fast (it can get to 1-3x C++ speeds) when warmed up. The JVM has techniques to deal with this reference problem that you speak of (escape analysis/inlining, etc etc).

          The problem is that these optimizations happen at runtime, i.e. in C++ speak everything in JVM is virtual and then it becomes static when the JVM has determined that the method is a hotspot. This is also the issue when it comes to benchmarking because its actually incredibly difficult to isolate the "warming up" phase from the "inlined phase" (even in internal Java benchmarks). Ideally when benchmarking JVM code you want to exclude the warming up phase but this in reality this is very difficult

          In certain cases, JVM can beat "equivalent" C++ code (albeit rarely) due to the following reasons
          • Garbage collecting a large chunk of memory is much faster than doing it whenever an object is deallocated in C++ (RISC)
          • The JVM actually knows what the hotspots are at runtime rather than the programmer guessing (although this is somewhat mitigated with PGO)
          In general, although JVM is generally slower than C/C++ its much faster than other higher level languages and this is one of the reasons why its used so often (fyi, Twitter uses Scala in their backend, even in hotspots). GraalVM also substantially improves classical JVM performance, particularly for Scala.

          Practically speaking (from personal experience) the bigger issue with JVM is more the memory usage than actual performance. You typically have to throw a lot of memory for JVM languages however again this is actually to improve performance (i.e. its faster to malloc a big chunk of memory vs doing it incrementally and very often).
          I think you're a bit generous towards Java as to the relative speeds of C++ and Java.

          Here's my view - the language designers of Java treated the compiler like a garbage disposal system (or sewer system) ... literally, you can throw anything in it and forget about it. Or pass the buck if you wish.

          I've been hearing this Java party line since 1997, how wonderful the Just-in-time compilation is. But really, it's more politics than engineering. The reality is that:

          * Just in time compilation is severely hampered by the fact that it happens at runtime. Compilation time is runtime now ...
          * Profiling is not cheap. You instrument the code to collect profiling data, you slow it down. As such, VMs do relatively little there.
          * The language is just too f*ing dynamic. A VM needs to not just optimize, but also be able to de-optimize code. You can make certain assumptions about the class hierarchy, only to be invalidated by a newly-loaded class. This is just an example.
          * Escape analysis rarely works well. There's a reason why newer languages (Swift, golang) give the developer the option to embed (inline) objects.
          * If you have performance-critical code, C++ simply gives you many more options to tune it. If you don't care that much about performance, don't use C++ of course.

          You can wish for a magical compiler, but it ain't gonna happen. The first thing that limits compilers is the equivalence problem.

          Try working a little bit in an optimizing compiler ...
          Last edited by vladpetric; 27 September 2020, 08:14 PM.

          Comment


          • #15
            Synthetic benchmarking... in CLI mode where PHP opcache does not do much good... comparing static types based implementation against native dynamic types based one... no strings... All in all, even if this is a lot of good prototyping work, such benchmarking is pretty much pointless.

            Comment


            • #16
              Originally posted by vladpetric View Post
              * Just in time compilation is severely hampered by the fact that it happens at runtime. Compilation time is runtime now ...
              Generating optimized assembly at runtime is not a bottleneck

              Originally posted by vladpetric View Post
              * Profiling is not cheap. You instrument the code to collect profiling data, you slow it down. As such, VMs do relatively little there.
              Wrong again here, you should have a look at the profiling its really not that expensive

              Originally posted by vladpetric View Post
              * The language is just too f*ing dynamic. A VM needs to not just optimize, but also be able to de-optimize code. You can make certain assumptions about the class hierarchy, only to be invalidated by a newly-loaded class. This is just an example.
              You are not making a point here

              Originally posted by vladpetric View Post
              * Escape analysis rarely works well. There's a reason why newer languages (Swift, golang) give the developer the option to embed (inline) objects.
              Which is the same reason why Java completely owns swift and Go in benchmarks if you disregard warmup time?

              You do realize that golang has optimized for compile speed over runtime speed? Also Swift uses reference counting which is the slowest way of handling memory (slow than having a GC or managing memory yourself, its what makes Python so slow if you aren't using a library that internally FFI's to C).

              Go's GC is very crude and simple which makes it good for one thing, keeping latency low (although this has been fixed in Java's G1 which lets you trade some throughput for latency).

              Also there is GraalVM which creates native images that reduces the startup time that uses AOT (see https://www.graalvm.org/reference-manual/native-image/)

              Actually to date, apart from Java and OCaml are the only languages (apart from typical C/C++/ASM) to be used in HFT which says something.

              Originally posted by vladpetric View Post
              You can wish for a magical compiler, but it ain't gonna happen. The first thing that limits compilers is the equivalence problem.

              Try working a little bit in an optimizing compiler ...
              You do realize that the equivalence problem effects both VM's and standard compilers right? You should have a read of https://wiki.c2.com/?SufficientlySmartCompiler . There is no such thing as a sufficiently smart compiler, for any given program (regardless if the compiler generates the assembly at compile time or at runtime like the JVM) you can hand write more optimized assembly.

              To note I am saying that the JVM isn't perfect, there are of course drawbacks (the primary ones being memory and warmup time) but your post is kind of fuddy hogwosh to be honest.

              And although Java has its fair share of problems, C++ is frankly a terrible language that is the result of what happens when you put every conceivable solution to a problem inside a blender and you get some weird hideous mutation. The only reason people used C++ is that it was the only language for its niche (a high level memory manged language) however C++ is getting its but kicked lately with Rust.

              Also even though Java has issues, you can just have languages that create JVM bytecode to alleviate these problems (i.e. Scala).
              Last edited by mdedetrich; 28 September 2020, 05:54 AM.

              Comment


              • #17
                Originally posted by Michael_S View Post
                Java launches a VM, loads the standard library, and runs "Hello World!" in 110ms on my machine and uses 39MB of RAM.
                Node launches and runs "Hello World!" in 70 ms on my machine and uses 31MB of RAM.
                Euhm man,

                Code:
                $ time /opt/php73/bin/php hw.php
                Hello world!
                
                real 0m0.033s
                user 0m0.000s
                sys 0m0.003s
                
                $ /usr/bin/time -v /opt/php73/bin/php hw.php
                Hello world!
                Command being timed: "/opt/php73/bin/php hw.php"
                ...
                Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
                ...
                Maximum resident set size (kbytes): 28564
                ...
                Exit status: 0
                28M and 33ms. That's PHP on x86-64 with a whole load of modules compiled in.

                Comment


                • #18
                  Originally posted by Alex/AT View Post
                  Euhm man,

                  Code:
                  $ time /opt/php73/bin/php hw.php
                  Hello world!
                  
                  real 0m0.033s
                  user 0m0.000s
                  sys 0m0.003s
                  
                  $ /usr/bin/time -v /opt/php73/bin/php hw.php
                  Hello world!
                  Command being timed: "/opt/php73/bin/php hw.php"
                  ...
                  Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
                  ...
                  Maximum resident set size (kbytes): 28564
                  ...
                  Exit status: 0
                  28M and 33ms. That's PHP on x86-64 with a whole load of modules compiled in.

                  Code:
                  $ time perl hw.pl
                  Hello World!
                  
                  real 0m0.006s
                  user 0m0.006s
                  sys 0m0.000s
                  
                  $ /usr/bin/time -v perl hw.pl
                  Hello World!
                  Command being timed: "perl hw.pl"
                  ..
                  Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
                  ...
                  Maximum resident set size (kbytes): 5760
                  ...
                  Exit status: 0
                  And "C" hello world runs in 1 ms with 1.3MB of memory. Python 3 is about as fast as your PHP example.
                  I wasn't trying to say that Java was fast, just that it doesn't have much more startup overhead than Node.

                  If low memory overhead and fast startup is critical, then PHP > Java or Node. But Perl > PHP, and C > Perl.

                  Edit: and SBCL Lisp is about as fast as Perl, 6ms. It has a higher memory overhead, though.
                  Last edited by Michael_S; 29 September 2020, 11:51 AM.

                  Comment


                  • #19
                    I have a ton of fun with these performance discussions. But the truth is simple - most of us arguing these things, no matter what side we're on, would be better off spending the same amount of time writing more efficient code in our respective languages of choice. Few people are going to be convinced by vague arguments in a discussion.

                    With respect to "sufficiently smart compilers", smart compiler technology keeps incrementing forward but in my humble opinion at this pace we are many decades away from having non-trivial applications written in Java, Lisp, Python, PHP, Node, etc... run as quickly as equivalent applications written in well-optimized Rust, C++, or C.

                    Comment


                    • #20
                      Originally posted by mdedetrich View Post

                      Generating optimized assembly at runtime is not a bottleneck



                      Wrong again here, you should have a look at the profiling its really not that expensive



                      You are not making a point here



                      Which is the same reason why Java completely owns swift and Go in benchmarks if you disregard warmup time?

                      You do realize that golang has optimized for compile speed over runtime speed? Also Swift uses reference counting which is the slowest way of handling memory (slow than having a GC or managing memory yourself, its what makes Python so slow if you aren't using a library that internally FFI's to C).

                      Go's GC is very crude and simple which makes it good for one thing, keeping latency low (although this has been fixed in Java's G1 which lets you trade some throughput for latency).

                      Also there is GraalVM which creates native images that reduces the startup time that uses AOT (see https://www.graalvm.org/reference-manual/native-image/)

                      Actually to date, apart from Java and OCaml are the only languages (apart from typical C/C++/ASM) to be used in HFT which says something.



                      You do realize that the equivalence problem effects both VM's and standard compilers right? You should have a read of https://wiki.c2.com/?SufficientlySmartCompiler . There is no such thing as a sufficiently smart compiler, for any given program (regardless if the compiler generates the assembly at compile time or at runtime like the JVM) you can hand write more optimized assembly.

                      To note I am saying that the JVM isn't perfect, there are of course drawbacks (the primary ones being memory and warmup time) but your post is kind of fuddy hogwosh to be honest.

                      And although Java has its fair share of problems, C++ is frankly a terrible language that is the result of what happens when you put every conceivable solution to a problem inside a blender and you get some weird hideous mutation. The only reason people used C++ is that it was the only language for its niche (a high level memory manged language) however C++ is getting its but kicked lately with Rust.

                      Also even though Java has issues, you can just have languages that create JVM bytecode to alleviate these problems (i.e. Scala).
                      I think you know enough stuff to have an opinion, but not enough to realize that it's primarily party line ideology.

                      Have you ever worked on a compiler pass?

                      Anyway, the problem with a JIT - when compilation time becomes running time - does not stem from assembly generation. That is primarily one (or a maybe couple) of passes. But you do a couple dozen other passes before that for optimization (in gcc the total number of passes is above 100, though in llvm it's lower than that).

                      With respect to unoptimizing/deoptimizing - it's absolutely a real thing. You should have read the classic Jalapeno paper https://ieeexplore.ieee.org/document/5387060 . In C++ you don't need to worry about that, but in Java you do.

                      With respect to the language being too dynamic - let me give you another example: having all methods virtual by default is a bad idea for correctness as well (I'd much rather have virtual methods explicit, and the compiler warn on non-explicit override).

                      With respect to profiling - the Hotspot-derived JVMs don't do profiling of active, optimized code (or continuous profiling). What they do is lazy compilation - they start by interpreting code, while keeping counters for the basic blocks encountered. Once a basic block reaches a certain threshold, the whole method is compiled. The problem is - that's it, there's no continuous profiling in Hotspot-derived JVMs of the optimized code (it's really easy to prove me wrong here though - pointer to code that does it).

                      The point about Swift and Golang, both languages that are much much younger than Java, and not nearly as performance tuned, is that they allow for more flexible memory management - for instance, you can both use links (references) and inline the data. As a developer it's really useful to have that choice, and it's a bad idea to leave that task to the compiler. (Again, it would be good if language designers stopped treating the compiler like a sewer system). As far as speed is concern, right now Swift is actually reasonably fast except for three benchmarks here (and for two of them, I'd suspect that the swift standard library is slow):



                      Given your tone you seem to be part of the Make Java Great Again! party.

                      Comment

                      Working...
                      X