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.
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?
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.)
I am so happy that I've never had to do that in my career.
In fact, if the tiny reads are still there in the MySQL C client, that in itself might explain the difference.
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.
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.
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.
> 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.
> 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.
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.
"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.
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.
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.
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.
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.
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?
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.
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?
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.
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.
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.
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.
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.
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.
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.
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.
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.
Ever notice we're not driving cars on ox cart wheels?
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.
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"
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
Besides, that's just an example snippet.
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.
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.
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...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.
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.
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'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.
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.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).
Which tools have you found useful?
I don't know, I use neither. I'm just saying, there are profiling tools which handle the "One Big Function" pattern.
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.
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)
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.
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...
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.
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?
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.)
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-).
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.
Note: it uses node_buffer.cc which is some C++ code in node. So it is not exactly pure Javascript.
Really they are comparing compilers, not languages. Everyone seems to just keep making potshots at Language Z.