Auto-Threading Compilers Are Here
developinthecloud.drdobbs.com
developinthecloud.drdobbs.com
"The power of a single CPU core has plateaued and won't ever get faster. CPUs are only getting more cores."
Pretty sure that isn't true. It may be getting more difficult to make CPUs faster, but advancements in CPU architecture continue.
But it can also bring some problems that might limit performance, such as bottlenecks on shared resources such as memory and I/O. If the problem can divided into fairly large and independent chunks of work, on the other hand, then distributed computing becomes a lot more attractive.
In single threaded code, the unused cores can be powered off.
Second, DRAM is made differently from CPUs, and it is difficult to use two different processes on the same silicon.
Third, squeezing 4GB of DRAM onto a single CPU die? How?
Think about how much larger a CPU would have to be to include an entire gigabyte of cache, much less multiple gigabytes.
Another interesting note from that talk was that they had spent a large amount of time making an 8 socket architecture with quick-connect paths between all pairs of sockets for memory transport. Unfortunately that was not as important as believed either, since the programs that typically benefit from 8 CPUs normally have good memory properties anyway.
Not sure if either data-points are true, but interesting nonetheless.
A single core of my i7 does something like 6 or 7x the work a single P4 core does, at half the mhz.
Cores are getting faster, but we're also putting more on. Why not? We can afford to do so.
>he power of a single CPU core has plateaued and won't ever get faster.
Sigh.
Do you have a reference for this? I'd be surprised if it's more than 2x for general-purpose code. (It might be more for specialized stuff like video decoding, which I guess has improved hardware support these days.)
http://www.cpubenchmark.net/singleThread.html
The new i7's float around a rating of 2,000.
A netburst vintage P4 at 1.8ghz rates 217 (original P4 2001). 358 if we move up to the 2.8ghz model (2003 model). So anywhere between almost 10x the performance to 5.5x depending on model, mhz, etc.
Note: pentium is a brand and later its the budget name of C2D's, but this comparision to P4's.
No idea what cpubench uses, but its not soley a video benchmark, its more of a mixed bag.
But for some more general application, this might not be true. Then again it depends. For example a lot of the Adobe 2d-filters would gain from such thing, if the data is accessed the right way (swizzled if possible). But then such algorithms usually tend to be one of the 13 dwarfs that are easily parallelized using OpenMP, or rolling your own thread-version. Or even with CUDA/OpenCL/DirectCompute - but then you might have to pay for the communication between the CPU/GPU, and loss of result, or instability of results across machines (different floating point accuracy tradeoffs for the sake of speed).
But then the problem comes with state-machines, for example an LZ compression, or anything that relies on results from before. This is very hard to data-parallelize.
But yeah if your load is specific like floating point calc or mp4 encoding, then it will vary, but its a good shorthard to have these types of conversations, especially when people go half-cocked about how CPU progress has stalled which it clearly has not.
Okay, point taken. But how much more improvement is there to be had just from architectural improvements, with no more movement on clock speed?
It's because of a lot of things. Perhaps the i7 has more pipelines, but significantly it also has much shorter pipelines. Stalls were really, really expensive on the P4's 30-stage pipeline. Plus there's hyper-threading. And of course the i7's got a lot more going for it in the cache department.
The "won't ever get faster" part should be qualified, though, with "at least not on silicon". There is still the possibility of a breakthrough using some other semiconductor -- silicon germanium, buckytubes, or something. Any such thing is years away, admittedly.
The assertion that we hit the limit in 2004 and CPUs have not gotten any faster (in the useful sense of the word) is ridiculous, and for someone to still be perpetuating the gigahertz myth in 2012 is bewildering. My MacBook Pro has a 2.2Ghz Core 2 duo, and my netbook has an Intel Atom 1.6Ghz, and I can tell you now the MBP single core speed is not merely 40% faster!
Even in functional languages, auto-parallelization hasn't worked well because of the coarseness issue: it's difficult for compilers to figure out what to run in multiple threads and what to run single-threaded because of tradeoffs with inter-thread communication.
It's just like the GPU, you need massive amounts of data to overcome the communications overhead.
That F# can outperform C on numeric code should tell you that the optimizations available to functional code far exceed those available to languages that poke bits.
This is just one more micro-optimization to overcome what a bad idea it is to poke beads on an abacus rather than use mathematical rigor available in calculus.
Do you have a citation for this? I love F# and I've written some fairly pointer-intensive code with it, but the CLR's code-gen is pretty bloody abysmal[1]. F# does more optimizations than C#, but most of the heavy lifting is left up to the CLR/JIT (obviously).
In fact, I find I have to experiment with F#'s inline feature for high-perf code, because the CLR optimizer works far better on big functions than inlining/optimizing calls to smaller ones. Even simple stuff like removing a tuple allocation is not done. Even basic things like eliminating the allocation of a tuple when it's obvious you're immediately deconstructing it is not done. F# doesn't even lift lambdas, as of 2.0.
F# doesn't even do fusion like Haskell, so for high-perf code, you're often giving up nice functional code and resorting to loops and mutability. Just check the F# stdlib implementation.
So while I really do love F# and enjoy writing in it, "faster than C" is not really applicable. A: You'll be writing C-in-F# (which is fine, if most of your app isn't that way), B: the codegen isn't remotely competitive with a modern C compiler.
[1] Edit: OK, that's an exaggeration, but I mean in comparison to what you'll get out of a C compiler for equivalent, low-level code.
"The group has written sev- eral million lines of code, including: core libraries (includ- ing collections with polymorphism over element permis- sions and data-parallel operations when safe), a webserver, a high level optimizing compiler, and an MPEG decoder. These and other applications written in the source language are performance-competitive with established implementa- tions on standard benchmarks; we mention this not because our language design is focused on performance, but merely to point out that heavy use of reference immutability, includ- ing removing mutable static/global state, has not come at the cost of performance in the experience of the Microsoft team."
"we mention this not because our language design is focused on performance, but merely to point out that heavy use of reference immutability, ...has not come at the cost of performance in the experience of the Microsoft team."
Stop trolling[1] http://en.wikipedia.org/wiki/Pipeline_hazard [2] http://en.wikipedia.org/wiki/Branch_predictor
Same with C/C++ I'm not sure what you mean "without anything substantive making it to industry".
The hard problem is making the compiler automatically figure it out, and as OP says they haven't done so usefully (yet).
Functional programming is a style of programming which uses the lambda calculus as its base model of computation. Just because you can subvert that at times doesn't mean that idiomatic code doesn't disapprove of breaking referential transparency.
The ST monad is there for many reasons but if you can avoid it you probably should. If profiling says it's necessary, then add it.
Look at Coq.
There's no reason to avoid ST, and in many cases it makes the code clearer and shorter than trying to figure out some pointfree contortionism to reach the same goal.
I'll look at Coq when it has support for binding to C libraries, opening sockets, or doing anything else than a programming language needs to support.
This is always the user/theorist divide. I'm not saying that sometimes ST isn't necessary, but it should always be the smallest necessary imperative subset.
By the way, the authors of the ST monad make this same point (read the paper). ST is (by necessity) always single threaded. It ruins modularity by not being able to interact with any non-ST code. In short, it's not functional.
Anyway, theorists will continue to do interesting things with Coq and whether or you think it's sufficient as a "programming language," it's useful to us.
They basically describe a modified C# language, with global state (static variables) eliminated - any global state is immutable only. Naturally, anything marked immutable cannot access anything marked writable, so unless you want to put writable permissions on everything (turning it back into standard OOP), you're going to need to design programs around immutable data by default. Also, anything marked writable in the new language can only be written to by one thread at a time anyway, since the writable references are unique.
The result is a significantly different style to the traditional imperative OOP people are used to, so it's not like you can lift an existing program into this paradigm without problems.
If the author thinks that FP won't become mainstream, what makes him think that this will?
"In most FP languages, variables are declared immutable by default."
That doesn't sound like a claim that mutable state is impossible. Perhaps we should spend more time reading and less time criticizing...It's really not about compilers, fp, not fp so much as to what kind of tasks are easily multi-threaded. As I replied in another post - things like state-machines are very hard to parallelize (one of the dwarfs that the article below talks), while others very easy - like raytracer (to a point, since a raytrace have to share data across all computing units - cpu-s).
(An article from 2008)
No.
Parallelism implies that there are multiple CPUs and/or multiple cores at work (or in older use of "parallelism", at least some instructions that are parallelized).
Multithreading doesn't imply that at all: you can have a multi-threaded program (like, say, a Java program using multiple threads + its GC thread, EDT thread, etc.) running on a single-machine using on CPU which has a single core and which doesn't do any kind of parallelism.
To me you're totally wrong in saying that multithreaded code is a particular kind of parallelism.
Multithreading doesn't imply parallelism.
However, I was not primarily concerned with this distinction, but with the distinction between obtaining parallelism through multithreading, versus parallelism through message passing. Multithreading implies that parallel threads will communicate implicitly through shared memory, which does not scale past a single machine.
Pig can turn a combination of relational operators into a series of Map and Reduce operations that can be done on a Hadoop cluster. This is all stuff I can code up by hand, but most the things I might do with a shell script or SQL statements I can parallelize in a way that's scalable in both directions. Because I can write parallel code easily and quickly, I can use it to do little jobs. As for big my home cluster handles terabytes and I can rent any level of power from AWS.
The group has written several million lines of code, including: core libraries
(including collections with polymorphism over element permissions and
data-parallel operations when safe), a webserver, a high level optimizing
compiler, and an MPEG decoder.
So it also handles data-parallelism.http://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf
Incidentally, I hear this paper is quite similar to one that the Rust[1] folk recently authored regarding their "borrowed pointer" system, due to be possibly published next year. If this sort of thing interests you, I suggest you take a look at Rust (though keep in mind that it's still very pre-alpha).
Disclaimer: my thesis is on a very similar system for a different programming language (before this paper was released), with some differences. For example they assume mutable is the default, where I assume readonly is the default.
https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pd... (this is the TR linked from the Dr. Dobbs thing.)
Automatic parallelization has been the holy grail of performance-based computing since the 1980's or earlier, and if auto-threading compilers had arrived we would all know about it.
The fact remains that for general-purpose code, automatic parallelization is an unsolved and exceedingly difficult problem. So difficult that PG claimed it as one of his highly ambitious startup ideas.
Assuming that he's merely talking about CPU frequency, does that hold? And if so, why?
1. Simulating a large world using complex entities and voxels
2. Being single-threaded with no clear way to make them multi-threaded
Minecraft in particular is a pretty interesting problem since it only simulates the part of the world that's within a radius of a player, it would make sense to have each player's machine simulate their own part of the world and the server to somehow merge those together.
Minecraft, to me, is a visual 3d database -- digging dirt doesn't remove something, it merely changes the value for that block in the database -- from "dirt" to "air" -- which changes how the game's algorithms act. And the game still ships with "developer graphics" which would have been easy for a TNT to run.
I can't imagine people would trust each other enough to allow them to simulate themselves.
Think of a player crouching on a plank that another player just phasered. If you continue simulate the first player's movement "crawl forward" by itself, how do you integrate the result of the plank being disintegrated, causing the player to fall? The first player's simulation outcome depends on multiple inputs, but they aren't findable directly from that player's perspective. You have to first simulate the phaser beam to know the plank is gone to know the player is falling now, not crawling.
And then imagine that with far more complex rules and a few hundred thousand objects having similar interactions, each one possibly modifying any other one.
But today's games involve a completely different paradigm. Almost all the games today have such a huge focus on open worlds and modeling the interaction between hundreds of thousands of objects in real time. Even the most GPU-intensive such games can still realize bigger FPS gains with a CPU upgrade than a GPU upgrade.
In the section on concurrency, he notes the hardest part is updating the game logic (tens of thousands of interacting objects) and notes that synchronizing it is hopeless. Instead, STM:
"~2-4X STM performance overhead is acceptable: if it enables our state-intensive code to scale to many threads, it’s still a win. Claim: Transactions are the only plausible solution to concurrent mutable state"
It's also a neat presentation as it's from the perspective of someone running a real large scale, commercial, time-sensitive, _real world_ software project. Yet he talks about the most common types of bugs, and how FP and other advanced concepts would help (like dependent typing).
1: http://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-...
> By 2009, game developers will face CPUs with 20+ cores.
Anyways, fact we only have ~16 core CPUs today just means he was off on the timeline, and got a slightly bit more "free lunch" for a few more years: a single threaded program gets 12% instead of 5% of a CPU's capability.
The underlying "we're screwed without better tools" still stands. Besides, the work required to take advantage of 8-way concurrency on mutable state is the same required for 32-way.
It wasn't until recently (a couple weeks ago, when giving a presentation on FP) that I realized why stateful programming lends itself so easily to evil. If a program is a serial collection of possibly unrelated stateful actions, everyone can add new intermediate behaviors to a function to satisfy some dipshit requirement, and the API doesn't change. Writ large, this allows silent complexity creep.
I think a major reason why FP is better is that changing a purely referentially transparent function requires an API change: more parameters or a different return type. If nothing else, this tends to break tests. It's hard to change functions that already exist, and it should be hard. You should be writing new ones instead. Also, if there's only one way to combine programs (function composition) it's easier to break them up. So you don't get the 500-line monsters that plague enterprise codebases.
That said, the worst thing about OOP isn't state. It's inheritance, which is the 21st-century goto.
Of course, both of them can also come in handy if you are careful and know what you're doing.
http://michaelochurch.wordpress.com/2012/08/15/what-is-spagh...
"Are goto’s always bad eventually? Who cares? There’s far bigger problems with gradual change in codebases, let’s think harder about them. My peer reviewers, hold off review until you’ve used what I’ve built and found problems with it. Managers and programmers, wrestle with judgement everyday, the stuff not easily put into rules. Leave the comforting shallows and engage with the abyss."
http://michaelochurch.wordpress.com/2012/08/15/what-is-spagh...
I'm programming in C++ and C# right now, and my general mantra is "state is bad".
Of course I learned that from doing functional programming... :)
Edit: This is a very interesting statement, seriously. How easily do we stumble onto a statement whose truth hinges on the purpose of programming languages. There are a lot of ways one can look at this.
For example, the statement may be true but then if failure-to-hide complexity is what's making things hard, something is still making things hard. Reframing someone's problem won't make it go away unless you also hand them a way to deal with it.
Also, isn't whole point of a high level language that it hides complexity appropriately in order to allow the limited human brain to deal with the ungodly complexity of a large computer program? Having to paste ten boiler-plate arguments to a group of functions (when if one was using OO the arguments would be subsumed in the object) might not add complexity to the resulting logical object but without other mitigating factors, it seems to me that such an approach would add to the complexity of the code creation process, which is really the major bottleneck in computer programming, right?
is completely unnecessary. Depending on how you plan to use the boilerplate arguments, you'll typically encapsulate them with either a Reader, Writer or State monad.
It also has carrying, for ad hoc accumulation of arguments, so you don't need the boilerplate of ten overloaded methods or a builder class just to accumulate arguments.
In the words of a Wikipedian, "citation needed".
EDIT: To the downvoters, care to comment?