Opened 8 years ago

Closed 14 months ago

#11332 closed defect (wontfix)

65x penalty in performance for using float instead of RealNumber

Reported by: pang Owned by: burcin
Priority: major Milestone: sage-duplicate/invalid/wontfix
Component: symbolics Keywords: float, RealNumber
Cc: Merged in:
Authors: Reviewers: Maarten Derickx
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description

The function random() returns a "float", but 1.0*random() is a "RealNumber?". The following code:

%time
#1
N=5000
x=random()
for c in xrange(N):
    kk = exp(x)

takes 5.24 seconds, while

%time
#1
N=5000
x=random()*1.0
for c in xrange(N):
    kk = exp(x)

takes 0.08

Change History (15)

comment:1 Changed 8 years ago by pang

It's a bit worse:

x=random()
timeit('exp(x)')

125 loops, best of 3: 7.88 ms per loop

while

x=random()*1.0
timeit('exp(x)')

625 loops, best of 3: 48.3 µs per loop

so the ratio is rather around 150x.

comment:2 Changed 8 years ago by nbruin

note that "float" is the standard python float type, whereas RealNumber? is a preferred type for sage. Furthermore, "exp" is a general sage function that can do all kinds of "exponentiation" (symbolic, numeric etc.), and that incurs overhead. Apparently a particularly bad one for "float" types. Setting the base line:

sage: x=random()
sage: y=RealNumber(x)
sage: z=RDF(x)
sage: timeit('exp(x)')
625 loops, best of 3: 1.15 ms per loop
sage: timeit('exp(y)')
625 loops, best of 3: 10.3 µs per loop
sage: timeit('exp(z)')
625 loops, best of 3: 3.52 µs per loop

Using python's own "exp" is the fastest:

sage: timeit('math.exp(x)')
625 loops, best of 3: 373 ns per loop

You can shave off some time from the RealNumber? one too by calling a method specific for it. It's slower, but RealNumber? has much more functionality (also multiprecision)

sage: timeit('y.exp()')
625 loops, best of 3: 6.28 µs per loop

RDF is supposed to be Sage's version of "double precision floats" and is indeed comparable:

sage: timeit('z.exp()')
625 loops, best of 3: 704 ns per loop

If you don't mind a float, math.exp seems to receive a fairly efficiently coerced float from either RealNumber? or RDF

sage: timeit('math.exp(y)')
625 loops, best of 3: 510 ns per loop
sage: timeit('math.exp(z)')
625 loops, best of 3: 419 ns per loop

It would be nice if the generic "exp" would find a bit faster codepaths for some of these types, but I wouldn't consider the current behaviour a "defect".

comment:3 Changed 6 years ago by jdemeyer

  • Milestone changed from sage-5.11 to sage-5.12

comment:4 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.1 to sage-6.2

comment:5 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.2 to sage-6.3

comment:6 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.3 to sage-6.4

comment:7 Changed 4 years ago by jdemeyer

  • Component changed from performance to symbolics
  • Owner changed from tbd to burcin

comment:8 follow-up: Changed 4 years ago by mmezzarobba

  • Milestone changed from sage-6.4 to sage-duplicate/invalid/wontfix
  • Status changed from new to needs_review

Fixed?

sage: sage: x=random()
sage: sage: y=RealNumber(x)
sage: sage: z=RDF(x)
sage: sage: timeit('exp(x)')
625 loops, best of 3: 17.7 µs per loop
sage: sage: timeit('exp(y)')
625 loops, best of 3: 5.9 µs per loop
sage: sage: timeit('exp(z)')
625 loops, best of 3: 2.29 µs per loop

comment:9 in reply to: ↑ 8 Changed 4 years ago by vdelecroix

Replying to mmezzarobba:

Fixed?

sage: sage: x=random()
sage: sage: y=RealNumber(x)
sage: sage: z=RDF(x)
sage: sage: timeit('exp(x)')
625 loops, best of 3: 17.7 µs per loop
sage: sage: timeit('exp(y)')
625 loops, best of 3: 5.9 µs per loop
sage: sage: timeit('exp(z)')
625 loops, best of 3: 2.29 µs per loop

Half

sage: x = random()
sage: timeit('exp(x)', number=50000)
50000 loops, best of 3: 8.15 µs per loop
sage: from math import exp as math_exp
sage: timeit('math_exp(x)', number=50000)
50000 loops, best of 3: 290 ns per loop

just 30x slower. Better than the 65x that was reported for the difference between float and RR.

comment:10 Changed 4 years ago by jdemeyer

92x on my system:

sage: timeit('exp(x)', number=100000, repeat=10)
100000 loops, best of 10: 8.55 µs per loop
sage: timeit('math_exp(x)', number=100000, repeat=10)
100000 loops, best of 10: 92.1 ns per loop

comment:11 Changed 4 years ago by mmezzarobba

Wait, what exactly are we trying to measure? I thought this ticket was about the overhead of exp() (I mean sage.functions.log.exp) for some argument types. If we allow ourselves to call the “right” function or method for each type, then both RDF(x).exp() and math.exp(x) are fast when applicable.

comment:12 Changed 4 years ago by vdelecroix

  • Status changed from needs_review to needs_info

Agreed that it is not exactly the same issue... but still there is a problem for exp being very slow. So we can either open a new ticket for that slightly similar issue or precise the issue here.

comment:13 Changed 2 years ago by rws

  • Status changed from needs_info to needs_review

I think there was progress from https://github.com/pynac/pynac/issues/108

I don't think you can get better than a few µs for symbolic exp(), there is too much overhead from symbolic/function.pyx even for GinacFunctions.

comment:14 Changed 18 months ago by mderickx

  • Reviewers set to Maarten Derickx
  • Status changed from needs_review to positive_review

I agree that the original problem is fixed.

comment:15 Changed 14 months ago by embray

  • Resolution set to wontfix
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.