Python Front-end to GCC

Oscar Benjamin oscar.j.benjamin at gmail.com
Tue Oct 22 10:15:32 EDT 2013


On 22 October 2013 13:00, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> On Tue, 22 Oct 2013 10:14:16 +0100, Oscar Benjamin wrote:
>
>> On 22 October 2013 00:41, Steven D'Aprano <steve+comp.lang.python at pearwood.info> wrote:
>>>
>>> Are you suggesting that gcc is not a decent compiler?
>>
>> No.
>>
>>> If "optimize away
>>> to the null program" is such an obvious thing to do, why doesn't the
>>> most popular C compiler in the [FOSS] world do it?
>>
>> It does if you pass the appropriate optimisation setting (as shown in
>> haypo's comment). I should have been clearer.
>
> "C can do nothing 10 times faster than Python!" -- well, okay, but what
> does that tell you about my long-running web server app? Benchmarks at
> the best of time are only suggestive, benchmarks for null programs are
> even less useful.

This is precisely my point. They should show a benchmark that is not
semantically equivalent to the null program. I modified their example
to do that so that it wasn't simply a case of removing dead code and
then found that the C version performed 6-7 times faster than the PyPy
version. Had they simply stated that I would have been impressed.

At the bottom of this post I show a much better benchmark that shows
how PyPy can come very close to C performance for intensive floating
point computation. Note that although it is simple the benchmark
actually produces a result and none of the computation can be skipped
as dead code (why would I put that in?). Also note that both the C
binary and the script produce exactly the same numeric output. It's
also a simple example of numerical integration - something that is
often a bottleneck in scientific computation.

For the benchmark I find that the gcc -O3 binary runs in 4.6s and PyPy
runs the script in 6.9s (CPython 2.7 takes 600 seconds). That is
impressive and makes me think that there may be no need for me to use
C for things like that. To be sure I'd have to scale it up a bit to
see what happens when I break it apart into many functions and use
lists in PyPy vs arrays in C.

> [...]
>> They are more than carefully crafted. They are useless and misleading.
>> It's reasonable to contrive of a simple CPU-intensive programming
>> problem for benchmarking. But the program should do *something* even if
>> it is contrived. Both programs here consist *entirely* of dead code.
>
> But since the dead code is *not* eliminated, it is actually executed. If
> it's executed, it's not really dead, is it? Does it really matter that
> you don't do anything with the result? I'm with Maciej on this one --
> *executing* the code given is faster in PyPy than in C, at least for this
> C compiler. Maybe C is faster to not execute it. Is that really an
> interesting benchmark? "C does nothing ten times faster than PyPy does
> something!"

I don't think it is reasonable to compare those things and I was
joking when I said that the optimised C version was 600 times faster
because this is an absurd benchmark - see the much better one below.

> Given a sufficiently advanced static analyser, PyPy could probably
> special-case programs that do nothing. Then you're in a race to compare
> the speed at which the PyPy runtime environment can start up and do
> nothing, versus a stand-alone executable that has to start up and do
> nothing. If this is a benchmark that people care about, I suggest they
> need to get out more :-)

Like Chris I have also had situations where startup time mattered and
it can vary substantially between different interpreters and binaries.
I have GNU Octave on Windows and it literally takes 20 seconds to
start up. Matlab is worse: it takes about 1 minute so I don't tend to
use it for CLI scripts much.


Oscar


The benchmark:

$ cat euler.py
#!/usr/bin/env pypy

import math

def main():
    x = 1
    v = 0
    t = 0
    T = 1
    dt = 2**-30
    while t < T:
        dxdt = v
        dvdt = - x
        x += dt * dxdt
        v += dt * dvdt
        t += dt
    print('t = %.2e' % t)
    print('x = %.2e' % x)
    print('v = %.2e' % v)
    print('x_err = %.e' % (x - math.cos(t)))
    print('x_err = %.2e' % (v + math.sin(t)))

main()
$ time pypy euler.py
t = 1.00e+00
x = 5.40e-01
v = -8.41e-01
x_err = 3e-10
x_err = -3.92e-10

real    0m6.907s
user    0m0.076s
sys     0m0.045s
$ cat euler.c
#include <stdio.h>
#include <math.h>

int main()
{
    double x = 1;
    double v = 0;
    double t = 0;
    double T = 1;
    double dt = pow(2, -30);
    double dxdt, dvdt;
    while (t < T)
    {
        dxdt = v;
        dvdt = - x;
        x += dt * dxdt;
        v += dt * dvdt;
        t += dt;
    }
    printf("t = %.2e\n", t);
    printf("x = %.2e\n", x);
    printf("v = %.2e\n", v);
    printf("x_err = %.e\n", x - cos(t));
    printf("x_err = %.2e\n", v + sin(t));

    return 0;
}
$ gcc -O3 euler.c
$ time ./a.exe
t = 1.00e+000
x = 5.40e-001
v = -8.41e-001
x_err = 3e-010
x_err = -3.92e-010

real    0m4.609s
user    0m0.015s
sys     0m0.000s

$ time python euler.py  # CPython 2.7
t = 1.00e+00
x = 5.40e-01
v = -8.41e-01
x_err = 3e-10
x_err = -3.92e-10

real    9m51.818s
user    0m0.015s
sys     0m0.015s



More information about the Python-list mailing list