News for hackers. Stuff that matters.
Re:JITs are un-ergonomic by banachtarski on Sunday March 29, 2020 @12:10AM (#22716329)
This article has a number of issues. JS with JIT is waaay faster than Python. Not “between python and java” as purported. Second, generalizing jits as “un-ergonomic” seems silly given that what’s being specifically looked at is benchmarking. But what makes this claim ridiculous is that nothing is easy to benchmark. Even native code is hard to profile and this is literally my day job. If the JIT makes your code that much faster, this strikes me as a pretty suspect complaint
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @12:14AM (#22716346)
I think that by “between python and java” they meant “faster than python and slower than java”. I think Java still beats JS unless you get lucky.

You’re totally right that benchmarking and profiling is hard even for native code. I think this post fetishizes whether or not a piece of code got JITed a little too much. Maybe the author had a bad time with microbenchmarks. There’s this anti pattern in the JS world to extract a small code sample into a loop and see how fast it goes - something that C perf hackers usually know not to do. That tactic proves especially misleading in a JIT since JITs salivate at the sight of loops.

Re:JITs are un-ergonomic by Skunkleton on Sunday March 29, 2020 @01:54AM (#22716766)
> I think that by “between python and java” they meant “faster than python and slower than java”. I think Java still beats JS unless you get lucky.

Yeah, that is what they meant, but it is a little misleading. Javascript's performance is usually within a single digit multiple of java's, whereas python is often significantly slower. Javascript is somewhere between Java and an abacus too.

Re:JITs are un-ergonomic by shawnz on Sunday March 29, 2020 @12:26AM (#22716413)
That still doesn't make sense to me.. how can JIT in general be slower than Java when Java is JITed?
Re:JITs are un-ergonomic by ridiculous_fish on Sunday March 29, 2020 @03:12AM (#22717020)
The peer comment about static typing is correct, but there's more, err, flavor to be enjoyed in the challenges of JITing JS. Here's some deopt scenarios to keep you up at night.

To whet your appetite, what happens if you redefine Math.round? Java prohibits this for obvious reasons, but a JS joker may write:

    Math.round = () => Infinity;
JS engines really do inline Math.round, and must be prepared for this nonsense.

It gets worse. Maybe you check for a property which is usually not found:

    if (!val.uuid)
       val.uuid = uuidgen();
Hidden classes can almost reduce this to a pointer comparison. But what if someone adds a uuid property on Object.prototype? Every check is busted! v8 handles this with "validity cells", and it's ugly, requiring that every object know about every object which "inherits" from it.

Now if you are a monster you may choose to write:

    Object.defineProperty(Array.prototype, "42", {value: "lol"});
    console.log([][42]); // yes it prints "lol"
Every array gets a default value for 42. Think about how you would JIT numeric code in such an environment...
Re:JITs are un-ergonomic by progval on Sunday March 29, 2020 @03:46AM (#22717158)
Python suffers the same issue. There's some discussion about dealing with it in this PEP and the pages it links: https://www.python.org/dev/peps/pep-0509/
Re:JITs are un-ergonomic by The_Colonel on Sunday March 29, 2020 @08:51AM (#22718574)
Python does not seem to be even trying to be competitive in performance though so it's less of an issue for them.
Re:JITs are un-ergonomic by progval on Sunday March 29, 2020 @09:33AM (#22718873)
They do, it's just not a priority. The PEP I linked (as well as most of the work of its author, Victor Stinner, in the last years) are motivated by JITing.

There's also the "frame evaluation API" PEP [1], whose purpose is to allow pluggable evaluators in CPython without forking the entire interpreter, like Unladen Swallow had to.

[1]: https://www.python.org/dev/peps/pep-0523/

Re:JITs are un-ergonomic by divs1210 on Sunday March 29, 2020 @10:45AM (#22719405)
Python is orders of magnitude slower than JS, though. It has the same problems, but doesn't even try solving most. PyPy would be a better VM to compare against.
Re:JITs are un-ergonomic by tomp on Sunday March 29, 2020 @11:26AM (#22719742)
Java deals with almost exactly the same issue. If you define an interface and a single implementing class, the code will be compiled to always call that classes method, and the deoptimized / recompiled if you load another class that implements that interface. JS could deal with these issues in a similar manner.
Re:JITs are un-ergonomic by vbezhenar on Sunday March 29, 2020 @11:34AM (#22719809)
You can redefine Math.round. It's an ordinary method from rt.jar. You can change rt.jar or you can redefine it with java agent.

Not as straightforward as with JS, but Java JIT still have to account for those things.

May be it will assume some things about standard classes for optimization, but for user classes that will be true anyway.

Re:JITs are un-ergonomic by ridiculous_fish on Tuesday March 31, 2020 @10:15PM (#22744951)
You can really redefine an existing Java method at runtime? Well TIL!
Re:JITs are un-ergonomic by seanmcdirmid on Sunday March 29, 2020 @12:45AM (#22716492)
The Java JIT has static type information to work with, the JS JIT can only infer type information via heroic efforts. Static types do mean something, especially when working with primitives and other unboxed data types.
Re:JITs are un-ergonomic by erik_seaberg on Sunday March 29, 2020 @01:01AM (#22716559)
This. Javascript engines have to do stuff like https://mathiasbynens.be/notes/shapes-ics to assume many objects will have the same key names and types and create an optimized class layout, with some kind of expensive fallback if anyone ever randomly stores a key or value that violates the assumption. They can't even be sure you'll always be doing integer math (unless you resort to bit masking a la asm.js). Hinting (like __slots__ in Python) might have helped some.
Re:JITs are un-ergonomic by discreteevent on Sunday March 29, 2020 @10:53AM (#22719468)
This was one of the main motivations for writing dart. The V8 implementers were tired of having to write these kinds of hacks. Even though dart was initially a dynamically typed language, the shape of the objects was stable.
Re:JITs are un-ergonomic by masklinn on Sunday March 29, 2020 @09:34AM (#22718882)
> The Java JIT has static type information to work with

I don't know that the java JIT has type feedback. However regardless Java being statically typed means Java code is structurally closer to what a JIT wants and can analyse, it's much more difficult (and thus rarer) to fuck around with types and objects generated on the fly at runtime for instance, you're not going to add new attributes to an instance whereas that's just tuesday in javascript.

Re:JITs are un-ergonomic by titzer on Sunday March 29, 2020 @09:42AM (#22718921)
Java JITs definitely do have type feedback. They profile the types of objects at virtual call sites and do guarded inlining, as well as removing expensive interface casts, etc. The JVM doesn't really have a distinction between classes generated on the fly and those that were on disk, as they all go through a classloader anyway. JVMs, for the most part, blow their brains out at the end of the day and start with zero the next VM run.
Re:JITs are un-ergonomic by pcr910303 on Sunday March 29, 2020 @03:55AM (#22717193)
Well, you're right that JS JITs can only infer type information via heroic efforts, but AFAIK the Java compiler throws away any type information from the source code, which means that the JVM JIT needs to inver type information again from the byte code.

Still, the JVM JIT is faster than JS due to reasons explained in the sibling comment of the parent one.

Re:JITs are un-ergonomic by imtringued on Sunday March 29, 2020 @09:23AM (#22718783)
Java is only throwing generic type information away in the declaration of classes and methods. The code that is accessing generic types is compiled with casts to the expected type. List<String>.get(1) will generate a cast to String therefore nothing is actually missing in the generated code. It is only missing when you use reflection to e.g. deserialize a List via Jackson by passing List<String>.class. That unfortunately won't work because the generic type parameter is not part of the declaration, only the generated code.
Re:JITs are un-ergonomic by pdpi on Sunday March 29, 2020 @05:03AM (#22717429)
> but AFAIK the Java compiler throws away any type information from the source code

You're thinking about generics. .class files preserve a whole bunch of type information (I'm building a .class decompiler in my free time, and I'm looking at that very same data in my debugger ATM).

Re:JITs are un-ergonomic by The_Colonel on Sunday March 29, 2020 @08:56AM (#22718605)
You probably know this, but it's not obvious to the random reader.

Even generic types are available in the Java .class file and are accessible from the reflection API. Spring for example uses this quite heavily.

Re:JITs are un-ergonomic by cogman10 on Sunday March 29, 2020 @09:15AM (#22718720)
It depends on where you are at.

Type information is present in fields and class inheritance

For example, a class like this

`class Foo implements Bar<String>`

Retains the fact that the generic type is a String.

That information is completely lost at method invocation. So a method that takes a `Bar<String>` ultimately compiles to a method that takes a `Bar` and knows nothing of the String.

To get that generic information down you have to engage in some fun tricks using either the class or field method I mentioned earlier. (Usually you do this with a second type parameter where it matters).

Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @09:27AM (#22718819)
Java JITs don’t throw away type information. The bytecode carries strong types, though you have to do some work to get them out (some abstract interpretation). But that’s something you can do statically; no need for profiling or speculation.

In JS you can only get the types by profiling.

Re:JITs are un-ergonomic by titzer on Sunday March 29, 2020 @09:43AM (#22718933)
Generics are erased in Java. Not so in the CLR.
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @10:23AM (#22719203)
Yeah but the thread is about types, not generic types specifically.

Also it’s not really true that genetics are erased. There’s that horrible thing javac does so that the VM can support reflection for generics. I get your point though.

Re:JITs are un-ergonomic by titzer on Sunday March 29, 2020 @10:34PM (#22724703)
Do you mean the passing of classes as additional arguments? I haven't seen the horrible thing.

Overall I think C# got this one right. Generics are right there in the binaries.

bUt ActuALLy, I think the rightest right thing is to do specialization up to representation at link time (or compile time), when the whole program is available, ala MLton. Virgil does this. Of course this is not possible in a dynamic code loading environment but I only have so many fucks to give in this life.

Re:JITs are un-ergonomic by pizlonator on Monday March 30, 2020 @12:13AM (#22725182)
No, I meant that the Class format has metadata about what the genetics were so some java.lang.reflect thing can query about what the genetic type was. I don’t think it comes with soundness guarantees.

I agree C# got this right.

I agree that doing specialization up to link time is ideal from a certain standpoint.

Re:JITs are un-ergonomic by username90 on Sunday March 29, 2020 @10:54AM (#22719472)
All generics in Java are of type Object from the start, you can't call any methods on them not implemented by Object. So it is wrong to say they are erased, they were never there to start with.
Re:JITs are un-ergonomic by titzer on Sunday March 29, 2020 @04:46PM (#22722570)
You can add a constraint to a generic declaration, which is an upper (or lower) bound on the allowable type arguments.

e.g.

  class A<Y extends X> {
    // in this scope, Y is known to be of at least type X,
    // so, we can call methods on expressions of type Y
    // that belong to type X (and not Object)
    Y m() { ... }
  }
Type arguments are omitted from usage sites. The technique is literally called erasure in papers and documentation.

  a = new A<Foo>();
  f = a.m(); // should return a Foo, in bytecode returns Y
             // and compiler inserts a cast from Y -> Foo
Generic code is slower in Java because of these extra casts. To get back (most of) the performance, the JVM has to inline enough methods to be able to track the types from start to finish. It can't always.
Re:JITs are un-ergonomic by vbezhenar on Sunday March 29, 2020 @11:44AM (#22719883)
And that's why Java is slower than it could be. If I'm using String[] array, it can't contain anything but String objects, so JVM does not have to check type everytime I'm accessing that array. That's not true for ArrayList<String>, where compiler must check returned object type from `get(index)` (because it really is Object and can contain anything), but it could be true with better language design.
Re:JITs are un-ergonomic by BorisTheBrave on Sunday March 29, 2020 @04:17AM (#22717263)
This is not true, bytecode stores fields and classes as fully qualified strings: https://stackoverflow.com/a/17406592
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @01:38AM (#22716708)
Yeah what you said.
Re:JITs are un-ergonomic by raverbashing on Sunday March 29, 2020 @03:09AM (#22717001)
You're not wrong, but I always wonder how the verbosity and crazy class hierarchy of Java code doesn't make things slower.

I know that compilers are smart, but the API doesn't make things easier at all

Re:JITs are un-ergonomic by pdpi on Sunday March 29, 2020 @05:04AM (#22717435)
The Java standard library isn't particularly verbose or insane. It's the "enterprise java" world that deals with the sort of excesses you're thinking about.
Re:JITs are un-ergonomic by bosswipe on Sunday March 29, 2020 @03:13AM (#22717034)
Verbosity makes the programmer slower not the program.
Re:JITs are un-ergonomic by dgoldstein0 on Sunday March 29, 2020 @04:39AM (#22717338)
It depends. For example, you can verbosely write a loop to copy data from one array to another, or you can use memcpy. The later is typically implemented as hand optimised assembly - it's a pretty small number of operations in x86_64. The former - maybe the compiler optimizes, maybe it doesn't. If it does optimize it, it's definitely more complexity in the compiler and slows it down.

In general having some higher level, well optimized helpers can certainly reduce verbosity and increase speed. That said, some types of verbosity just make the programmer write what the compiler would translate to anyway. Or can end up being unnecessary - e.g. a strongly typed language with no inference certain slows the programmer with no effect on the program (though maybe an effect on the type checker).

Re:JITs are un-ergonomic by im3w1l on Sunday March 29, 2020 @09:27AM (#22718817)
A fast memcpy used to be complicated to implement but these days I heard a simple

    rep movsb
will do the trick. This assumes that the source register points to source, destination register points to destination and counter register is set to number of bytes to copy.
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @03:25PM (#22721835)
I wish that was true but my data says it isn't:

- A verbose SIMD copy loop is often faster even on modern Intel CPUs that have the more modern rep implementation.

- A simple byte copy loop will beat both SIMD and rep when you're copying smaller amounts at a time.

Re:JITs are un-ergonomic by raverbashing on Sunday March 29, 2020 @04:12AM (#22717246)
Yes I understand some verbosity is structural and won't change anything, for example

SomeClass x = new SomeClass();

won't make anything slower (ignoring auto for now)

Now, I read Java code and I can't help but wonder how things are harder

For example, setters and getters, what would be a simple memory write becomes a function call. Not complaining when you actually need it.

Reading the examples here (and those are not too bad) https://developer.android.com/reference/java/net/HttpURLConn... it seems you have to actually fight the API to get anything done

Why do you need to cast the return of a url.openConnection() to a HttpURLConnection? (I mean, how many connection types exist?)

Re:JITs are un-ergonomic by pgrulich on Sunday March 29, 2020 @04:56AM (#22717403)
So for getters and setters a Jit can inline the function call and in the end you have a direct memory access. In your example you have to cast because URLConnection could be a HttpURLConnection or JarURLConnection. But again a good Jit would speculate that it is always a HttpURLConnection and deoptimize if not.
Re:JITs are un-ergonomic by imtringued on Sunday March 29, 2020 @09:29AM (#22718843)
The JVM also has full information about the class hierarchy at runtime. If you add a class that overrides a function it will deoptimize that overriden function to a virtual function but otherwise the JVM will just treat it as a static function and inline it if necessary.
Re:JITs are un-ergonomic by vips7L on Sunday March 29, 2020 @12:19PM (#22720182)
In modern Java I don't see why you would directly use an HttpURLConnection. The stdlib provides an easy to use HttpClient.

https://docs.oracle.com/en/java/javase/11/docs/api/java.net....

Re:JITs are un-ergonomic by gnosek on Sunday March 29, 2020 @05:15AM (#22717484)
> I mean, how many connection types exist?

Two? https://developer.android.com/reference/java/net/URLConnecti...

Re:JITs are un-ergonomic by kevingadd on Sunday March 29, 2020 @01:24AM (#22716664)
The design of JavaScript is not very friendly to high performance. Even though Java is itself not easy to generate efficient code from, producing efficient code from JavaScript is far more difficult.
Re:JITs are un-ergonomic by throwaway894345 on Sunday March 29, 2020 @12:28AM (#22716422)
The claim wasn’t about JIT in general, but rather about JS.
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @01:48AM (#22716743)
Then it’s problematic to be so JS and V8 centric. Also the post specifically talked about JS being faster than Python and slower than Java so that’s what this thread is about.
Re:JITs are un-ergonomic by throwaway894345 on Sunday March 29, 2020 @10:15AM (#22719151)
I’m not advocating for the post or anything else, I was just clarifying a misunderstanding.
Re:JITs are un-ergonomic by imtringued on Sunday March 29, 2020 @09:05AM (#22718671)
That was not a general statement about Javascript performance. The entire article is about the unpredictability of the JIT. When the JIT hits a bad codepath then it really does perform like python or when it hits a good code path (most of the time) then it performs like java. This unpredictability is what is causing the issues, not the general performance.
Re:JITs are un-ergonomic by j88439h84 on Sunday March 29, 2020 @12:24AM (#22716402)
Pypy JIT is way faster than CPython
Re:JITs are un-ergonomic by throwaway894345 on Sunday March 29, 2020 @12:31AM (#22716435)
It is, but that’s not saying a lot and it’s still far far slower than Go/Java/C#, and it also isn’t compatible with lots of existing Python code. Such as anything that would like to talk to a Postgres database. Pypy is great, but it can’t fix a broken ecosystem and general lack of leadership in the Python community. :(

(Broken ecosystem = lots of things don’t work with lots of other things; package managers are another example; Mypy another)

Re:JITs are un-ergonomic by aeyes on Sunday March 29, 2020 @12:36AM (#22716454)
What's the problem with Postgres on PyPy? Running fine in production here.
Re:JITs are un-ergonomic by throwaway894345 on Sunday March 29, 2020 @01:29AM (#22716677)
There are no supported drivers for it as far as I could find. The common answer is to use psycopg2cffi, but that hasn’t had a commit in like 4 years. The alternatives I could find were in the same shape or worse.
Re:JITs are un-ergonomic by anarazel on Sunday March 29, 2020 @08:30PM (#22724093)
There's a few pure python drivers. Check https://wiki.postgresql.org/wiki/Python and https://wiki.python.org/moin/PostgreSQL

E.g. pg8000 looks like it's being maintained?

Re:JITs are un-ergonomic by throwaway894345 on Monday March 30, 2020 @02:19PM (#22730641)
I recall looking at pg8000 in particular, but it didn't inspire confidence for our production use case. It had only 20 commits in 2019 and fewer than 100 stars. I also didn't have a good understanding of the performance tradeoffs (pypy/pg8000 vs C library).
Re:JITs are un-ergonomic by j88439h84 on Sunday March 29, 2020 @01:19PM (#22720699)
Poetry and mypy are fine. Postgres works on pypy. But generally.. yeah you're right.
Re:JITs are un-ergonomic by throwaway894345 on Monday March 30, 2020 @02:33PM (#22730775)
My experience with Mypy has not been pleasant. It doesn't work with a whole host of packages including zip packages (PEP 441) or those that aren't built for Mypy directly (you have to sprinkle empty .pytyped files in various places in your project IIRC or mypy will ignore the type hints you provide; I ran into this with the `black` package. Further, getting it to find installed packages is tremendously difficult--it generally just fails with "couldn't find package" or something similarly useless and the docs it links you to are not helpful in my experience. Mypy also barfs on recursive types, so you can't express things like JSON, nor can you constrain generic types based on protocols.

Similarly, Postgres doesn't work for Pypy unless you're willing to use libraries that are unmaintained or only very lightly maintained, and even then who knows what the performance tradeoffs will be. Those are pretty substantial caveats for a production use case.

I haven't used Poetry, but I've heard good things. I'm very cautious though, because I've also heard high praise about pip/virtualenv, pip-tools, pipenv, etc and every single one had spectacular problems on the happy path (30 minutes to resolve dependencies with pipenv is my favorite).

Re:JITs are un-ergonomic by j88439h84 on Tuesday March 31, 2020 @03:00AM (#22735463)
> who knows what the performance tradeoffs will be

Sure that's true, but performance is about measurement.

Poetry has some missing pieces still (I can list them if you're interested but I'm on my phone) but it's the first time I've felt ok recommending a packaging tool to beginners. The experience is way better than the alternatives like pipenv.

Re:JITs are un-ergonomic by throwaway894345 on Tuesday March 31, 2020 @04:05PM (#22741896)
> Sure that's true, but performance is about measurement.

I have a very low degree of confidence that a pure Python solution (even JIT optimized) is going to compete with a native solution, not to mention that by all appearances it isn't sufficiently well-supported to meet our criteria. Measuring the performance for me feels like a waste of time; it's easier just to forego Pypy until the ecosystem matures.

> Poetry has some missing pieces still (I can list them if you're interested but I'm on my phone) but it's the first time I've felt ok recommending a packaging tool to beginners. The experience is way better than the alternatives like pipenv.

This is good to know. I'll have to give it a try.

Re:JITs are un-ergonomic by fnord123 on Sunday March 29, 2020 @01:19AM (#22716638)
>JS with JIT is waaay faster than Python. Not “between python and java” as purported.

You are correct that JS is not between Python and Java. Python is faster than Java which is faster than JS. Though some people seem to think calling APIs written in C is "not Python" but if the ecosystem provides the library and I call it from Python then it's Python enough for me!

Re:JITs are un-ergonomic by gbear605 on Sunday March 29, 2020 @01:35AM (#22716697)
By that logic, Python, Javascript, and Java are all the same speed, just call out to C, or assembly perhaps if you really want to tune some code.
Re:JITs are un-ergonomic by fnord123 on Sunday March 29, 2020 @01:39AM (#22716712)
No, not at all. Java FFI is extremely expensive.
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @02:01AM (#22716785)
Yeah. And so is JS’s. I think CPython’s design makes it a champ at native interop and a loser at pure compute perf. That’s a valid trade off for lots of important situations.
Re:JITs are un-ergonomic by frankpf on Sunday March 29, 2020 @02:34AM (#22716883)
Are you referring to V8's/Node's C FFI? Why is that extremely expensive?
Re:JITs are un-ergonomic by smabie on Sunday March 29, 2020 @03:35AM (#22717107)
It's not a trade-off. There's no reason why you can't have a blazing fast and expressive language that also has good C FFI. A single good programmer could make a language that was as expressive as Python (that is, not very), faster, and with a good C FFI in under 6 months.
Re:JITs are un-ergonomic by pizlonator on Sunday March 29, 2020 @09:24AM (#22718793)
You couldn’t be more wrong. Java and JS have expensive FFI because of the specific costs of synchronizing the VM entry/exit with the GC and JITs.
Re:JITs are un-ergonomic by progval on Sunday March 29, 2020 @03:52AM (#22717181)
Aren't you saying it's possible to make a perfect language with no tradeoff, and all that in just 6 months?
Re:JITs are un-ergonomic by smabie on Sunday March 29, 2020 @04:09AM (#22717236)
No I'm saying it's easy to make a language better than Python in six months.
Re:JITs are un-ergonomic by fnord123 on Sunday March 29, 2020 @05:47AM (#22717621)
Then where is it?
Re:JITs are un-ergonomic by smabie on Sunday March 29, 2020 @03:31AM (#22717092)
What you're implying is that the "speed" of a language is purely defined by the speed of the C FFI? This view is absolutely ridiculous and I don't think you would find a single other programmer on this green earth that would agree with you.
Re:JITs are un-ergonomic by fnord123 on Sunday March 29, 2020 @05:46AM (#22717618)
I think everyone agrees that when they want to do some data analysis they pip install numpy and get to work. It's only the navel gazers who are concerned about cpythons performance instead of treating python as a 'race to C' wherever performance is concerned.

Get used to this approach since it crops up everywhere. If you target a gpu, you try to keep the work in the gpu. When we move to use bpf and io_uring things will be a race to the next kernel program. If you target the CPU then your code is a race to C or a race to the function that calls the relevant cpu instruction that will make your code fly.