4 ms·
The whole code is horribly over-engineered, at least for a performance benchmark. Anybody who uses a pow call to square a number must believe compilers are mag
by galacticpony 10y ago
The whole code is horribly over-engineered, at least for a performance benchmark.
Anybody who uses a pow call to square a number must believe compilers are magic. Worse yet, some compilers might actually optimize for that case, reinforcing that belief.
Compilers should be dumb, fast and predictable instead. That way, everyone gets what they deserve.
- pcwalton 10y ago> Compilers should be dumb, fast and predictable instead. That way, everyone gets what they deserve. That's a good way to get pummeled in benchmarks. Benchmark scores matter a lot to perception: just look at any HN thread about programming language or browser performance, or any review of browsers in the tech press. We may not like it, but the benchmark-dominated world is the world we live in.
- sqeaky 10y agoI disagree that compilers should be dumb. A smart compiler can do impressive things like take types into account to add optimizations or it can also take use patterns into account to make Javascript nearly as fast as C++. With dumb compilers we are putting the need to understand every machine on every developer. Isolating what knowledge is required in different locations is exactly why we have abstractions. The compiler is just one more abstraction to help this kind of specialization and basic division of labor.
- galacticpony 10y agoThe first paragraph is just nonsense. You, too, suffer from the belief in the magic compiler. Regarding the second statement: These "smart" optimizations happen before architecture specialization, so that's wrong too. But even if it was true, you now shift the burden to understanding every compiler in order to get the optimization you need. If people expect that pow(x,2) transforms to x * x, then every compiler would have to implement that. This is a trivial example, but you in reality you always have to structure your code appropriately for some optimization to kick in, what if one of your target compilers needs a different structure?
- pcwalton 10y ago> If people expect that pow(x,2) transforms to x * x, then every compiler would have to implement that. This is a trivial example, but you in reality you always have to structure your code appropriately for some optimization to kick in, what if one of your target compilers needs a different structure? Do you get your copy of Hacker's Delight off the bookshelf to look up the magic number instead of writing "x / 3"? Everyone relies on optimizations to some extent. It's simply infeasible to do otherwise.
- galacticpony 10y agoI'm not saying compilers shouldn't optimize, they just shouldn't try to be clever. Some things can be expected to be done by most any compiler, many things are extremely compiler-specific and only work under very specific circumstances.
- pcwalton 10y agoI agree that there is a line beyond which you shouldn't expect compilers to optimize. But "being clever" is responsible for lots of seemingly-simple optimizations. If you want something to blame, blame the C language for making program transformations hard due to unrestricted aliasing and so forth. Don't blame compiler authors for responding to the demands of their users.
- galacticpony 10y agoMany users don't want "clever" optimizations and compiler authors often implement things that nobody would ever ask for, because it has no real-world benefit. See: https://www.theregister.co.uk/2015/11/01/linus_torvalds_fires_off_angry_compilermasturbation_rant/ https://www.theregister.co.uk/2015/11/01/linus_torvalds_fire... If we had an hour to discuss which optimizations are or are not "clever" in the derogatory sense, maybe we would agree on almost everything. Alas, I've spent enough time on this thread. Good day!
- sqeaky 10y ago
- aseipp 10y agoAnd for smart compilers, developers have to have intimate knowledge about the implementation details in order to work around infelicities, or understand exactly how much performance they're leaving on the table when it does or does not do something. So what happened to all that abstraction you were clamoring about, where dumb compilers require "understanding the machine" -- when for the 4th time this week you're staring at the generated code from your "smart compiler", wondering why it's leaving performance on the table? I still write assembly and it isn't because I'm working on a Z80, or for a lack of "very smart compilers" -- I assure you. Sometimes the compiler just can't do what I want; other times it's being too clever for its own good and getting in my way. Most of the time it does a perfectly good job. The abstraction is fundamentally leaky. As someone who worked on a compiler for years, cost models are important, and benchmarks and perceptions are very important -- but they are often non-intuitive and not totally "free", as TINSTAAFL says. That said, optimizing something like a self-pow call to a square is probably not overreaching as an optimization or whatever. But there is certainly something to be said about over doing it and before you know it, you've kicked the can down to <person in the hallway who's really good at optimizing on platform X> because they had to do it anyway because only they know why the JVM or whatever behaves that way on a Friday with 17 inner class methods or something and you're really sure it can be faster but you've got a deadline in like a week and holy shit you have 3 other things to do. As an aside, I think if any compiler gets the "most sane cost model award", it would probably be Chez Scheme, since it is both unbelievably fast, and based entirely around a practical metric: basically no optimization is added if it cannot speed up the compiler itself. Performance should be predictable both in terms of runtime and compile time. Since the compiler is a rather general purpose application -- if the optimization isn't worth it there, it's probably too overly specific, and likely isn't carrying its own weight. After 30 years of following this rule -- Chez is very, very fast.
- buzzybee 10y agoThe Chez Scheme rule is also used by Niklaus Wirth with respect to the actual language design, and it shows in the evolution from Pascal to Modula-2 and Oberon. All have extremely fast compilers, although some implementations expend more effort on optimization than others.
- 10y ago
- jbclements 10y agoWow; I really disagree with this viewpoint. I want clever compilers that produce good code from high-level specifications. I fully accept the lack of predictability. Also, your comment that "everyone gets what they deserve" suggests that those who write high-level code (e.g. using pow() to square a number) "deserve" to have slow code. That's a strange moral outlook.
- 234dd57d2c8dba 10y agoIf your code isn't predictable, you can't write performance sensitive code in it.
- galacticpony 10y agoIt really isn't. You want something for free without putting the work. I want to put in some work to get what I need. You, too, believe in the magic compiler that doesn't exist. You don't get good code from a high-level specification. You really have to understand what the compiler actually can do for you and write your code accordingly, either way - except the predictable case is more straightforward (though maybe not as pleasing).
- pcwalton 10y ago"Putting in the work" often means not being able to use abstractions, which reduces the maintainability of code. That's what people often miss about optimizations: one of their most important uses is to enable abstractions. As a simple example, take SROA: without that optimization, you can't make a "Point { float x, y, z; }" struct and have that be as efficient as "float x, y, z;", because x, y, and z can live in registers in the latter, while in the former they remain as memory instead of being promoted to SSA values. But being able to use a Point structure like that is extremely helpful, because then I can define useful methods on it and so forth. I shouldn't have to choose between good engineering practice and performance, and thanks to SROA, I don't have to.
- galacticpony 10y agoYou've just invited the assumption that your compiler can do SROA as the basis for better performance - how is that an abstraction? If you really care about performance to the point of register occupancy, you need to look at the context. The "abstraction" of having a Point type with methods is almost certainly far from optimal, because it doesn't fit SIMD well. It's then also not "good engineering practice" to use it.
- username223 10y ago> Anybody who uses a pow call to square a number must believe compilers are magic. I'm guessing he thought using a temporary variable would look less pretty, and had no idea of the relative costs of imul and ipow. > Compilers should be dumb, fast and predictable instead. I don't care too much about dumb or fast, but they definitely need to be predictable. Even with something as low-level as C++ or Fortran, you often have to profile and disassemble to see if the compiler is doing the optimizations you want (e.g. unrolling loops, inlining functions, propagating constants, using SSE), or if you have to hold its hand. Trying to predict whether something as high-level as GHC will do what you want, or to figure out how to make it do so, is an absolute nightmare.
- pjmlp 10y agoThat is what profilers are for. One cannot realistic expect that any compiler for a given language behaves the same way.
- username223 10y agoYes, but it's nice to be able to predict what your compiler of choice will do, or at least to know that all of the things it might do will have similar performance. When you depend upon certain optimizations, you need to diagnose the compiler's failure to do them. This usually means knowing both how to read assembly, and how to force the compiler to do what you want. This doesn't matter when any correct program is "good enough," but it matters a whole lot when failure to perform specific optimizations makes a program unacceptably slow.
- galacticpony 10y ago"Trying to predict whether something as high-level as GHC will do what you want, or to figure out how to make it do so, is an absolute nightmare." GHC also happens to be one of the slowest compilers you could possibly use. It all goes together.
- pjmlp 10y ago> Compilers should be dumb, fast and predictable instead. That way, everyone gets what they deserve. This is what gave us C, while the rest of the mainframe world was busy using Algol, PL/I, Fortran and Lisp dialects. Where many of the compilers already were capable of doing bounds checking elision.