modelx icon indicating copy to clipboard operation
modelx copied to clipboard

Profiling modelx execution

Open fumitoh opened this issue 6 years ago • 11 comments

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 avatar Oct 12 '19 13:10 fumitoh

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

fumitoh avatar Oct 12 '19 13:10 fumitoh

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

alebaran avatar Oct 12 '19 16:10 alebaran

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

fumitoh avatar Oct 13 '19 06:10 fumitoh

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.

alebaran avatar Oct 13 '19 07:10 alebaran

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?

fumitoh avatar Oct 13 '19 08:10 fumitoh

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

alebaran avatar Oct 13 '19 09:10 alebaran

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)

alebaran avatar Nov 05 '19 12:11 alebaran

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

fumitoh avatar Nov 05 '19 12:11 fumitoh

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

alebaran avatar Nov 05 '19 12:11 alebaran

This should be easy to implement by the next release.

fumitoh avatar Nov 05 '19 12:11 fumitoh

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

fumitoh avatar Dec 01 '19 06:12 fumitoh