Hacker News new | past | comments | ask | show | jobs | submit login
Faster than C? Parsing binary data in JavaScript. (github.com/felixge)
219 points by tuxychandru on Oct 7, 2012 | hide | past | favorite | 172 comments



I am extremely doubtful that optimized C is going to be equally performant as optimized JavaScript. There is innate overhead when using an interpreted language, no matter how advanced the interpreter. JavaScript is also garbage collected, while C is not, adding an additional level of overhead.

At no point in this article are we shown the code of this new parser. We are also told that is incomplete. So we have a parser which we can't see and which is not finished, but apparently dominates its C counterpart in performance. This leads to me to believe one of two things:

1. The parser isn't complete, and its unimplemented functionality is going to be more expensive in terms of performance than the author anticipated, thus rendering his preliminary results void.

2. The implementation of the C extension he is comparing against is not very well optimized. As said above, I find it very hard to believe that well optimized C is going to be beaten by well optimized JavaScript.


It feels likely that the fundamental problem facing JS programs competing with the entire solution space available to C programs --- apart from the nerd who will implement an equivalently fast JIT compiler to run the JS on just to make a point --- is that C code has much better control over the layout of data in memory. You can work around the GC issues and modern compilers work around the interpretation overhead, but a C program is going to tend to have the easiest time ensuring that its working set fits into cache.

Of course, the real problem here is that he's comparing his JS code to a random blob of C code that just happens to be part of the MySQL package. Is the MySQL client library famously performant?


C-like control over the layout of data in memory is provided by the Binary Data proposal for ECMAScript: http://wiki.ecmascript.org/doku.php?id=harmony:binary_data&#...

I think the GC issues and codegen are the most difficult, actually. When the GC bites you you rarely have any other choice than to use free lists, which are always a pain. Furthermore, JS codegen is always complicated by the fact that JS is a JIT, and so many optimizations commonplace in C compilers tend to be skipped in the name of faster compilation. (You would be amazed how many of the common JS benchmarks end up boiling down to compilation speed.)

Despite all of this, however, I'm bullish on the future of JS with respect to performance; it may lose on head-to-head competition with C, but modern JS performance is perfectly adequate even for 3D games and the like.

