licit-lab / symupy

SymuPy: A python API for SymuVia
https://symupy.readthedocs.io/en/stable/
MIT License
4 stars 3 forks source link

Performance issue #70

Closed floriangc closed 3 years ago

floriangc commented 3 years ago

Description

When running a SymuVia simulation with SymuPy the time to perform a next_step increases with the number of step.

Reproduce

Use the configuration file: https://github.com/licit-lab/symupy-examples/blob/main/network/SingleLink_symuvia_withcapacityrestriction.xml

And run the simulation with the code:

from symupy.runtime.api import Simulator
from symupy.utils.constants import DEFAULT_PATH_SYMUVIA

import time

sim_instance = Simulator.from_path("SingleLink_symuvia_withcapacityrestriction.xml", DEFAULT_PATH_SYMUVIA)
sim_instance.trace_flow = True
sim_instance.step_launch_mode = "full"

with sim_instance as s:
    for _ in range(400):
        start = time.time()
        s.run_step()
        print("Total time step:", time.time() - start)

After tracking down the problem, it seems that this line take more and more time during the simulation.

The issue might be related with the size of the buffer that SymuPy get from SymuVia.

aladinoster commented 3 years ago

Going deeper the problem seems related to the demand augmentation and the update of the structures at each time step.

Processing time vs number of vehicles

image

Average processing time per vehicle

image

floriangc commented 3 years ago

By the structure you mean the buffer_string attribute of the Simulator ? Or the whole update of the vehicles data ?

aladinoster commented 3 years ago

The update of vehicles' data. There's an internal loop that spreads updates to overall subscribers (parsing data from xml trace to a dict and then to the object), it's via a for loop within the publisher. I'm checking on why the performance goes from 1 ms to 5ms, this might be due to the buffer size (In exploration)

When updating the buffer there is a dispatch to objects (called subscribers to update internal object data). E.g vehicle's data, etc. This is done along multiple channels (as in a pub-sub pattern), and up to the moment, there's only one channel to dispatch information.

https://github.com/licit-lab/symupy/blob/e8694d026cddf56710b39ba24083f4bd9380c1cc/symupy/utils/parser.py#L65-L69

Afterwards, each one of the subscribers is updated via this loop, this loop scales bad with number of vehicles since the number of vehicles is the number of objects to run along the for.

https://github.com/licit-lab/symupy/blob/e8694d026cddf56710b39ba24083f4bd9380c1cc/symupy/runtime/logic/publisher.py#L72-L79

floriangc commented 3 years ago

Maybe to speed up things a little, we can consider using comprehension list for those loops ?

floriangc commented 3 years ago

But there is only one channel here .. My bad, it will not improve this case.

aladinoster commented 3 years ago

Parsing around 340 vehicles to a dict is not costly but it can go up to 2 ms.

from xmltodict import parse 

%timeit parse(s.request.query)
1.86 ms ± 89.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
floriangc commented 3 years ago

Parsing around 340 vehicles to a dict is not costly but it can go up to 2 ms.

from xmltodict import parse 

%timeit parse(s.request.query)
1.86 ms ± 89.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

The weird thing is the exponential grow in time of your first plot .. The parsing of the string into a dict should have a linear increase in time. So It's maybe not the problem.

aladinoster commented 3 years ago

Actually parse, does more complex things than linear parsing because creates embeddings, (dicts of dicts) when the xml structure allows for it. I used the library since it reduced the effort on this transformation in terms of code but we could try a custom solution that follows the linear time increase.

On the other hand, there are still 2~ms/veh processing to search they could be related to memory handling.

floriangc commented 3 years ago

On the other hand, there are still 2~ms/veh processing to search they could be related to memory handling.

Copy in memory of the string returning by symuvia ?

aladinoster commented 3 years ago

Now performance has this behaviour: For reproduction please check https://github.com/licit-lab/symupy-examples NvsT TvsTime