Advertisement

Do software engineers really need to know low level stuff anymore?

Started by March 25, 2011 03:11 PM
22 comments, last by Antheus 13 years, 10 months ago
Yea I'm conscious of Math applied to various fields, just not as in detail as you did. The math is you mentioned is applied Math and people in different disciplines learn a bit from a very huge set called math, and most of the time people learn to apply it, not to do mathematics like mathematicians (like developing math theory). In the IT industry, Math is good to have, but not all programming jobs require Math.


maths is maths.
cynical math rant ->
ask a mathematician to write some code and suddenly you might start to feel alot smarter than them. There formulas and notation are crap. They cant explain 1/2 of what they calculate yet proclaim to understand it fully. Mostly they are just spending longer on the task for completeness. Once you break them formulas down into their different parts and write it up into a functional language you will probably understand it.

if your programming job doesnt require maths your doing it wrong.

if a given program is 10% slower in Java than in c++, its 10% slower no matter how fast is the computer.

Not quite.

Java, by design, is a 386 CPU overclocked to 3GHz - no pipeline, no cache. Due to design constraints, there are limitations which cannot be overcome.

JVM scales with memory latency, not CPU power. It's completely IO bound. As a consequence, as CPUs get faster, Java is getting effectively slower. For many algorithms there exists a partial workaround, namely not using objects but arrays of primitives. Math libraries intended for HPC use this approach. The result is fast, but almost utterly unreadable code (see example above).

Places which need high programmer productivity want Java for its ease of use and simple code. Places which value fast code will use better language.

For embedded systems, everything is structured around primitive types and offloading as much as possible in simplest way to hardware path.

For business applications which are already IO bound, the above doesn't matter, most of time is spent waiting for database. Real-time, low latency applications and most things related to multimedia however do. Java specifically (not managed languages) suffers from a memory model that is simply the exact opposite of what CPUs can do well.

C#, despite having worse-performing VM has different type of memory model which does not suffer from this. It's one of the reasons why C# is widely used for tools, but not necessarily the main reason.
Other reason, when it comes to Java in particular, is abysmal support for video and audio. With Oracle takeover, desktop or client parts have been effectively abandoned.
Advertisement
Java, by design, is a 386 CPU overclocked to 3GHz - no pipeline, no cache. Due to design constraints, there are limitations which cannot be overcome.JVM scales with memory latency, not CPU power. It's completely IO bound.


As a developer coming to Java from a C++ background, I'm quite interested in this - can you point me in the direction of any references on this topic?

Of course the comparative real-world performance of languages cannot be easily quantified - it depends too much on the specific benchmark and the hardware it is running on.


It's also worth remembering that sometimes the naive implementation of a particular task in a language like Java can outperform a fairly literal translation into C++, although it's almost certainly possible to make C++ perform faster if you dig just a little deeper.


As a developer coming to Java from a C++ background, I'm quite interested in this - can you point me in the direction of any references on this topic?

struct Foo {
float x,y,z;
}

Foo stuff[A_LOT];
In C, C++, C#, this will result in one single block of memory, with elements stored inline. In Java, the following will occur:Foo * stuff[A_LOT];If iterating one by one, each element access will cause a pointer fetch, require branch predition and likely memory stall. It gets better - each time garbage collection runs, order of Foos in memory may change, resulting in non-deterministic behavior.

Basically, Java memory model throws away branch prediction, pipeline, caches and speculative execution. The only advances CPUs made post-386 and the reason for their exponential performance growth. Without those (try turning off L1 cache in BIOS on an i7 or similar), the CPU performance increases linearly, with memory, and that has only gone up some 5 times over same period.

Of course the comparative real-world performance of languages cannot be easily quantified - it depends too much on the specific benchmark and the hardware it is running on.[/quote]I don't run benchmarks.

Here is a real world example. ~5 TB dataset, one needs to perform some ad-hoc correlation. Since data is text, C/C++ is pain due to poor out-of-box support for UTF8. In Java it's trivial.

But to process stuff, I needed a lookup table, something like a Map. HashMap works. The standard library of HashMap in Oracle's JVM is a fine piece of engineering and algorithmically perfect. The actual processing took 18 hours * 4 cores, needed 4GB just for this one Map.

The problem - each entry in the Map is a separate object, each entry needs to be traversed on GC and each dereference has high probability of a miss.

Cause - since data is so large, most accesses caused L2 cache miss.


Solution is quite simple - use a data structure that stores more data in continuous blocks. In Java, the only continuous blocks are arrays of primitives. While I was tempted to drop to native code, it would require more work, so I beat Java into submission, even if it required some really ugly code (see above example). The new "map" simply used one char array and two int arrays, the latter two were the "pointers".

Result - ~300MB memory, 2 hour runtime on single core. Simply because of drastically reduced L2 pressure.


Some would recommend tools like Hadoop, cloud computing and similar. A good solution, inherently scalable, proven and tested. Except that it would require obtaining enough machines, none of which is free. It may also not be allowed as per company policy to move code or data outside, and obtaining in-house resources requires submitting request for cluster time which may take days or weeks. And - it would take ~50 machines to complete in 2 hours what a single machine can do now.


At which point, switching to language which is better suited for such processing makes sense. C# is surprisingly good candidate. Beside some really nice syntactic sugar (LINQ) it also allows one to seamlessly and painlessly drop down to lower level without resorting to native code. This doesn't make C# the best language, it just covers more ground.


None of this is a deal breaker most of the time and for most CRUD applications it doesn't matter.

My anecdotal experience shows that Java stalls at some 1/30th of theoretical throughput due to above reasons. So do most C and C++ applications. Does it matter? Most of the time it doesn't. But if working on visualization or data processing, would you rather it runs at 60Hz or 2Hz? Would you rather wait 2 seconds or one minute? C and C++ are preferred since they allow those rare edge cases to be optimized. Java makes this a pain or almost impossible.

The implications for long running tasks are even bigger. Assuming one is choosing between 1 hour or 24 hours. The first one is likely to succeed in one go. Even if something is wrong, it can be restarted. With 24 hours, you need to wait till next day or build application to support restarts. The 1 hour allows 24 iterations in same time it takes to complete one slowly.


Java in Oracle's JVM can be fast, it is competitive with non-SIMD native code. But to use hardware liberally it requires too much wrestling with language, so suitable existing implementations are few and far in between. None of them use standard interfaces either since those are unsuitable for such work.

But as mentioned, most of the time it doesn't matter.

This topic is closed to new replies.

Advertisement