(Also interestingly, Emscripten works around all of these difficulties surprisingly well -- you get low-level control over memory with it; you never GC; you get LLVM's optimizations.)


modern JS performance is perfectly adequate even for 3D games and the like

You can certainly write a 3d engine in JS, and it won't be laughably slow, but the idea that you're going to see any AAA games in the next 5 years written with any more JS than the usual Scaleform is extremely unlikely.


I don't think there will be a wholesale replacement of AAA game engines with JS-based engines, but I do think JS-based engines will encroach more and more on AAA territory from the bottom up, as the visual-fidelity differences between AAA games and web/mobile/etc. games narrow. I know of at least one AAA-level game company that's working in-house on a WebGL-based game engine to hedge their bets, and currently debating what should be deployed on that platform. I would guess others are looking into it as well.


I agree with you. If getting every bit of performance out of your hardware is important to you, C (possibly with inlined assembly) is the way to go.

I am so happy that I've never had to do that in my career.


Are you being sarcastic? Because wringing performance out of a known-working piece of C code is a pretty fun problem.


I'm not being sarcastic. I can see how it could be fun (in a particularly zen-coder way, in fact), except almost every performance issue I've had to deal with has shown itself in production, needing a fix yesterday.


The difference, as best I can tell, is mixed C-assembly code is generally built for performance from the very start, so it isn't all performance bugfixes for production code.


That being said, Fortran is being used equally often, if not more often, in HPC applications. The reason being that modern Fortran both gives you bare bone access to the memory structures and offers array slicing notation as well as good multidimensional arrays for HPC. (C multidimensional arrays usually don't offer optimal performance, leading to the pointer arithmetic notation).

It's still an ugly language though. I've yet to find a C language extension that gives you the higher level features of Fortran however - and even then it would have to be an industry standard to be supported by the wealth of HPC compilers out there - remember it's not only x86, you also have GPUs, Itanium, PPC.. Looking forward to a world where LLVM actually gives the performance people need in that field, because architecture wise this could turn out to be a silver bullet.


The main reason Fortran is used is that medieval professors can't be bothered to learn C. There are less assumptions about pointers in Fortran - which means it can be parallelised more easily - but you can work round that in C.


Fortran is not exactly a general purpose language though, it's specifically designed for the sorts of problems that scientific and HPC tends to deal with, and it's probably rare especially nowadays to see it used anywhere else. I'm guessing there aren't any web frameworks written in Fortran (though I'm sure someone will now point one out....)


Web development with Fortran. Shudder. (String handling is abysmal in Fortran so I wouldn't wish that to my worst enemy).

No, but my parent was talking about deep code optimizations being almost exclusively being done in C. I'd say HPC is a significant market for code optimization, so I wanted to point out that Fortran is kind of the industry standard there.


If I'm trapped on a desert island with (somehow) my MacBook and a solar charger, this will definitely be the first project I take one...


Well, it might surprise you to know that the first serious optimizing was written in fortran. In my book, compilers trump frameworks for generality.


I found it fun. I had to handle the stock options feed at a very high rate and do a binomial calculation to get the implied volatility on every tick.


Last time I looked at the MySQL client library, which is admittedly a few years ago, I was horrified to find it wasted a tremendous amount of time doing tiny read()'s instead of reading into larger buffers and splitting things up client side - the former causes ridiculous extra latency due to the extra context switches - , so I'd not be the least bit surprised if it is still slow.

In fact, if the tiny reads are still there in the MySQL C client, that in itself might explain the difference.


> C code has much better control over the layout of data in memory.

Yes. This presentation really drives that point in.

Building Memory-Efficient Java Applications: Practices and Challenges http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/mem...

(There are plenty of other sources too.)

Our Java study group tackled this paper. To prepare for the discussion, I tried to put my XML document object model implementation on a diet. Super fun. Modest benefits.

> You can work around the GC issues and modern compilers work around > the interpretation overhead, but a C program is going to tend to > have the easiest time ensuring that its working set fits into cache.

As I understand it (h/t Joe Bowbeer), Doug Lea and others have been doing very cool work micro tuning data structures suitable for use on multicore systems. So it's possible. But definitely not trivial; certainly beyond my abilities.


Is that a blanket statement about C versus any dynamic language, or just JavaScript? Because with LuaJIT2, Mike Pall has already shown that a highly-optimized Lua interpreter can hold its own against optimized C, and sometimes even surpass it.

Here's a nice look at some of the magic he does in assembler to get LuaJIT at such a high level of performance:

http://article.gmane.org/gmane.comp.lang.lua.general/75426

My point is, there's nothing inherently unbeatable about C. I think that a select group of dynamic language -- probably including JavaScript -- can and will reach that level of performance, or at least close to it. They just haven't been around as long.


Yeah, well please tell me how? The JavaScript engine is written in C so how could the language running on top of it be faster?

I will tell you how it can be - if the JavaScript engine JITs the JS in a more optimized way than the C compiler compiled the C.

Well how does that make JS faster than C when JS will always carry more overhead? It cannot and does not - all it means is that the compiler was far better.

A poor C compiler may be outperformed by the best JS one, but that is about the only scenario where JS will outperform C.


This argument reminds me of when I was 15 and trying to explain Unix security to my democoder friend, who kept insisting that he could bypass file permissions by just programming directly to the hardware and reading the bits off the disk.

If you want to keep arguing that every other language merely asymptotically approaches the performance of x86_64 assembly, that is a fine (if dumb) position. But the argument that C has a monopoly on assembly code generation is silly, as is the argument that C compilers are inherently better at code generation than all other compilers. Look at the LuaJIT2 direct-threading post upthread for an infamous example of a performant dispatching structure that isn't easily expressible in ANSI C.


> Look at the LuaJIT2 direct-threading post upthread for an infamous example of a performant dispatching structure that isn't easily expressible in ANSI C.

Sure, but the point of that post is that hand-written assembly can beat C-compiler-generated assembly. It's not arguing that any other language's runtime (even LuaJIT's own code generator) is going to generate assembly that's any better than gcc's in this case.

I do know that one of Mike Pall's stated goals with LuaJIT is to minimize the performance difference between Lua and C as much as possible. Though one of his methods of doing so (the foreign function interface: http://luajit.org/ext_ffi_tutorial.html) gives up the memory-safety of Lua to accomplish this. Even without FFI, LuaJIT is incredibly fast for functional/numerical calculations.

> If you want to keep arguing that every other language merely asymptotically approaches the performance of x86_64 assembly, that is a fine (if dumb) position.

I think what rubs some people (including me) the wrong way about these "faster than C" claims is the implied argument that C (and other non-GC'd languages) are obsolete. These claims often come from people who, as this article's author explicit states, want higher-level languages to win because they don't want to ever have to write in C or deal with anything written in C.

If people can get stuff in higher-level languages to run faster, then great, but those of us working in system-space in non-memory-safe languages are still going to beat their pants off if we combine all the tricks of their VM with domain-specific knowledge and optimizations (specifically parsing, in this case). "Faster than C" claims can sometimes feel like a big "F U" to those of us trying to innovate in system-space, like "our VM is the only system software we'll ever need." It's the Java attitude where people only want "100% pure Java" and shun JNI and anything that won't run on their VM.


Why would it be hard to generate the code for a direct-threaded interpreter?


That's exactly the question that Mike's whole post is answering. It turns out that the common optimizations like hoisting, CSE, tail-merging, etc. perform badly on direct-threaded interpreter code. Which is one of the primary reasons Mike wrote the interpreter for LuaJIT2 in hand-written assembly instead of C.


I think it is easier for the compiler for a high-level language to predict usage patterns --- which branches will be taken, which variables should be in regs or L1, which functions are best served by slower code with a small memory footprint vs. faster code with a larger footprint, what's best handled with a jump table versus with conditional jumps, &c &c --- that can a C compiler, and that over the long run languages with better, more consistent abstractions than C are going to have better runtime characteristics than the outputs of a C compiler.

Put differently: C compilers are hamstrung by all the dumb C programs a developer could express with C.

Javascript compilers have to deal with bad Javascript, don't get me wrong, but they don't have to deal so much with bad list and table implementations.

I get what the LuaJIT2 post is saying (and let's be clear: I'm not putting myself on a level with the Lua JIT people).

For what it's worth: C is my first language, and my favorite language. My background is systems programming. I would not enjoy figuring out how to reliably write a memory-mapped CSR while masking the right set of interrupts in Javascript. :)


> I think it is easier for the compiler for a high-level language to predict usage patterns

Profile-guided optimizations for C can give a C compiler a lot of the same information. It's true that these patterns could vary over the run of the program, though at that point you have to weigh the speed gained from being adaptive vs. the runtime overhead of monitoring the program's execution and doing multiple passes of code generation.

> For what it's worth: C is my first language, and my favorite language.

Yeah I know. :) A lot of what I wrote was directed more generally at the "faster than C" sentiment and not at you specifically.

> I'm not putting myself on a level with the Lua JIT people

I think you mean the LuaJIT person. I got to finally meet him this summer and verify that he is human, though I guess I can't guarantee that he doesn't have cybernetic implants or work together with others under a single pseudonym. :)


The Lua people are not like the Java people. The whole point of the luajit ffi is to make interfacing with C code really easy, without any more function call overhead than calling C to C. So it is the ideal language to interface with performing well written C code without losing the benefits.


I don't know why I am wasting my breath either since it is not my law that abstractions (if both implementations are sound) always come with a performance tradeoff. It is just a fact (therefore considered a law), not made up by me.


The opposite is often true. The right abstractions can provide a performance benefit, when they force programs to conform to constructs that are easily expressed in performant native code.

The standard C library is full of functions that are slower than equivalent functionality in higher level languages. Or do you think ticking through arrays of hopefully-ASCII bytes, byte by byte, waiting for the 0 byte, is the fastest way to compare two strings?


> Or do you think ticking through arrays of hopefully-ASCII bytes, byte by byte, waiting for the 0 byte, is the fastest way to compare two strings?

I'm sure you must know this, but this is not even remotely how strcmp() is implemented in modern libc's.


It is quite close, actually. "not even remotely" is a very strong statement.

There are tricks that let them do this 8 bytes at a time (on AMD64, 4 bytes on x86), but that doesn't change the fact that in order to compare two 128KB strings which are equal, you actually have to read 2*128KB from memory and compare each single byte (in groups of 8, if you are lucky enough with your alignments and instruction set).

Different abstractions, such as Python's strings, can very often do this comparison with almost no memory access:

(a) if both strings are interned, it is enough to do a pointer comparison.

(b) if the length is not equal, the strings are not equal - a one word comparison.

(c) if both strings have been hashed before (quite likely), you can tell they are different if their hash is different - a one word comparison.

(d) if length is equal, and hash is (equal or uncomputed), you will have to do the comparison.

Whether this trade-off is worthy depends on your application. If most of your strings are 7-characters or less (as is often the case for software dealing with e.g. stock tickers), then the C approach on 64-bit archs wins hands down: you should actually have all the strings in-place because a pointer takes more memory and causes contention. However, if your strings tend to be 100 bytes or above, and many of them have equal prefixes, the Python approach wins hands down.


> There are tricks that let them do this 8 bytes at a time (on AMD64, 4 bytes on x86)

It's actually 16 bytes at a time on any machine that supports SSE (maybe 32 bytes soon with AVX).

> Different abstractions, such as Python's strings, can very often do this comparison with almost no memory access:

Sure, different abstractions have different trade-offs. All of these abstraction possibilities are available to C. strlen() isn't "the C approach," it's just the most common one. Any C application where comparison of long almost-identical strings is important will surely use techniques similar to what Python does. On the other hand, the reverse is not true: Python does not have access to all the same optimizations that a C programmer could draw upon to do string processing.


I was mostly replying to your assertion that "that's not even remotely how strcmp is implemented", which, for most definition of "even remotely", is false.

> All of these abstraction possibilities are available to C

That's a tautology at best, and meaningless at worst. The way strcmp() is implemented, which we discussed above, is not actually available in C.

> Any C application where comparison of long almost-identical strings is important will surely use techniques similar to what Python does.

And similarly, any Python application that requires (insert some uncommon requirement ..) can do what C can with the same kind of help that strcmp() gets - by delegating to the layer that does it best.

> Python does not have access to all the same optimizations that a C programmer could draw upon to do string processing.

Pure python is more limited than C, true. But specific Python implementations (RPython, PyPy, IronPython) might have better access to some optimizations than specific C implementations.

And there's always the aspect of "what's theoretically possible" and "what happens in practice". The fact that PyPy will dynamically switch from 32-bit to 64-bit to unbounded-long-integer might make a real difference on a 32-bit machine where the code might occasionally require 2048 bits, but overwhelmingly requires just 32 bits.

It is possible to construct pathological cases where there are e.g. pow(2,128) possible type combinations within a function, the exact combination is only known from the data (but is consistent for an entire run) - in which case, PyPy will essentially compile the right program to machine code, whereas you cannot do AOT because of the number of combinations; which means a C program will essentially be an interpreter based on those types.

But I don't care about theoretically constructed pathologies. In practice, especially with time-to-implement constraints, it is not true that a C programmer has all the tools at their disposal that higher level languages have.


> I was mostly replying to your assertion that "that's not even remotely how strcmp is implemented", which, for most definition of "even remotely", is false.

eglibc's SSE2 implementation of strcmp is just over 5k of machine code, whereas the simple implementation compiles to 56 bytes on x64-64. That was my definition of "not even remotely." I did not mean to imply that it was a fundamentally different algorithm, only that it was a far more sophisticated and optimized implementation of the same algorithm. My apologies if this was unclear or appeared overstated.

> That's a tautology at best, and meaningless at worst.

By "these abstraction possibilities" I meant the ones you mentioned, which is true.

> And similarly, any Python application that requires (insert some uncommon requirement ..) can do what C can with the same kind of help that strcmp() gets - by delegating to the layer that does it best.

That's great and I fully support that. What I am arguing against is high-level language cheerleading that discounts the importance of C (or assembly for that matter). Since you mention PyPy, I have to say that their PR is some of the worst in this regard; some of their "faster than C" claims are actively misleading, like this one that benchmarks some generated string formatting code against sprintf() (which re-parses the format string every time): http://morepypy.blogspot.com/2011/08/pypy-is-faster-than-c-a...


> > There are tricks that let them do this 8 bytes at a time (on AMD64, 4 bytes on x86)

> It's actually 16 bytes at a time on any machine that supports SSE (maybe 32 bytes soon with AVX).

Is there a sequence of fewer than 16 instructions to spot a NUL byte inside the 16 byte block?


> Is there a sequence of fewer than 16 instructions to spot a NUL byte inside the 16 byte block?

Yes:

    pxor  %xmm1, %xmm1
    pcmpeqb (mem), %xmm1  // Do 16 byte-wise compares
    pmovmskb %xmm1, %eax  // Move results into the low 16 bits
    test %eax, %eax
    jnz saw_null


Very cool.


What's a modern libc? Not being snide or anything: I have no idea. I didn't know where to look so I looked at glibc [1] and that, in fact, does seem to be how it works.

[1] http://sourceware.org/git/?p=glibc.git;a=blob;f=string/strcm...


You might want to look at the non-generic implementations, like http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/x86_...


This might be the most delicious piece of code ever written ( I cannot judge that, really), but we're talking 2307 lines for a string comparison.

I'm impressed, but also scared and amused. I always look with envy at system level guys, lacking the knowledge to play on that level. This, though, comforts me quite a bit. That's just not my definition of 'fun'.


I've never written anything non-trival in C and even that was ages ago so I didn't hope to be able judge the niceties of different implementations but I can't even tell what the algorithm is in that one.


I have heard of musl[1] and Bionic[2]. Interested in hearing about any others.

[1] http://www.musl-libc.org/

[2] http://en.wikipedia.org/wiki/Bionic_(software)


Those seem to both use basically the same algo as the glibc one, all though a little more compactly written.


Uclibc and dietlibc. Must recommend Musl for code readability and implementation quality.


Care to provide and example?

Your statement would only be true if the abstraction implemented something more efficiently than the C developer. This in of itself says nothing about C or X language for that matter being faster.


It could also be true if the abstraction lays bare optimizations not available (readily enough) to the C compiler. While this wouldn't make X faster than C as languages (what does that mean, anyway?), it could make an X compiler produce faster code than the best C compiler.


You are not seeing my point. If the JIT compiler can be made better - than so can the C compiler right? Until some point where neither can be made better. Then C would win because it does not carry the extra overhead of the other.


OK, here is an example. Let's consider 'memcpy'. There are various problems with implementing memcpy in C:

1) You can't assume that pointers are aligned. 2) (related) If the user asks for you to copy n bytes, you better not read byte n+1, even if you don't need it, because maybe it is on a different page which is not available for reading.

So, an optimised memcpy usually first has to do a bit of work to find the 'aligned segment', do that, topped and tailed with some special cases.

A JIT compiler for Javascript (for example) takes issues of alignment out of the hands of the user, so can make any assumptions it wants by keeping such choices away from users.

Of course, we could write a memcpy_aligned (and some systems have such a method), but we can't ever optimise simple memcpy as much as the equivalent in javascript.


1) Loop versioning. You can check if the pointers are aligned, and then decide whether you want to take the fast path or the slow path. (A better example would be aliasing. Because pointers don't carry the size of the region they point to, we can't check if two pointers alas. Restrict solves this problem with programmer intervention.). I believe that GCC's vectorization code already does this sort of versioning.

Example:

     testl $0xf,%ptr
     jz aligned_path // in reality, fast path would be inlined here for cache locality reasons.
     jnz aligned_slow_path
2) If your reads are naturally aligned, you will never be able to read a word that starts on one page and ends on another, so working in naturally the largest naturally aligned chunks you can is valid. This is a non-problem. (In fact, glibc takes advantage of this in it's assembly implementations of various SSE string functions.)


This is true, but a high-level language can avoid having to even make that check, making it "faster than C", in at least some sense of the phrase.


If it does not "make that check"... then how does it know? (It does check)


A Javascript JIT doesn't have to make the check, because it can simply decide that all memory blocks, and all copies, occur on word boundaries.

One of the problems with optimising C is that you have to assume (in simple terms, obviously the full story is more complicated) whenever a user's function is called, then all of memory might have changed. Even if you have a pointer to a const int, maybe in another part of the code there is another pointer to that int which isn't const, so you have to assume it might have changed.

In a language with different semantics, the optimisers can have a much easier job seeing what is going on, and know what can effect what else. This is the reason that Fortran compilers can often be seen beating C compilers.


No, not neccessarily. There could be optimization opportunities in the more abstract language that perhaps cannot ever arise in the less abstract.


Sure: interned strings.


You are wrong. A JITted environment can take advantage of knowing about the current run of the system. As a result, it can do things like unroll loops and inline function calls.

Yes, you could do the same thing in C code, but the resulting executable would be unreasonably large because you would have to unroll every loop and inline every function.

Pypy has show itself faster than C in some cases as well[1].

1. http://morepypy.blogspot.com/2011/08/pypy-is-faster-than-c-a...


That PyPy example has nothing to do with C and everything to do with a particular implementation of libc.


Maybe some day they will add profile guided optimization to C compilers.


They're not the same. VMs can assume invariants (which may not always hold) and compile specialized methods which depend on those assumptions and then fall back to a non-optimized version during the execution of a method. To do something like that (OSR) in C, you'll have to have a very sophisticated runtime.


you're kidding right? and at least referring to gcc's -fprofile-generate -fprofile-use right?


Profile-guided optimization is decades old. It was, for example, one of the things people loved about the (Ultrix?) DEC Alpha compiler was profile-driven optimization.


First VMS.

That was one of the outstanding compilers ever written.


There is a major difference between performing profile-generated optimizations at compile-time based on sample data, and performing it at run-time based on real data. It is one pretty good way in which JITs could beat programs implemented directly in C.


Not really since the 'sample' data is 'real' data which has been gathered during run-time.


That is the most optimistic statement about profile-directed optimization that I have ever read.


It's not all about the quality of the compiler. C compilers have to deal with a language that has terrible semantics for aliasing, and in which cross module information flow is usually limited to what programmers type into header files (although this is slowly beginning to change with LTO and WPO). This is a significant disadvantage for an optimizing compiler. In contrast, JS implementations have the entire program text and can optimise, say, calling conventions however they like.

JS and Lua also have disadvantages, such as their inferior (but memory safe) representation of data, so I would not be surprised if JS were faster for some problems and slower for others.


That's why Luajit also has an unsafe C compatible representation too, the ffi.


Your argument is the same as the arguments that higher level arguments cannot be faster than assembly.

In theory, any optimization available to a compiler is also available to an assembly programmer. In practice humans do not match automation. This has been demonstrated both in theory and practice for decades.

There is no limit to the level of language that this argument could theoretically apply to. In practice the run-time guarantees and programmatic indirection that we demand in high level languages make the task insurmountable for current programs. But never underestimate what can happen with a good compiler and the right program.


> "In practice humans do not match automation." Actually in practice human's almost always surpass automation mostly because they can start with automated output and improve upon it.


Humans can do that. But in practice we don't seem to.

Instead the trend mostly seems to be that we do it by hand until automation becomes good enough to do it better than we were doing it, and then we move on to harder kinds of problems and let automation do its thing.

I say "mostly seems to be" because there are plenty of counter-examples. But that's the general trend. As is seen by the explosion of programmers working in what used to be considered unbearably slow scripting languages, and the relative lack of people doing traditional assembly programming.


"In practice humans do not match automation." Maybe this is a nitpicky argument, but to me this means one thing: when put head to head, humans do not do better than automated output. This is wrong for exactly the reason I said. In 99% of cases you start out with an unoptimized version, find the areas that need optimizing, and improve the automated output by hand. Thus in practice and in theory humans almost always beat automated output. The general trend of people working on higher level problems isn't because automation can do low level stuff better, it's because automation can do it well enough for most cases that we don't need a human to step in. Automation isn't doing better than what a human would do, but it is doing well enough that there's no need to go back and optimize it.


In 99% of cases you start out with an unoptimized version, find the areas that need optimizing, and improve the automated output by hand.

This strongly depends on the scenario.

If people are identifying and optimizing a hot spot, it tends to happen this way, yes.

But what I am thinking about is the common situation where a company produces a product in a low level language, and then later on a competitor produces a competing product in a high level language. The second entrant is optimized by an automated process, the first was done by hand, and can't easily be rewritten.

In these situations - and I have encountered several - the second implementation frequently winds up doing more and doing it faster than the first implementation.


> I will tell you how it can be - if the JavaScript engine JITs the JS in a more optimized way than the C compiler compiled the C.

Yes. Exactly. Let's say there are two languages A and B, and A is compiled (be it JIT or AOT) by a smarter compiler, resulting in faster code than the same program written in language B, how does that not make language A faster?

I do know that comparing interpreted/JITed code and AOT-compiled code is somewhat nonsensical, but then again, so is talking about "faster" and "slower" languages.


>Yes. Exactly. Let's say there are two languages A and B, and A is compiled (be it JIT or AOT) by a smarter compiler, resulting in faster code than the same program written in language B, how does that not make language A faster?

Well I am talking about the performance limitations imposed by the laws of physics. Not which compiler is better. I can always find a better or worse C or JS compiler/JITter so that proves nothing.

Doing more (Which a more highly abstracted languages must do) in less time with all else being the same is not possible as we understand quantum physics today.


> Doing more (Which a more highly abstracted languages must do)

Can you explain why you think this assumption is true? I don't think it is.

A higher level of abstraction may allow your to convey more information in less code, but that does not mean it necessarily translates to more machine code.

In fact, when you operate on a higher level of abstraction with more information available, the compiler may even have more freedom to produce highly efficient output without breaking expected semantics.


Wow.


It's not like performance is a fundamental property of the language, it's just a matter of which tools are available. JITs outperforming compilers is just a matter of specialized compilation approach being able to outperform a generalized compilation approach, which is actually a far more fundamental truth than abstractions having a performance penalty. LLVM outperforms GCC in some cases.

However, in general JITs do not outperform GCC. The JIT overhead only pays off in a limited set of cases.

Most people publishing performance benchmarks on the Internet barely know how to compile a C program for production, let alone write or benchmark one. Google did a thorough benchmark of several languages and C++ was the clear winner: https://days2011.scala-lang.org/sites/days2011/files/ws3-1-H...


>> Google did a thorough benchmark... <<

No. One person employed at Google did a comparison and lots of other people (including some others employed at Google) explained what they thought was wrong with that comparison.


In the abstract, a just-in-time compiler will beat an ahead-of-time compiler because it has more information, including statistics about control flow (which branches tend to be taken, etc.) and what exact instruction set is being targeted.


From the article:

> JavaScript will no longer be the bottleneck. At this point the main cost is turning network data into JavaScript objects. This cost is equal for JavaScript libraries, as well as for C++ addons making V8 calls. Also, when a single client can process 5000 MBit/s utilizing a single CPU, your MySQL server has long exploded

Remember these are Node drivers, so everything has to end up becoming a JS object.


I'm also doubtful that this will beat C, however...

> There is innate overhead when using an interpreted language, no matter how advanced the interpreter.

There is an overhead in JIT'ing the code, yes. But it is not a given that when amortised over sufficient data, that this overhead can not be compensated for by making use of knowledge that is simply not there at compile time. E.g. there are several well known methods regularly used in optimising dynamic languages that depend on discovering and adapting the code based on the actual types used. But when you're first doing this specialisation at runtime, nothing would stop you from taking actual input data into account rather than just basic type information for example.

> JavaScript is also garbage collected, while C is not, adding an additional level of overhead.

This is not necessarily a benefit for C unless a) your JavaScript program uses enough memory to trigger the garbage collector, which will depend on both the VM and your system, or b) your C program is written in a way that requires no extra effort to keep track of when memory becomes garbage. Programs written for GC'd systems may sometimes require far less logic to keep track of memory, and instead take the cost at collection time, and so may spend less time dealing with memory in situations where collection isn't necessary during the lifetime of the program.

