I’m perfoming Mission Analysis runs for 10 years.
However, I have huge performances problems. Run duration rises exponentialy according to run duration :
First year of run : 50 min
Last year of run : 5h15…
After profiling different runs, I discovered that it’s due to parameter drivers with timeSpan. There is a lot of time spend in TimeSpanMap methods (“getFirstSpan”, “getNbOfValues”) called from ParameterDriver class (getValue, getNbOfValues).
In the screenshot, one of my profiling results after 6 months of propagation. We can see the methods taht use the most CPU Samples.
Is it possible to remove the synchronized ? or improve drivers with timespan ?
The getNbOfValues() method is just one line, it calls valueSpanMap.getSpansNumber(), which itself just does return nbSpans. This method is synchronized, but I am not sure it is the culprit. We could perhaps replace this by an AtomicInteger, but I doubt it will improve things.
The getFirstSpan method on the other hand could perhaps be improved by just keeping a reference to the first span (and update it when it changes due to calls to addValidBefore), this would avoid the loop from current span to first span.
As the methods are indeed quite small, they are probably called a very large number of times (probably millions of times) to explain their overwhelming cost. Could you look at the caller (InternalFiniteManeuver it seems), to try to see if you could reduce the number of calls? Maybe there is a loop somewhere and a loop invariant could be moved outside of the loop?
If the computation cost is small at start and increases, it could also indicate we have a large overhead because we always keep all data in TimeSpanMap (we have add methods but no remove methods). If your simulation never goes backward in time (i.e. if you don’t need to loop over the 6 months several times), then we could consider either adding remove methods, or (probably better) add a configuration parameter to forget too old data, using either a time range limit or a number of spans limit.
I also have this issue for long termes SK analysis of GEO satellites (i.e. 20 years). We compte about 1000 maneuvre cycles (i.e. one per week). The computation time of the fiest cycle is about 20 sec while the last one needs about 30 minutes. With a constant augmentation cycle after cycle.
(It is not the same case of @pauline because she works on LEO simulations, with a different simulator because different SK algorithm)
It has to be noted that we store all the maneuvers during the simulation inside a list, but the propagation duration is the same (i.e., cycle duration). So, if a cycle is based on 7 maneuvers, after the first one our list of maneuvers has a size of 7, after the second one a size of 14, etc.
Our first improvement, before Orekit 12, was to reduce the called to the InternalFinlteManeuver object to the minimum ones inside our similator. It improved a lot the performance and stabilized the computation time.
After the upgrade to Orekit 12, the situation worsened to the current situation (i.e., 20sec for 1st cycle and 30min for the last cycle with an increase cycle by cycle). After analysis, the problem comes from the introduction of time stamped ParameterDriver. The more maneuvers you have in your list, the more time stamped ParameterDriver you have, and the computation time increase. At the end most of the computation is spent on méthodes handling the drivers.
Our fix was to clean the list of maneuvers before a new cycle. It stabilized the computation time. But, it is a local fix that I dont find optimal since some applications could have the need of storing big list of maneuvers.
Maybe we can think about an improvement inside Orekit on the handling of these time stamped drivers.
If you don’t really use the drivers (no estimation-like feature), and your maneuvers are time-stamped, then I suggest you replace your N maneuvers with a single ProfileThrustPropulsionModel.
I remember I had the same problem a while back (though it was more the multiple detectors that slowed down my propagations, at least I thought), and this fix drastically improved performances.
Still, I also think we should do something to improve performances with multiple time-span drivers. @pauline, is there a way you could reproduce the performance issue within a minimal example so that we could use it for testing?
I was thinking about adding both a maxNumberOfSpans and a maxMapDuration. Then when we call one of the add methods, we would perform a cleanup sweep. If adding the new transition is performed at one end (either earliest or latest entry), then the sweep would be done at the other end. I don’t know what to do if we insert something in the middle of a span, this could be either looking at the end that is farthest from the inserted element, or just don’t cleanup in this case which would mean maximum values would be ignored in this use case.
As Maxime suggested, if you have many purely date-defined maneuvers and you don’t need partial derivatives w.r.t. start/stop dates (it might not be the case for you Bryan, but it could help somebody else), you should use a single Maneuver (possibly with an AggregatedAttitudeProvider as attitude override).
On the develop branch there is now a TimeIntervalsManeuverTrigger which allows to have arbitrarily many firing time intervals.
You could also define your own ManeuverTrigger that does’nt have any ParameterDriver.
I have started work on this. You can look at the branch issue-1742 to see what I have in mind.
Note that one test fails in ParameterDriverTest, I did not check the culprit yet.
I have changed slightly the API, removed the extra constructor in TimeSpanMap and created a configureExpunge method that can be called after construction.
This allows to configure the maps that are automatically created within ParameterDriver, by just retrieving the driver and then calling getNamesSpanMap().configureExpunge() and getValuesSpanMap().configureExpunge(). I have added a recommendation in the javadoc that if users retrieve one map and update the expunge policy, then they should update the second one accordingly. For sure we could also set up a configureExpunge method in configureExpunge that does that, but we still need to warn users that have access to both maps independently (they could already do nasty things like adding entries in one map only, but that is another story).
@bcazabonne and @pauline, I let you use this feature for your case, please tell us if this fixes the issue.