10 ms·
Why git is so fast (or why Java is not as fast as C)
- houseabsolute 17y agoOne thing I have been wondering as a non-git user: is git really CPU-bound in most operations? Maybe someone who is a regular git user can answer me this question. If it's not, I wouldn't expect Java to matter too much to its performance.
- mhansen 17y agoGood article, but it seems to ignore the elephant in the room: the JVM's cold start times. For me, git's use case is being called from the command line, often interactively, between code editing sessions. It needs to start fast and finish fast, to not interrupt my workflow. The JVM's cold start times are huge. On the order of a second. Noticeably slow. So slow, that in the common case of committing a few files, the JVM startup time would totally dwarf the time spent actually doing work.
- strlen 17y agoThe point of JGit was to provide a Git plugin for Eclipse. In this case the start-time is "outsourced" to Eclipse. Seems like there are many other potential uses for this: other Java IDEs, web applications, integration into Java SCM tools - places where Git would be very useful and start-time can be neglected.
- jorgeortiz85 17y agoJGit isn't meant to be a replacement for git on the command-line. It's meant to be used inside IDEs and web servers that 1) are already running on a JVM, 2) need to interact with git, and 3) don't want to pay JNI costs. JVM start-up times are a non-issue for these use cases.
- DarkShikari 17y agoIs the cost of JNI really that high? I'm curious--I haven't used it myself, but a client of mine is using it in a very latency-sensitive Java applet that uses JNI to call libavcodec to decode a video stream and then immediately display it through Java's own native libraries, so I would think the cost isn't that high.
- mey 17y agoThe real cost of JNI is when you hotspot crash and take out the entire JVM instance (say your servlet and all your Tomcat instance as well) I don't like anything calling out to JNI unless it's the only sane way and it's been heavily tested.
- 10ren 17y agoRun the java app as a server. I did this with javac, and went from 5000ms (ant) to 200ms (averages). It gets faster each time it runs, enormous speedup after the first run; but still very significant for the next 10; and continuing at a slower rate from then on. The client needs to be non-java, to avoid the startup cost there. I run it as a console, so that is the "client" (wrapped in rlwrap, for filename completion/editing etc). My workflow is to compile in a separate shell; that's why I did it this way.
- berntb 17y agoDisclaimer: I'm very much not a Java/C# guy, so this might be totally barking up the wrong tree. :-) Would it be a speed win to keep some JVM processes "half-started" if load and memory use allowed? The next started Java app will use one of the already half started JVMs. You wouldn't need to do anything fancy to keep the JVMs around; if a half-started JVM wasn't used for so many seconds that it might be swapped out, you half-start another JVM and throw away the timed out one. (Hmm.. I don't remember, but another process could take over stdin/-out/-err? Or you could just limit this to non-console applications.) How much of the work time is in initializing the JVM and how much is specific for initializing the application? Could the JVM data structures (JIT etc) for an app be cached between runs? Edit: Made a little clearer. Moved disclaimer to the top, so people know they can stop reading if I'm in the wrong forest.. Edit 2: I probably have read and unconsciously copied a similar idea that some Perl guy implemented?
- pronoiac 17y agoApache in pre-forking mode might have inspired you. High availability Java might be relevant.
- jwinter 17y agoCheck out nailgun if you're interested in using the JVM as a command-line tool without a cold-start. http://martiansoftware.com/nailgun/index.html http://martiansoftware.com/nailgun/index.html
- dschobel 17y agoI was looking at this the other day and am concerned that it hasn't been updated since February, 2005. That's practically ancient in terms of software.
- zaphar 17y agoand yet it functions perfectly with no problems when I use it in the VimClojure plugin. Tex hasn't been "updated" in ages either yet its fully functional. Sometimes software is just done and no further activity is needed. Judge it on whether it works not the date of the last commit.
- dschobel 17y agoWell as the github repo posted above you attests, there are (unsurprisingly) some non-trivial bugs in the last official release. Unmaintained code is just not something I would ever use in a production capacity/rely on for my daily work. Especially considering the changes which have come to java and the jvm since 2005.
- jwinter 17y agoThis looks unofficial, but Github has a version that has updates over the past few years: http://github.com/ato/nailgun/tree/master/nailgun/ http://github.com/ato/nailgun/tree/master/nailgun/
- DarkShikari 17y agoThis has always been true and will continue to be true. It's possible to build a high level language that's as fast as C? Sure--but only if you restrict the programmer to the same amount of effort in both languages. If your application is one where it's worthwhile applying a great deal of extra programmer time in order to improve performance, a low level language will always win because it exposes more of the native machine. The goal of a high-performance high-level language should be to provide C-like performance for a reasonably unoptimized application. Once one starts to optimize a program down to the last instruction, staying on par with a low level language becomes simply impossible for a high level language. In my experience, every level of abstraction one creates away from the machine limits your performance by some amount. This can be demonstrated without even leaving assembly language! Fastest possible: raw assembly code in a NASM-like assembler. With this, you can write basically any code possible with no limitations, at the cost of extremely high programmer time costs. Shortcut: Use inline assembler instead of NASM to simplify calling convention and other niceties. Cost: There's now a whole bunch of stuff, like calling convention optimization and computed jumps, which you can no longer do. Shortcut: Use compiler intrinsics instead of raw assembly. Cost: You can no longer tweak your algorithm to minimize register spills because you aren't directly controlling spills anymore. Shortcut: Use a set of macros (like my project does) for handling calling convention, MMX/SSE abstraction, and other such simplifications. Cost: You tend to overlook optimizations that apply to one possible output of the abstraction and not others, resulting in either messes of ifdefs or suboptimal code--the former of which is of course violating the abstraction. Shortcut: Use a framework like liboil to write SIMD assembly instead of native code. Cost: By using generic SIMD operators, you lose access to specialized architecture-specific operations, along with the aforementioned issue of register spills. Here we haven't even gotten beyond assembler and we're already losing performance. Now scale this up to C and beyond: abstraction inherently comes at a performance cost. It isn't even merely a function of language: abstractions within a language reduce performance as well.
- Locke1689 17y agoCouldn't agree more. One thing to remember though: "Premature optimization is the root of all evil." C Git is optimized and fast. Mercurial, with a combination of Python and C, is almost as fast. Maybe not quite as fast, but fast enough for me. A lot of the time those optimizations just don't pay off in terms of programmer time.
- barrkel 17y agoI find it interesting to read that every single one of his criticisms of JGit would not need to apply to a C# implementation. Unsigned types, unmanaged memory allocation (Marshal.Alloc), unsafe code with pointers, native P/Invoke access, value types (e.g. fixed arrays for his SHA-1 point), and an IDisposable convention for managing all the unmanaged trickery, C# has pretty much all the needed features. When optimizing C# for space use in particular (which ends up being a time optimization for I/O heavy loads), I've leaned heavily on arrays of structs, and even bit-packed arrays (e.g. an Int32 array storing 14-bit integers, packed so that they don't align on index boundaries). Programming at the level of C in C# loses most of the benefits, of course, but at least you can hide the optimizations behind pretty APIs, and write the non-critical parts in terms of an easier to work with lower layer.
- j_baker 17y agoI actually believe they're accessible in Java as well through JNI and JNA. But I'm hardly a Java expert.
- barrkel 17y agoNot at the same level of abstraction, IMO. To take a representative example, pointer arithmetic simply isn't really available to you from Java, unless you pretend your integers are pointers and go through JNI functions for indirection, etc., which is going to be slow enough to defeat the purpose.
- thibaut_barrere 17y agoFrom the last line: "But, JGit performs reasonably well; well enough that we use internally at Google as a git server." Rings the 'good enough' bell to me.
- axod 17y agoAgree. If your bottleneck is your source control tool, you're doing something wrong.
- DougBTX 17y agoDiscussing bottlenecks oversimplifies, it assumes everything goes down one pipeline. Small changes can make big differences. If your tool feels a little bit snappier, you might make two commits instead of one, then six months down the line someone saves half an hour tracking down a bug because the blame messages are more relevant.
- JulianMorrison 17y agoSpeed changes your workflow. With slow or fussy source control, you're more likely to do "branches" by just not checking in your changes for awhile. With near-instant source control, you don't feel burdened by making a feature branch, switching, editing and committing a few times, and merging back.
- axod 17y agoTrue, I don't really like using branching/merging as a workflow unless absolutely necessary. So sure, if you're constantly branching and merging all day, then I can see it being a problem. But I'm not convinced branching+merging is really good for your productivity. The other point is that with a distributed system like git, all of the load is on your local machine. With a centralized system like subversion, the server could do the heavy lifting (Wether this happens in practice is another matter). My point is, if you want lightening fast rev control for some reason, probably better to not use distributed.
- 17y ago
- axod 17y ago>> "why Java is not as fast as C" Not actually true in reality. Modern JVMs can make on the fly optimizations based on the runtime profile, which would need to be done by hand in C. As said elsewhere though, Java excels when used for long running tasks - servers - backends etc where it can optimize for the long term. It doesn't excel when you try and start up the jvm loads of times for quick individual jobs. I don't understand why people are optimizing source control :/ fast vs fast meh I don't think it's an issue really.
- fauigerzigerk 17y agoThe post specifically mentiones Java's implementation of memory mapped files, Java's lack of value types and Java's lack of unsigned types. These are very different areas but none of them can be solved by on the fly optimizations or longer running processes.
- riffraff 17y agowrt value types, shouldn't it be partially solved by escape analisys? Cfr: http://weblogs.java.net/blog/forax/archive/2009/10/06/jdk7-do-escape-analysis-default http://weblogs.java.net/blog/forax/archive/2009/10/06/jdk7-d... not that it would matter much in the case anyway, I guess.
- fauigerzigerk 17y agoYes I think you're right that it should help a little in some cases. But the big issue with the lack of value types is memory usage (not in the case of jGit), which isn't solved by escape analysis.
- richardw 17y ago'Modern JVMs can make on the fly optimizations based on the runtime profile' That's something I've heard ever since hotspot came out, but it's not a silver bullet to beating C/C++ etc. Here are some server tests. Some are comparable, some are definitely not: http://shootout.alioth.debian.org/u64q/java.php http://shootout.alioth.debian.org/u64q/java.php
- richardw 17y agoWhile I'd never claim Java is comparable to C, I'd like to note that the C codebase has, by their admission, 4 years of work in it. I'd be surprised if the JGit codebase isn't much faster in 3/4 years.
- bad_user 17y agoThe Git codebase has been heavily-optimized from the start. Its speed when branching/merging was its main selling point, ever since Linus started talking about it. The only way JGit would ever be equal-to or faster than Git is by using better algorithms. And somehow, I don't see this happening ;)
- richardw 17y agoNobody's claiming equal-to or faster - currently JGit is twice as slow so there's a lot of room for improvement. Faster than now, not faster than C.
- ajross 17y agoThe linked article actually shows quite a few non-trivial optimizations already being done in JGit (e.g. storing an SHA-1 in 5 ints to avoid the extra heap block). I'd be surprised if they got much farther than they are, honestly.
- fauigerzigerk 17y agoOf the three issues mentioned in the post Java's lack of value types is the important one in my view. That's what causes Java programs to use hugely more memory than C, C++, C# or Go programs. Using more memory translates into an orders of magnitude drop in performance for memory intensive applications.
- bad_user 17y agoNot only memory, but there's also a performance penalty related to boxing/unboxing of primitives. That's why the author of that email described how he hasn't used the standard data-structures from Java, like HashMap ... preferring to write his own specialized implementation.
- jrockway 17y agoThey use the word "high-level languages" and then use Java as the example. This is going to lead to some very wrong conclusions; the problems listed in the article are problems with Java, not problems with high-level languages. I imagine a Git-in-Haskell would be very close in performance to the C git. (Then why is Darcs so slow? Because it uses an icky imperative, mutable model, whereas git uses a immutable functional model.)
- j_baker 17y agoIn strictly language terms, C will always be faster than Java. However, I would dispute that one could say on a general basis that C programs will always be faster than Java programs. In fact, I would argue that all things being equal, the Java program is more likely to be faster (and yes, I realize there are a metric ton of potential caveats to what I just said). Why? Because Java allows you to focus on the "big picture" optimizations that really make all the difference. On the other hand, given an infinite amount of development time and experienced developers, the C program will likely be much faster. In some cases this is necessary. But for most cases, I personally would rather just ship something than try to squeeze every ounce of efficiency out of it.
- ErrantX 17y agoIm not wholly convinced that version control is an area where microsecond speed advantages matter. Rather versatility, portability and compatibility :)