In the general case, there's an extra overhead. In specific cases it is most certainly possible that the garbage collection can be a performance benefit by acting like a safety net that lets you do other stuff (avoiding logic to track ownership) that can speed up your app - this applies regardless of language.

Other than that I agree with you.


node is compiled to native code at runtime, and the compiler uses runtime type information to generate that code. C (without LLVM's JIT, of course) is compiled to native code before runtime, and as such, cannot take advantage of runtime type information when producing the code. So in this case, node does have a theoretical advantage.

But to be thorough, one should also compile libmysql's parsing routines with LLVM and turn on runtime JIT compilation, and then write a benchmark that will exercise the code long enough for the JIT to kick in.


So take the output of the profiler after running the program on a diversity of real inputs and use that to drive the optimizer.


Modern JavaScript runtimes are not interpreters, V8 for instance is just a JS to native ahead-of-time compiler. Also, for the general case, garbage collection has been outperforming manual management for over a decade now.


There are 3 common fallacies in this post that people continually bring up about modern languages. Thought i'd come on here and write some corrections:

"There is innate overhead when using an interpreted language, no matter how advanced the interpreter."

I think a lot of people think this is true, because they have an antequated idea of an interpreter which reads each line as a string, parses the string, then executes the code. Modern js (and jvm bytecode, similar-but-different scenario) 'interpreters' compile to native bytecode and the code runs directly on your hardware.

The speed overhead from modern language has a lot less to do with the 'interpreted' nature of the language, and a lot more to do with (a) code structure (overhead of objects, closures, namespace resolution, all that junk), and (b) the maturity of gcc vs other compilers.

Theoretically a language with a JIT compiler should actually be faster than a precompiled language in any scanario where you are intensely going round and round a loop which has a lot of logic inside it. The more the loop runs, the better the JIT compiler can optimise it based on the current runtime conditions.

"JavaScript is also garbage collected, while C is not, adding an additional level of overhead."

The overhead of the garbage collector is only really to do with memory and startup speed, not runtime speed. It does barely anything when not collecting. Every time you alloc in c, you must free, and those actions have to happen in proximity to each other. Free takes time. GC allows all those free operations to happen when the program is idle, instead of holding up your program.

The more stuff you create and delete, the faster a GC language should be compared to an equivalent program in a non-GC language.


I love the "eval is awesome" section.

It's taken my years of study, but I finally "get" Lisp. Let me summarize pg's On Lisp:

"Lisp is a language for writing programs fast"

1) Write a function

