From 1fe2fde9604db53e57996648d6d8627480391bab Mon Sep 17 00:00:00 2001
From: Daniel Schadt <kingdread@gmx.de>
Date: Fri, 27 Apr 2018 13:22:29 +0200
Subject: speed up boon calculation

This prevents calling BoonQueue::simulate a lot of times. Still needs
more profiling to make it even faster.
---
 src/statistics/boon.rs     | 12 ++++++++++++
 src/statistics/mod.rs      |  3 +++
 src/statistics/trackers.rs | 22 +++++++++++++++++++---
 3 files changed, 34 insertions(+), 3 deletions(-)

(limited to 'src/statistics')

diff --git a/src/statistics/boon.rs b/src/statistics/boon.rs
index 912fdb6..059329f 100644
--- a/src/statistics/boon.rs
+++ b/src/statistics/boon.rs
@@ -158,6 +158,18 @@ impl BoonQueue {
             BoonType::Intensity => self.queue.last().cloned().unwrap_or(0),
         }
     }
+
+    /// Calculate when the boon queue should be updated next.
+    ///
+    /// The next update always means that a stack runs out, even if it has no
+    /// visible effect.
+    ///
+    /// For each queue: `next_update() <= next_change()`.
+    ///
+    /// A return value of 0 means that there's no update awaiting.
+    pub fn next_update(&self) -> u64 {
+        self.queue.last().cloned().unwrap_or(0)
+    }
 }
 
 #[cfg(test)]
diff --git a/src/statistics/mod.rs b/src/statistics/mod.rs
index efb934f..0a524ea 100644
--- a/src/statistics/mod.rs
+++ b/src/statistics/mod.rs
@@ -151,6 +151,9 @@ pub fn calculate(log: &Log) -> StatResult<Statistics> {
     let boons = try_tracker!(boon_tracker.finalize());
     for (agent, boon_map) in &boons {
         let agent = agent_stats.entry(*agent).or_insert_with(Default::default);
+        if agent.exit_combat < agent.enter_combat {
+            continue;
+        }
         let combat_time = agent.combat_time() as f64;
         if combat_time == 0. {
             continue;
diff --git a/src/statistics/trackers.rs b/src/statistics/trackers.rs
index d80c5ee..9b8d633 100644
--- a/src/statistics/trackers.rs
+++ b/src/statistics/trackers.rs
@@ -233,6 +233,7 @@ pub struct BoonTracker {
     boon_areas: HashMap<u64, HashMap<u16, u64>>,
     boon_queues: HashMap<u64, HashMap<u16, BoonQueue>>,
     last_time: u64,
+    next_update: u64,
 }
 
 impl BoonTracker {
@@ -279,6 +280,17 @@ impl BoonTracker {
         }
     }
 
+    fn update_next_update(&mut self) {
+        let next_update = self.boon_queues
+            .values()
+            .flat_map(HashMap::values)
+            .map(BoonQueue::next_update)
+            .filter(|v| *v != 0)
+            .min()
+            .unwrap_or(0);
+        self.next_update = next_update;
+    }
+
     /// Get the boon queue for the given agent and buff_id.
     ///
     /// If the queue does not yet exist, create it.
@@ -302,9 +314,12 @@ impl Tracker for BoonTracker {
 
     fn feed(&mut self, event: &Event) -> Result<(), Self::Error> {
         let delta_t = event.time - self.last_time;
-        self.update_queues(delta_t);
-        self.update_areas(delta_t);
-        self.last_time = event.time;
+        if self.next_update != 0 && delta_t > self.next_update {
+            self.update_queues(delta_t);
+            self.update_areas(delta_t);
+            self.update_next_update();
+            self.last_time = event.time;
+        }
 
         match event.kind {
             EventKind::BuffApplication {
@@ -315,6 +330,7 @@ impl Tracker for BoonTracker {
             } => {
                 self.get_queue(destination_agent_addr, buff_id)
                     .add_stack(duration as u64);
+                self.update_next_update();
             }
 
             _ => (),
-- 
cgit v1.2.3