Live data from Hacker News

Beating the compiler

roguelazer.com

11–20 of 46 posts

Re: Beating the compiler

#11
post #5

Er. Author missed a crucial point of "just" using PyPy: for me it's over 24x speedup over standard python (if you run it enough times for JIT to warmup). Know your tools

I got 25x on sum_naive_python() and 6x on sum_native_python() (PyPy 2.7.3 vs CPython 2.7.6 on Intel Arrandale), using timeit to measure time and not cycles.

But IMO it's a nice article anyways. I'd wager the final implementation he comes up with is faster than PyPy.

Re: Beating the compiler

#12
> What's the point of micro-optimizing a 3ms function call when each request spends 8 or 9 seconds inside the SQLAlchemy ORM? Well, sometimes it's nice to practice those optimizion skills anyway

I have a different opinion on those 3ms optimizations:

"It all adds up"

Stopping at one 3ms optimization is not going to move mountains. But doing that 10 times is already 30ms. Imagine that you found 100 micro optimizations. Now we are talking!

So keep calm, optimize on. This is how compilers get better over time.

Re: Beating the compiler

#14

Note that the Python code is not limited to 32 bits and will automatically promote to bignum (aka long in py27). >>> l=[0xffffffff, 17] >>> sum(l) 4294967312 C based code will silently overflow/truncate, giving 16 in the example above. The author handwaved all this away, but it does show the usual tradeoffs between right/robust answers and fast answers.

Signed integer behaviour is undefined on overflow in C.

Re: Beating the compiler

#15

Note that the Python code is not limited to 32 bits and will automatically promote to bignum (aka long in py27). >>> l=[0xffffffff, 17] >>> sum(l) 4294967312 C based code will silently overflow/truncate, giving 16 in the example above. The author handwaved all this away, but it does show the usual tradeoffs between right/robust answers and fast answers.

Obviously if this weren't a trivial example and were real code he'd account for this in his C code, and it would still be much faster than the Python code.

He hand waved it away because it's not really relevant to the point.

Re: Beating the compiler

#16
post #6
post #3

The reason to use intrinsics and inline assembly (actually, the latter is pretty rare these days, intrinsics being much more common) isn't only about beating the compiler. When you're relying on the compiler to vectorize, you run the risk of a subtle, innocuous change to the code breaking the vectorization -- and this will happen a lot. Also, when you target multiple compilers, it's very difficult to get reliable per…

Rather than inline ASM, wouldn't it be better to have a maker that says "error if this can't be vectorised"? Something analogous to Scala's @tailrec

I've been thinking about that for the last few days, and I think that's the best solution, if it's possible. Optimizations might clutter up the code and make the intent not clear. Writing idiomatic code and hoping that the compiler figures it out is also suboptimal, as noted by the grandparent.

I think the best solution is to be able to make some kind of annotation, or other way of declaration, on a function that says "this function should be no worse than this". In Scala's case, for example tailrec. I'm unfortunately having a hard time with coming up with other, specific examples, but the gist of it is that the compiler either manages to do all the work on the function itself and the functions that that function calls, or errors out and reports what it couldn't do. Ideally I would want to make 10 functions which are all pure and referentially transparent, call all those functions from a top function with some kind of annotation that gives some demands with regards to optimizations, and then have that function be transformed to a single, efficient, fused loop with no allocations or intermediary values that are unnecessary. But like I mentioned, the hard part seems to be in actually specifying what your demands are.

Re: Beating the compiler

#17
post #6
post #3

The reason to use intrinsics and inline assembly (actually, the latter is pretty rare these days, intrinsics being much more common) isn't only about beating the compiler. When you're relying on the compiler to vectorize, you run the risk of a subtle, innocuous change to the code breaking the vectorization -- and this will happen a lot. Also, when you target multiple compilers, it's very difficult to get reliable per…

Rather than inline ASM, wouldn't it be better to have a maker that says "error if this can't be vectorised"? Something analogous to Scala's @tailrec

Again, inline ASM is pretty rare these days (when we do use it, it isn't for SIMD). Intrinsics are much more common.

The big issue (aside from convincing MSVC to implement it ;) with your suggestion is that, unlike TCO, vectorization isn't really a boolean. There's a range of what vectorization might mean (you can vectorize code and do a bad job with it, only marginally beating out the scalar code), so you'd still need to check the generated code for the situations where you care.

And honestly, it's not worth the effort. Vectorization shouldn't be as scary as it is for most programmers. Once you get the hang of how to do it, it's not bad at all. We write a lot of SIMD code at work, and 'difficulty of writing SIMD code' isn't a big issue for us. Honestly, it's kind of fun, a bit like solving a puzzle (an optimization puzzle, something like SpaceChem or Infinifactory).

Now, a situation where it might be a win is if you have a lot of different platforms you need vectorized code for... but in my experience you're probably better off doing it by hand unless this is a huge number.

Re: Beating the compiler

#18
post #15

Note that the Python code is not limited to 32 bits and will automatically promote to bignum (aka long in py27). >>> l=[0xffffffff, 17] >>> sum(l) 4294967312 C based code will silently overflow/truncate, giving 16 in the example above. The author handwaved all this away, but it does show the usual tradeoffs between right/robust answers and fast answers.

Obviously if this weren't a trivial example and were real code he'd account for this in his C code, and it would still be much faster than the Python code. He hand waved it away because it's not really relevant to the point.

The Python code was trivial to write and immediately correct and robust. Trying to get C code to do the right thing is considerably more difficult - for example even trying to detect overflow can result in code the compiler then removes - http://lwn.net/Articles/278137/

Robust, correct and fast are a hard combination to do. I do acknowledge the article is about the latter.

Re: Beating the compiler

#20
post #15

Earlier quoted context omitted.

Obviously if this weren't a trivial example and were real code he'd account for this in his C code, and it would still be much faster than the Python code. He hand waved it away because it's not really relevant to the point.

The Python code was trivial to write and immediately correct and robust. Trying to get C code to do the right thing is considerably more difficult - for example even trying to detect overflow can result in code the compiler then removes - http://lwn.net/Articles/278137/ Robust, correct and fast are a hard combination to do. I do acknowledge the article is about the latter.

It's not hard if you use GMP.
Post reply on HN