2) Write a function that does something similar to #1

3) Begin to write a function that does something similar to #1 and #2

4) Abstract out the commonalities between #1 through #3

5) Encounter all kinds of new use cases for your abstraction in #4

6) Wait for #5 to become unwieldy

7) Abstract #4 even further, until you have something that resembles an interpreter

8) Wait for #7 to become a performance bottleneck

9) Write a compiler that takes inputs to #7 and turns them into #1 through #5

"Lisp is a language for writing fast programs"


Doesn't it cause a "Javascript eval injection" vulnerability?

I don't know Javascript so I may be wrong here, but:

* Suppose someone uses this library to create a "MariaSQL Explorer App", where you give the app connection credentials and it connects to the database and shows you the data etc.

* A malicious attacker tells a user "have a look at my database" and the user goes to the attacker's database.

* The attacker's database (or spoof of one) has a column called 'dummy": MALICIOUS_CODE(), "colname'. notice the '"' chars inside column name.

* The MALICIOUS_CODE() runs in the user's node.js app. Perhaps it sends the attacker the passwords to other databases from the app's keychain or something..

* Profit


Which is why you sanitize input. Which every sql-communicating system must eventually do somewhere - this is no different.

Besides, that's just an example snippet.


If you sanitize input, it implies you're inserting the input into an execution environment. If possible, it's better to treat data as data.

In the Javascript eval case, it's definitely possible; just access the data through a variable instead of inserting it into the eval'ed code.


As Groxx points out, yes, you need to sanitize input. It's pretty easy to return an error if the user input doesn't match a whitelisting regex. It can be as simple as /[a-z][a-z0-9]*/i

However, in a Lisp, eval typically works on lists, not on strings. In effect, behaving like a parametric SQL query: a quotation mark or close paren or whatever in the string would be harmless.


For me myself it is often very motivating (sometimes demotivating) if somebody comes up and implements the same thing I want to do - but they accomplish 10x faster performance (even better if it is written in a cleaner style). The author seems also to rather enjoy those challenges ;)

In my interpretation the question "Faster than C?" is relevant because it is very easy to think that certain problems (like parsing binary data) are just not a good fit for language Y and thus the performance can't be good. Even if C performance is not attainable sometimes one cat get closer than one would think.

My last question is regarding his optmization example.I don't program javascript and thus have difficulties understanding how the optimized variant could every be faster than the original one. String concatenation and evaluation should not be faster (from my laymans perspective) than setting an indexed value to an array? (Ok actually it probably is not an array but a hash map, but are those so inefficient in java script? Or is it rather behaving like a sorted list where every value is inserted via binarcy search?).I would be very happy to get some insight.


