4 ms·
This has always been true and will continue to be true. It's possible to build a high level language that's as fast as C? Sure--but only if you restrict the p
by DarkShikari 17y ago
This has always been true and will continue to be true.
It's possible to build a high level language that's as fast as C? Sure--but only if you restrict the programmer to the same amount of effort in both languages. If your application is one where it's worthwhile applying a great deal of extra programmer time in order to improve performance, a low level language will always win because it exposes more of the native machine.
The goal of a high-performance high-level language should be to provide C-like performance for a reasonably unoptimized application. Once one starts to optimize a program down to the last instruction, staying on par with a low level language becomes simply impossible for a high level language.
In my experience, every level of abstraction one creates away from the machine limits your performance by some amount. This can be demonstrated without even leaving assembly language!
Fastest possible: raw assembly code in a NASM-like assembler. With this, you can write basically any code possible with no limitations, at the cost of extremely high programmer time costs.
Shortcut: Use inline assembler instead of NASM to simplify calling convention and other niceties.
Cost: There's now a whole bunch of stuff, like calling convention optimization and computed jumps, which you can no longer do.
Shortcut: Use compiler intrinsics instead of raw assembly.
Cost: You can no longer tweak your algorithm to minimize register spills because you aren't directly controlling spills anymore.
Shortcut: Use a set of macros (like my project does) for handling calling convention, MMX/SSE abstraction, and other such simplifications.
Cost: You tend to overlook optimizations that apply to one possible output of the abstraction and not others, resulting in either messes of ifdefs or suboptimal code--the former of which is of course violating the abstraction.
Shortcut: Use a framework like liboil to write SIMD assembly instead of native code.
Cost: By using generic SIMD operators, you lose access to specialized architecture-specific operations, along with the aforementioned issue of register spills.
Here we haven't even gotten beyond assembler and we're already losing performance. Now scale this up to C and beyond: abstraction inherently comes at a performance cost. It isn't even merely a function of language: abstractions within a language reduce performance as well.
- Locke1689 17y agoCouldn't agree more. One thing to remember though: "Premature optimization is the root of all evil." C Git is optimized and fast. Mercurial, with a combination of Python and C, is almost as fast. Maybe not quite as fast, but fast enough for me. A lot of the time those optimizations just don't pay off in terms of programmer time.
- DarkShikari 17y agoSlightly tangential, but I think "Premature optimization is the root of all evil." is the most misquoted statement in the history of computer science. Most importantly, people tend to misinterpret "premature" to mean "any time before the software is done" or similar. I can't even count the number of times where I've worked on or watched a project where performance is important and the following series of events occurs: 1. Module is designed with that quote in mind: it must be simple to implement and performance is unimportant. Note that this isn't a prototype: this is a plan for the actual final product. 2. Module is built and finished, then submitted for a review. The reviewers, knowing the importance of performance for this module, point out a number of ways that the module is extremely suboptimal. 3. Because of the assumptions so heavily ingrained into the module, implementing these performance improvements--which could have been foreseen as necessary far earlier--requires a near-complete rewrite of a large part of the module. It's exactly as if we finished our software and our customer decided that his requirements were actually totally different--except in this situation, it's entirely our fault, because performance was a requirement and we ignored it because we didn't want to optimize "prematurely". If you want performance, you have to design with performance in mind; if you don't, and then decide later you want performance, the cost of your earlier decision is magnified a hundredfold. I have almost never seen that quote used correctly.
- barrkel 17y agoWell, the fact that it says that something "premature" is causing a problem seems to me to mean that it's actually a tautology. It's like saying kids are immature; but of course, what is more of the nature of an immature person than a child? So yes, optimizations that are made before they should have been made, should not be made. It tells us little about optimizations other than that there is a time for which they are premature, and doing them at that time is premature.
- philh 17y agoI think the important bit is "the root of all evil": it also tells us that doing optimisations prematurely has the potential to destroy your project. Compare with something like, "premature optimisation will take a little longer to perform, and perhaps be not quite as optimal, but isn't that big a deal in the long run, really."
- rdtsc 17y agoAnother thing to keep in mind before optimizing is the 80/20 rule. Usually only a small part of the program (20%) needs optimizing. Of course one needs actual performance numbers (via profiling for example) before knowing what to optimize. There is nothing worse than faith-based performance assumptions. I have seen months being wasted re-writing code in a lower level language to "make things faster" only to find out that it didn't make a difference, the code was disk or network bound and not CPU bound.
- barrkel 17y agoOf course, managed languages can buy you other things, such as inlining indirect method calls by rewriting the call site (polymorphic inline caching), dynamic profile-guided optimization, not to mention the fact that garbage collection is often faster than manual deallocation, depending on the nature of the problem and the pattern of allocations. (Of course, design of managed applications can benefit greatly from awareness of how the GC works). WRT SIMD operators, I'll point you to Mono.Simd.
- blasdel 17y agoI found that I had to read your comment carefully to realize that I agreed with you, because I'd already flipped the bozo bit 3 words in when you unnecessarily used parochial microsoft nomenclature.
- barrkel 17y agoWhat word would you recommend I use to cover everything from Ruby to Java? FWIW, I think you'll make the same mistake pretty often if you continue to think of folks who play in the MS pond as bozos. There are reasons MS is a leader in many markets.
- blasdel 17y agoAnything but 'managed' -- while conceptually it covers things quite nicely, in practice it's used almost exclusively to mean "runs on the CLR", by those living solely within the Microsoft ecosystem whose knowledge of programming languages comes from Microsoft marketing materials. It's a loaded term. There's plenty of nomenclature abuse in that ecosystem, like using 'assemblies' to refer to packages or 'blittable' for SHM. 'Garbage Collected' (or GCed) works fine instead of 'managed', especially since 'runs on a VM' is pretty nebulous, and the whole C++/CLI thing adds some confusion.
- barrkel 17y agoI don't use it to exclusively mean CLR-hosted, and to be frank, I think the meaning is pretty clear outside of MS contexts. I believe "GCed" focuses too much on the memory allocation strategy; which while important for many of the practical advantages of managed languages, I think it ends up lopsided. Finally, more people using a word in an alternative way is the path to controlling its meaning, rather than avoiding the word altogether, cf "queer" and the like.
- vii 17y agoThis completely misses the point. The reason JGit cannot compete with Git is not that it is using an extra cycle or two to make function calls. The problem is that Java cripples you in the sort of data-representations you can use -- no mmap, no value types -- forcing lots of extra copying. There's no reason a language can't provide these features, and I don't know that they require significant extra programmer effort. C# does it, etc.