fumitoh / modelx

Use Python like a spreadsheet!
https://modelx.io
GNU Lesser General Public License v3.0
90 stars 20 forks source link

Profiling modelx execution #13

Open fumitoh opened 4 years ago

fumitoh commented 4 years ago

On a related subject: what is the way to profile modelx execution? I would like to see how long it takes to evaluate various functions.

Originally posted by @alebaran in https://github.com/fumitoh/modelx/issues/12#issuecomment-541148640

fumitoh commented 4 years ago

I used profile module to measure performance of modelx. Have you tried it yet?

alebaran commented 4 years ago

It isn't informative: it says that all the time is consumed by cells.py:562(get_value)

fumitoh commented 4 years ago

I'll see if I can add profiling feature in modelx.

alebaran commented 4 years ago

Something very simple would already make a huge difference: currently I need to type "print(time())" in each cell formula to find bottlenecks. A simple solution can be to print a log of call stack returns, when the call stack became one element shorter.

fumitoh commented 4 years ago

I am thinking of the API like below:

import modelx as mx

m, s = mx.new_model(), mx.new_space()

@mx.defcells
def fibo1(x):
    return fibo1(x-1) + fibo1(x-2) if x > 1 else x

@mx.defcells
def fibo2(x):
    return fibo2(x-1) + fibo2(x-2) if x > 1 else x

mx.start_stacktrace(stop_after=0)  # 0 means no stop until stop_stacktrace is called.
fibo1(10)
fibo2(20)
mx.stop_stacktrace()

If you give stop_after=1 instead, then trace stops before fibo2(20) and only fibo1(10) is traced and no need to call stop_stacktrace.

Now, which do you prefer as stop_after's default, 0 or 1?

alebaran commented 4 years ago

I think it is like a profiler: if you are in it, you get all the stats. Default 0 would be more intuitive.

alebaran commented 4 years ago

Is get_stacktrace limited by 10000 entries?

from modelx import *
import time
model = new_model()
space = model.new_space()
@defcells
def a(t):
    return 1
@defcells
def PnL_b(t, var):
    return a(0)
@defcells
def run():
    times = range(1,41+1)
    variables = range(1,500+1)
    for t in times:
        for var in variables:
            PnL_b(t, var)
    return True
start = start_stacktrace()
run()
stack_trace = get_stacktrace()
len(stack_trace)
fumitoh commented 4 years ago

Yes, but you can change it here https://github.com/fumitoh/modelx/blob/master/modelx/core/system.py#L162

alebaran commented 4 years ago

Awesome, thanks. It would be nice to have it as a parameter of start_stacktrace()

fumitoh commented 4 years ago

This should be easy to implement by the next release.

fumitoh commented 4 years ago

In v0.1.0, maxlen parameter is added to start_stacktrace(), to specify the maximum length of traces to be kept. See the release note linked below.

https://modelx.readthedocs.io/en/latest/releases/relnotes_v0_1_0.html