Regarding your last question: the string concatenation/evaluation happens once while creating the parseRow function and from then parseRow is a compiled/JIT'd function object, no string handling happening. The problem with the original is not the hash map creation, but the fact that it requires all sorts of extra loops, and array & property look-ups.

Also, I think that is possibly some missing information there, since in the second version the column names are fixed (so the columns argument to parseRow is ignored), while in the first they are not.


Ah ok so this is probably the parser equivalent to precompiled queries. Given a fixed query, a specific parse row function is created once and than reused. Thanks!

While I think code generation is certainly the right approach in some examples, I see one problem in this example: As the parser is basically pregenerated using a certain column definition, why does the generated function has an parameter columns? It is simply discarded. So I would say it should rather be:

  var parseRow = new Function('parser', code);


I agree, and I don't know. (I even looked through the source to try to find if parseRow is a function from node-mysql. It's not, as far as I could tell.)


The excessive use of "fuck" and "shit" throughout the entire article really takes away from its message. It just seems very immature. It's hard for me to take it seriously when it sounds like it was written by an angsty teenager who's trying to look tough in front of his friends, or something like that.


I would hardly call that excessive profanity. In a 2000+ word article there are what, 10 instances of 'profanity'?

Honestly I think it speaks more to your maturity that you would find that so bothering that it could detract from the content of the article.


Honestly, I think it speaks more to your maturity that you are so bothered that people are bothered by profanity.

In all seriousness though, profanity is unprofessional. I think a fair definition of profanity is 'vulgar extreme emotion.' If you have to use 'extreme emotion' to get your point across, then you aren't doing it right. You should be able to describe something or explain something with some sort of levelheadedness. On to the 'vulgar' part. We can fairly say that some people could care less about vulgarity and others are bothered by it. So why put it in in the first place? I'm not saying we all have to be ultra politically correct, but if I'm giving a speech on the free market, I'm not going to insert snide comments about liberal politicians and their economic beliefs. I could, it might even make sense in context, but there's no reason to.


"profanity is unprofessional"

That I can agree with. It is signals more of a casual tone than a professional tone.

Why should someone use a casual tone instead of a professional tone? Why not? It is nothing more than individual preference. Write in the style you feel most comfortable with.

("Honestly, I think it speaks more to your maturity that you are so bothered that people are bothered by profanity."

That he is bothered is not what makes me think he lacks maturity. That he is bothered to such a degree that he thinks those particular words actually devalue the article itself is what I think signals immaturity. The ability to separate ones emotional response to something from their intellectual appreciation of something is a hallmark of maturity.)


I don't take offense to the words that were used. It's more akin to articles that use absurd fonts or blatantly poor color schemes. Such things are unnecessary, and make it more awkward to absorb the actual content.

When I see authors doing things that obviously make their work harder to read, it does make me question their judgment, which in turn makes me question the validity of what is being expressed.


I pretty much agree with you, though it certainly depends on the context (I'm more likely to not be bothered by it in a post on a mailing list). But for a technical writeup? You want to be treated like a professional, write like one.


To be clear, I am not criticizing you for finding certain words to be offensive or thinking that they are offensive words. I am criticizing you for questioning the validity of the article because the author used certain words that you find/think are offensive.

I mean seriously...


Then he and I both lack maturity. So be it. I find the complaint valid.


Your entitled to your opinion. The author is entitled one as well. What you think about his style of writing does not matter. Expletives are not immature, you just view them as such. Again, that is fine and is your choice. There are (very few) people (in this thread who) agree with your view. There are over 25 comments actually discussing the article instead singling out of individual words to focus on. According to you, since there other people discussing the article and not caring about the sparse use of swear words they too must be immature.

Here is my opinion: it is more annoying to see people like you complain about the "excessive" use of "fuck" and "shit" every time an article is posted that contains "fuck," "shit," or something similar.


Absolutely. What baffles me is in the defense of the use of profanity in this article/talk? Perhaps he had sized up his audience and had determined that those he was talking to could only absorb the message if it were dumbed down a bit?


"Using profanity" and "dumbed down" have basically nothing to do with one another. I've read very intelligent things with lots of expletives, and incredibly simplistic things with none.

Why are you baffled by the fact that some people defend the author's use of profanity? Surely the fact that some people simply aren't bothered by profanity isn't news to you?


Sorry to say, if the article is good enough, I don't care who wrote it - immature or not. If I could learn something from a 13 year old kid, I would love to. In Europe "fuck" and "shit" are anyway not considered offensive at all (at least in the countries, where English is not the first language).


Surely you can imagine the equivalent in your language. Likewise for English speakers using foreign profanities is not considered offensive.


I didn't even notice the profanity. He's not in a corporate setting or anything, who cares?


>The excessive use of "fuck" and "shit" throughout the entire article really takes away from its message.

Really? I haven't even noticed it. Only remember reading a great js performance article. Maybe "shit" is in the eye of the beholder?

>It just seems very immature.

Zzzzzz.


This is an outstanding overview of how to build fast programs in JavaScript. I really appreciate the fact that Felix took the time to write it. I learned a lot, and will definitely integrate this into my work whenever performance-critical code is involved. Particularly since I enjoy dataviz so much.

I'm a little surprised that someone so into JavaScript is using R and ggplot2 to visualize his data, and not d3 along with CoffeeScript for munging data (or Python if you can't stand CoffeeScript). Don't get me wrong, R is a powerful tool, but with d3 you can skip the whole ImageMagick/Skitch step since you're making visualizations directly for the web. Plus, once you've grasped d3's declarative approach (took me a while), it's so easy to quickly make powerful visualizations with it. In fact, it was partially inspired by ggplot2, if I'm not mistaken.

And to quickly munge/clean data, I've found CoffeeScript does very well here, similar to how easy it is to use Python for this task. I wouldn't want to write out JavaScript when rapidly trying to get data in the right format for visualizations, but with CoffeeScript and a functionally-oriented library like underscore, it's pretty easy.

That said, I'm sure once you've mastered such an intricate tool as R, it's hard to give up that power. But if you're a node devotee and you're looking for a good tool in JavaScript to visualize data, you can't get much better than d3. I know a lot of dataviz folks are learning JavaScript just so they can have access to d3.


Really the nice thing about ggplot2 is that each of those figures were probably like 1 line of code. Having a DSL designed for your data analysis is awesome.


I like d3 (and coffeescript). But...

  df <- read.delim("benchmark.tsv")
  boxplot(df$timing ~ df$implementation)
Versus...hmm. How many hours / LOC would that take you in d3 and coffeescript? It will be great when it happens (nvd3 looks promising) but I don't think d3 is an exploratory data analysis tool yet.


> But, life is never this easy. Your code may not be very profilable. This was the case with my mysql 0.9.6 library. My parser was basically one big function with a huge switch statement. I thought this was a good idea because this is how Ryan's http parser for node looks like and being a user of node, I have a strong track record for joining cargo cults. Anyway, the big switch statement meant that the profiler output was useless for me, "Parser#parse" was all it told me about : (.

FWIW this is also a case of "get better tools". Line profilers exist, and they can handle that kind of cases (though the instrumentation costs go up likewise).


For Node and V8? I'm sure you're right, but when I was poking around I didn't see much more than suggestions to use "node --prof".

Which tools have you found useful?


> For Node and V8?

I don't know, I use neither. I'm just saying, there are profiling tools which handle the "One Big Function" pattern.


I write code primarily to analyze data from my experiments, and I do it primarily in Python. I have been told (and have read) repeatedly, that optimizing is to be done right at the end and only to optimize the inner most loop etc.

From my reading, this guy is advocating the exact opposte: optimize as you code. It sounds sensible, but what to other people who have to optimize for a living have to say?


I think the difference here is that the problem is completely understood from the start: there's a MySQL protocol (which the author has already implemented in the past) and his project needs to be able to handle that exact protocol as quickly as possible.


This. Also the applicability of the optimization rule depends a lot on the context. It is typically stated for a complete project. Writing a library is different from that.

Depending on the kind of library you write, it could be that it is called in a hot inner loop of an outer project. So yes in that case it would make fully sense to optimize the heck out of the complete library (like e.g. a mysql client).

Another point is to see the reasoning behind the optimization rule. Optimization always is associated with cost (cost of programming, additionaly complexity in the code, maintance). This cost has to be recovered from the effects of the optimization. As the number of users for a piece of code grows, the benefit of optimization rises, but the costs should be more constant. Thus at scale it also makes sense to look a smaller optimization potentials.

But this does probably apply to not even 1% of the typical projects.


It depends on what your primary goal is. If you want to write a program to do X, then you write a program to do X, and worry about performance later.

If you want to write a really fast parser, then you start out by thinking about the best optimizations that will give you a very fast parser.

To be fair, the author of this did write his library first without thinking too much about optimization, and then came back to make it faster. Unfortunately that sometimes means throwing away large pieces of code that just can't be made fast.

As with anything else, it's a balance. I think everyone should be writing code with performance in mind at least a bit. Just how much is dependent on the problem you're trying to solve and what your goals are.


>From my reading, this guy is advocating the exact opposte: optimize as you code.

Huh? He had ALREADY written his library before he started optimizing.

He even says that the profiler didn't show much, because he had all parsing code inside one big function.


No, those were just the optimizations he listed, he never said he hadn't optimize before.


>he never said he hadn't optimize before.

And he never said he _did_ optimize before.

Which kinda defeats the complain in the parent comment that he advocates optimize as you program.


But he does: that's what his "benchmark drive development" is all about. He even starts by benchmarking an empty function!


I really like the style of this writing. Thanks, I learned a bit. I just wish the presenter dug deeper into the final mystery to round out the entire presentation.


I think that the drivers can do a lot more to improve DB performance. http://williamedwardscoder.tumblr.com/post/16516763725/how-i...

At low load, the DB worker is idle when a request arrives and it can be dispatched immediately. But under load, the DB worker is busy when requests arrive and they build up as a backlog.

When a backlog builds, the DB worker can examine the pending requests and combine those that it can to reduce the total number of requests.

Not all requests are combinable and there can be subtle rules and side-effects. It is likely that a driver with just a modicum of combining ability would be very conservative e.g. simply combining single-key selects that are queued adjacently or such.

Even still, the gains can be massive and performance never worse.

(Oh, equally applicable to NoSQL too.)


No way. Even with equal-efficient code, there is an additional point that is often ignored: Data structures are way more simple in C, with less overhead, and with higher cache-hit ratio, because more data fits in CPU data cache.

As example, gcj is as fast as g++ for code generation (both generating machine code, without virtual machine involved), however, in benchmarking appears to be slower, just because the data structures. If you tweak the Java code for use simpler data structures, e.g. integer or byte arrays, data overhead gets reduced, so memory cache hit increases, thus keeping similar performance to C/C++.

Other cases, like Java bytecode running on a VM, even with great JIT like HotSpot, suffers also a lot because of data structures, so even when generated code is quite decent (runtime profiling, etc.), penalty is there, so code will suffer great penalty unless running with huge L3 cache (e.g. 32-48MB), being noticeable anyway no matter how much cache you add when having to do many memory indirections more.

And of course, when comparing, you have to compare equivalent things, e.g. Java <-> C/C++ ports, and not completely different software with different implementation (e.g. optimized built-in string handling vs non-optimized C string handling -e.g. ASCIIz string handling is slow, because of stupid C string function implementation, not because the C language itself, being the reason of C strings not being used for high performance code, even when writting in C-).


Excellent read. Written well, convincing examples of why it's good advice, and doesn't waste space in making its point.


I guess the hope of high-level languages is that you can build a more interesting vocabulary from complex concepts.

http://www.pvk.ca/Blog/2012/08/27/tabasco-sort-super-optimal...

It seems that there's a lot of effort going into making languages, "faster than C." Perhaps we would all be better off working with languages that just give us better abstractions -- user vocabularies. Layers on layers.

Don't get me wrong, C is the right language and a good tool for many situations. It's just that if you're going to extend the vocabulary then why do you have to change the implementation? If you want to optimize why optimize the compiler at such a low level?

Either way I just want to say that it's an interesting conversation and I'm looking forward to seeing more.


My only problem with this article was that it didn't once mention parsing binary data, except in the title.


Very worthwhile and well-designed writeup! I do wish that he had expanded the last argument to show what/how he fixed the performance problem. Also, does anyone know why eval is faster than just defining the function? I mean wtf, why doesn't v8 make this optimization?


>Also, does anyone know why eval is faster than just defining the function? I mean wtf, why doesn't v8 make this optimization?

There are three optimizations I see in the eval example:

1. The object is created as a literal rather than by property assignment (see http://jsperf.com/object-literals-vs-object-properties).

2. The for loop loop is unrolled.

3. The column names are cached in the function and do not have to be retrieved each time.

The reason these can't be done by v8 on its own is that they make assumptions that v8 can't guarantee. For the first two, you have to guarantee that the columns array is always the same length. For the first and last, you have to guarantee that the columns will always have the same names.

So even though you take a big hit on the initial eval of the function, you'll likely make up for it by having a better-optimized function.


I noticed a possible issue with the code generation, which may cause the issues with excessive heap allocation that were reported:

  var code = 'return {\n';
  columns.forEach(function(column) {
    code += '"' + column.name + '":' + 'parser.readColumnValue(),\n';
  });
  code += '};\n';
  var parseRow = new Function('columns', 'parser', code);
Instead of performing so many appends to a single string, I would try using map() and then join() the resulting strings:

  var code = ['return {\n',
    columns.map(function(column) {
      return '"' + column.name + '":' + 'parser.readColumnValue(),\n';
    }).join(''),
    '};\n'].join('');

  var parseRow = new Function('columns', 'parser', code);
Of course, this depends on how often the parseRow function is created...


That might be an improvement, but you probably wouldn't want to use Array.map, which generally has pretty terrible performance. See http://jsperf.com/map-vs-native-for-loop/5


Yes; the only reason for using Array.map() here is conciseness and similarity to the original code.


He's not just evalling code, but building a function without loops and lots of lookups. That's not something you can generalize.


I'll just leave this here: http://c2.com/cgi/wiki?FasterThanCee


This is only part of the picture. This version of the driver is much slower than the driver based on libmysqclient. See the benchmarks at the bottom. It's a more real world test combining both reads and writes.

https://github.com/mgutz/mapper


"Faster than C" seems to imply that the author is not seeing the true value of C. It is more than just speed.

You can only build so much with Javascript.

With C, the possibilities are limitless.

For a specific task like parsing, use whatever language you want. But please do not believe that by knowing Javascript you can both dismiss C as an optimal language and that you can build anything. You can't, as to either. As it stands, by relying on Javsacsript you're restricted to a browser or Node.js and whoever controls the browser and Node.js effectively has final control over your opportunitities. What's the browser written in? Javascript? What is Node.js written in?

Who cares if your parser is faster than C? If it's "fast enough", that's all that matters. Users of big, complex, graphical browsers or mySQL databases are well accustomed to slow speeds. They have learned how to wait.


Technically, you can write anything in JavaScript, for the simple reason you can manipulate bytes arbitrarily (using Typed Arrays), and platforms like NodeJS and Rhino let you write those bytes to a file and execute it, so you could (in theory) write a x86 compiler in JavaScript and run the result without ever dropping to C.

As an existing example, PyPy -a Python JIT compilter- is itself written in a subset of Python.

In the browser case, it's true that your JavaScript is restricted, but C is even more restricted: it doesn't run at all! (NaCl excluded)


Does Javascript run outside the browser and outside of a platform like Node.js? I want stuff that can run on bare metal as well as on top of other code (software platform).

Personally, I don't care about browsers. One application of a gazillion possible applications. They are an afterthought. I care about sockets and the ability to connect a machine to other machines over a network.

I care about code that can boot a computer, code that can be used to write drivers to control hardware (maybe some new hardware that just hits the market), and code that let's us build on top of that. With this code we should be able to build a kernel and userspace utilities and thereby manage to operate the hardware. Once everything is up and running, then we can install any scripting language we want. We don't have to use the same language we used to build the system to do any work after that, but we could. Indeed many higher level things are written in C, e.g., the interpreters for languages like JavaScript and the web browsers they are a part of. Maybe there's a reason for that?

If the best code for building from the ground up on any given piece of hardware is Javascript, it's news to me. Any examples? I have a new piece of hardware. Can I boot it using JavaScript? Can I control the hardware with JavaScript?

I believe the OP just wanted to do parsing in userspace. Personally I use C for that (generated from flex), but there are countless languages that can do parsing. Why he chose to attack C I have no idea. Like I said, once the computer is up and running (thanks to C), we can use any language we like. We can run "web browsers", and software platforms. And JavaScript. So, have fun with your JavaScript. But I'm pretty sure C isn't going away anytime soon.


Nobody attacked C, not me, not the author. If you disagree, please be so kind to indicate the excerpt where he attacks it.

Interpreters and kernels are written in C because C is a great, and probably the best language for the job. That doesn't mean, and this was my only point, that it's the only possible language that can ever do that; it isn't.

If the best code for building from the ground up on any given piece of hardware is Javascript

Where did anyone say that? I didn't say that. The author didn't say that.

As far as I'm concerned, JavaScript is not the best code for anything except pushing code to the browser.

The only thing I said was that technically, you can write JS to do it. That's all.

Can I boot it using JavaScript? Can I control the hardware with JavaScript?

The only thing that can control the hardware is machine code. You can control the hardware with anything that can generate that. JavaScript can, therefore in theory you can control the hardware with it. Doesn't mean it's a good idea. Doesn't mean it's better than C. Nobody ever claimed that.

But I'm pretty sure C isn't going away anytime soon.

No, it must certainly won't, and thank $DEITY for that.


ice: "Nobody attacked C, not me, not the author. If you disagree, please be so kind to indicate the excerpt where he attacks it."

author: "So fuck - maybe it's time to finally give up and accept that I cannot compete with a well engineered C binding. C must be faster after all.

Well - fuck this! This is unacceptable. Fuck this "C is the only choice if you want the best performance" type of thinking. I want JavaScript to win this. Not because I like JavaScript, oh it can be terrible. I want JavaScript to win this because I want to be able to use a higher level language without worrying about performance."

ice: "As far as I'm concerned, JavaScript is not the best code for anything except pushing code to the browser."

We are in 100% agreement then.

Sure, technically (i.e. by creating a language using a lexer+aprser and some primitives in asm), any language could be used for any purpose. The reason I said what I said about JavaScript being limited is that it was not designed that way, i.e. to do anything. It was as you state, designed to run in a web browser. I would love to use JavaScript from, e.g. the command prompt, outside of a browser, but it has never been easy to do that without pretending you are running a web browser (learning DOM an so forth). The language is designed for a browser. Is that a limitation? To me, yes.

C does not have that sort of limitation. That's all I'm saying. And C works for many purposes right now - my OS has a vast library of C functions to do all manner of things low and high level. And that's without even looking at other huge repositories on the web. Compare this with mere "theoretical" capabilities, e.g. ideas like "low level JavaScript".

I told you why I like C and why I see JavaScript as limited. Not to contradict anything you said, but to explain where I'm coming from. Maybe I would like JavaScript even more than C, if I explored it more fully, but there's no way I'll like it more when it is so limited in what it can do (practically, not theoretically). I approach computer languages from a practical standpoint. I ask myself what can I do if I learn this language? I concluded that for me, C opens more doors, many more doors, than JavaScript. Some people know both. But I'm not that smart. I have to choose.

If I was smart, I'd learn many languages. But I have to work with a smaller set of knowledge.

Given that I have to choose, truthfully, if I had my preference, I'd choose FORTH and devote all my effort to learning and writing in FORTH. Technically anything is possible using FORTH. So what? By focusing only on FORTH I would be losing all the leverage that people's work with C can offer. There is only so much I, with my limited smarts, could accomplish.

Certainly you can understand my position a little, can't you? Why do so many people love Perl and Python? If we took away all the libaries (=enablement, empowerment) would they still love them as much? For what I want to do (i.e. potentially anything, from booting to browsing), C gives me ample enablement and empowerment. Self-hosting JavaScript doesn't. And if someone writes a BIOS for ARM scriptable in JavaScript, but they write some part of it in C, well, I'm still going to want to learn C before JavaScript. That's just how I think.


I don't think those excerpts show any attack on C, he just doesn't like that he can't use higher level languages without sacrificing performance. Which is a position that you may disagree with, but I don't think it's an attack on C.

would love to use JavaScript from, e.g. the command prompt, outside of a browser, but it has never been easy to do that without pretending you are running a web browser (learning DOM an so forth). The language is designed for a browser.

I don't think there's anything in the language itself that is designed for the browser; it's just the standard library that is lacking.

The Rhino shell, for example, comes with functions like readFile/2 and runCommand/N which are much more adequate for that kind of programming.

But it's certainly not as useful as C, and I certainly don't use. Though I tend to use Python, not C either (ctypes is awesome).

C does not have that sort of limitation. That's all I'm saying. And C works for many purposes right now - my OS has a vast library of C functions to do all manner of things low and high level. And that's without even looking at other huge repositories on the web. Compare this with mere "theoretical" capabilities, e.g. ideas like "low level JavaScript".

Sure; I don't think anyone denies that.

That said, it's not true that those functions are closed to you if you use JavaScript; check out node-ffi: https://github.com/rbranson/node-ffi

Running JS on bare metal is, at the moment, a pipe dream, though.

Certainly you can understand my position a little, can't you? Why do so many people love Perl and Python? If we took away all the libaries (=enablement, empowerment) would they still love them as much? For what I want to do (i.e. potentially anything, from booting to browsing), C gives me ample enablement and empowerment. Self-hosting JavaScript doesn't. And if someone writes a BIOS for ARM scriptable in JavaScript, but they write some part of it in C, well, I'm still going to want to learn C before JavaScript. That's just how I think.

Sure, I can understand your position perfectly. I just don't think your portrayal of the article was fair to the author, that's all.


An equivalent claim: Faster than Assembly? Parsing binary data in JavaScript. Pah.


Check the code : https://github.com/felixge/node-mysql

Note: it uses node_buffer.cc which is some C++ code in node. So it is not exactly pure Javascript.


Why does everyone keep saying Doing X in Language Y is faster than X in Language Z?

Really they are comparing compilers, not languages. Everyone seems to just keep making potshots at Language Z.


Please stop with the X higher level language can be faster than C unless you can challenge the limitations imposed by the laws of physics. Not which compiler is better. I can always find a better or worse C or JS compiler/JITter so that proves nothing.

Doing more (Which all more highly abstracted languages currently do) in less time with all else being the same is not possible as we understand quantum physics today.

This title is clearly linkbait...


> Please stop with the X higher level language can be faster than C unless you can challenge the limitations imposed by the laws of physics. Not which compiler is better. I can always find a better or worse C or JS compiler/JITter so that proves nothing.

Turing equivalence and not even turing equivalence but 2 pieces of code with roughly the same functionality does not dictate the speed between them. You seem to be under some sort of misconception that two pieces of code have to be implemented in the same. For a long time tcl led the computer language shootout regex test because it has a wicked fast regex library(written in c I think). Nowadays the c version of that test uses the tcl regex library and is beaten by v8(chrome) javascript's even faster regex library(written in c++).

It is hard to beat c in speed and it is rare when something implemented in a different language does it. When it does it is frequently do to the algorithm/way it was implemented. The reason that this is so is that few people care enough about beating c with c++ being the only real contender. if you are careful you can beat c code with c++(almost all c++'s slower features do not slow it down if not used) add that to some cool compile time tricks with template metahackery and c++'s better inlining and you can do it.

The other part about beating c is complexity. Certain things are complex to implement in c. There is a reason we use so little assembly anymore, it's possible for smart people to beat optimizing compilers for certain cases but the general case isn't so pretty for it. Also with the rise of more/cheaper memory for gc to work well(and when it does it goes like hell on wheels) and parallel computers(parallelism being much easier in some languages then c) we may see it more soon. People have been saying that for a while but still.


>Turing equivalence and not even turing equivalence but 2 pieces of code with roughly the same functionality does not dictate the speed between them. You seem to be under some sort of misconception that two pieces of code have to be implemented in the same

I am merely pointing out that there is overhead with every VM. This is especially true with every current JITted JavaScript in use today (more so than with the JVM and CLR). So how could it possibly be faster if both implementations use an equal amount of optimization otherwise.

How is this even ever an argument?



> So how could it possibly be faster if both implementations use an equal amount of optimization otherwise.

Who says they are?


Anyone who says that JS or X other VM dependent language can be faster than C must say this to have a leg to stand on.

They cannot say this??? Thus my point...


INFLAMMATORY headline for self-branding and publicity , doesnt go much further. Yes javascript can be fast but in the end , having to write evals to gain performances demonstrate that there is something really wrong with that langage...


I disagree!! Being able to use evals to dynamically generate code for unrolled loops (and other similarly specialized procedures) sounds like a pretty amazing tool, and I can't not consider having it readily available an advantage of Javascript compared to C.


Um every fast and decent JS engine IS WRITTEN IN C!!!

I refuse to click on anything as ridiculous sounding as "Faster than C? Parsing binary data in JavaScript".

JavaScript will NEVER be faster than C. If you personally test it and it is - all that you have really proven is that the C compiler you are using was horribly written and is probably 20+ years old. The level of ignorance that programmers have about low level languages and the performance cost of abstractions amazes me sometimes.


This is a very silly point of view. What you think you're arguing is that Javascript can't conceivably be faster than native code, and you're conflating C with native code. But C isn't machine code either; like Javascript, it's transformed into machine code by a compiler.

I don't generally think that Javascript runtimes are going to routinely beat C compilers for most performant execution of basic programs any time soon, but I'd happily bet that some high level language JIT is going to give C a real run for its money sometime soon. That JIT will inevitably be expressible in C, but when your recourse as a C programmer is "implement the important parts of the JIT for language X, then proceed to solve your real problem", you're not making much of a case for C.


I am not even close to conflating C with native code (although it is the lowest level language next to Assembly). C is the lowest level structured language and JS is among the highest. The fact that they are both ultimately compiled to a processor level binary means very little.

Since it seems so simple and plausible that a high level JITted language can be on par with C, why did you not explain how?

You cannot because you clearly don't understand language compilation and the laws that exist between performance and abstractions - so I am confused by your argument.

Let me put it simply, take any two languages - both ultimately compile to machine code, one has the overhead of bounds checking, run-time type resolution and garbage collection (there is actually much more that I could mention but for brevity...) and the other does not. Now please explain to me how the one WITH all this overhead could possibly be faster?

There is only one way - If the C compiler were egregiously under-optimized.

This will be the case till the end of time. All other things being equal, the executable code with more overhead to slow it down will lose. This seems a very simple concept to me - I cannot understand how it is so hard to grasp. Perhaps it is because along side learning Java, HTML and JavaScript - I also learned Assembly Language, C, C++ and hardware architectures.


"C is the lowest level structured language and JS is among the highest."

What does this even mean?

Ten message board style points for assuming that anyone who disagrees with you must not know C.


If you or anyone does not know what a high/low level or structured language means - that is fine.

But WHY would you attempt to make arguments that require basic understanding of such things.


How about you stop calling "C" a low level language?


That you for the valuable response - BTW I only claimed that it was the lowest level structured language.


Which is also a silly claim.


I think you should review definition of "low-level programming language" and learn about assembly languages that support structured programming.


This argument is tired, but I'll rebut it anyway. Yes, every performant JS engine is written in C, but that doesn't matter, even a little bit. When the code is compiled to machine code (as in V8) you're on a level playing field; all that matters is speed of compilation and how well the compiler performs.

If I write a C compiler in Python with the same optimizations as GCC, is the output any different? No.

So the argument has to be: there is something fundamental in JS that prevents it from being compiled to code as fast as C. That argument holds up for whole programs -- there are places where you just can't optimize JS greatly -- but if you're talking about specific bits of code, there's no reason it can't match (or surpass) C.

At the end of the day, JS can be quite fast, and the arguments against it don't hold up to scrutiny.


"there's no reason it can't match (or surpass) C."

No reason?, so run-time bounds checking, type checking/resolution and GC are free of charge then (as in no performance penalty)? Managed heap re/allocation are free? JITting is even free right? What about when the machine is low on virtual memory? can it compete them? how about when there is not an unoccupied processor core and ram channel available to be dedicated to a GC cycle? What about the context switches that exist on every non RTOS? and how this affects a stack based VM? A modern JS engine is heavily slowed by the stack/register abstraction that the VM utilizes when the machine has other tasks on hand.

How about that for some reasons? I am looking forward to your rebuttal... Tell me how doing more work can be faster please? There must be something I am missing here.

Sure there are great VMs that are blazing fast and are absolutely a sufficient tool for a large majority of tasks at hand - fine. I am just tired of the "fast as C" or "Faster than C" statements by those who appear to always feel slighted by the fact that their language is not fast as optimized C and the proclaimed (and false) expertise by users of such languages. They have no knowledge to back up their claims so instead of engaging in a discussion - they simply down vote with bitterness.


> No reason?, so run-time bounds checking, type checking/resolution and GC are free of charge then (as in no performance penalty)? Managed heap re/allocation are free? JITting is even free right? What about when the machine is low on virtual memory? can it compete them? how about when there is not an unoccupied processor core and ram channel available to be dedicated to a GC cycle? What about the context switches that exist on every non RTOS? and how this affects a stack based VM? A modern JS engine is heavily slowed by the stack/register abstraction that the VM utilizes when the machine has other tasks on hand.

All of these can be summed up simply: none of these things have to happen in the execution of JS code. None. They're implementation features.

Take this JS code:

    function addfive(x) {
        return x + 5;
    }

    var correct = addfive(3) == 8;
There is no need for garbage collection, it can be purely type inferred and compiled statically, and the object representations could be minimal (there's no reason it can't use tagged ints Ocaml-style).

Again, you're arguing that all JS code can't be as fast or faster than C. That's obviously true, but it has absolutely no value in the real world. What matters is that some code -- especially math-heavy code -- can be just as fast as C, because it compiles to the exact same thing.

I'm no JS fan, but I've spent a lot of time working on compilers for other "high-level languages". I can say, without a doubt, that C is not the be-all and end-all of programming languages.


This is a straw man argument. You are reducing the claims made by both sides here into a function that adds primitives REALLY?

You know full well that this is complete BS. Nothing meaningful(including the original blog post) can be done in JS and have the code emitted even come close to the compiled code of the C implementation of the same function. Sure a few bytes here and there MAY be the same and therefore execute in a similar amount of time (as long as a GC Cycle doesn't happen to run in the middle of it) - but it is ridiculous to even compare the two overall in this manner.

As for C not being the be-all and end-all of programming languages... Who ever made this claim? Personally - I don't even like using C. Are you trying to create a diversionary argument to make-up for the edge case you presented that MAY execute as fast as a C compiler output?

Please only reply with real challenges. Not edge cases.


And not a single word about DTrace?


Thousands of words about optimizing the reinvention of a wheel.

I thought we were hackers? We use libmysqlclient and stfu because we don't give a shit what language a client library is in because it WORKS and isn't unacceptably slow and LETS US SHIP.

I really dislike this whole crowd and attitude.


What point are you trying to make? This kind of crowd and attitude is why you have a client library that works and isn't unacceptably slow and lets you ship.


Reinventing the wheel is a good thing when what you get is a better wheel, or even just one better suited to your purpose.

Ever notice we're not driving cars on ox cart wheels?


As someone once brilliantly (I thought) put it on HN: has anything ever needed more reinventing than the wheel?


>Thousands of words about optimizing the reinvention of a wheel.

Without the "re-invention of wheel" we would still use stone wheels a la Flintstones or wooden carriage wheels. And without optimizing our wheels we would still have the 1920's version of rubber-made wheels.

>I thought we were hackers? We use libmysqlclient and stfu because we don't give a shit what language a client library is in because it WORKS and isn't unacceptably slow and LETS US SHIP.

And you "thought you were hackers"? That's not a hacker attitude, that's an enterprise code monkey attitude. I mean, we "use it because it's isn't unacceptably slow and it lets us ship"? WTF.

Hacking, in the purest sense, is not even about shipping at ALL. It's about the joy of tinkering and discovering and improving and optimizing.

It's not about shipping some stuff to the market with whatever happens to be available, and some "good enough" mentality.

>I really dislike this whole crowd and attitude.

It's called _Hacker_ News for a reason. Perhaps you were looking for "Building average shit with off the shelve components News".

I mean, _complaining about_ and writing that you _dislike_ a guy:

1) creating a free, open source, library useful to many

2)improving upon the status quo in MySQL driver libraries for Node

3) writing about it, to present his results, other's improvements, and useful tidbits he found?

It must take a very disturbing sense of reality, entitlement, and self-importance to do it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: