View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.beans.stats.collectors;
12  
13  import jakarta.inject.Inject;
14  
15  import java.util.List;
16  import java.util.Map;
17  import java.util.TreeMap;
18  
19  import org.jfree.data.xy.XYDataItem;
20  
21  import psiprobe.Utils;
22  import psiprobe.beans.stats.listeners.StatsCollectionEvent;
23  import psiprobe.beans.stats.listeners.StatsCollectionListener;
24  import psiprobe.model.stats.StatsCollection;
25  
26  /**
27   * The Class AbstractStatsCollectorBean.
28   */
29  public abstract class AbstractStatsCollectorBean {
30  
31    /** The stats collection. */
32    @Inject
33    private StatsCollection statsCollection;
34  
35    /** The max series. */
36    private int maxSeries = 240;
37  
38    /** The listeners. */
39    private List<StatsCollectionListener> listeners;
40  
41    /** The previous data. */
42    private final Map<String, Long> previousData = new TreeMap<>();
43  
44    /** The previous data2 d. */
45    private final Map<String, Entry> previousData2D = new TreeMap<>();
46  
47    /**
48     * Gets the stats collection.
49     *
50     * @return the stats collection
51     */
52    public StatsCollection getStatsCollection() {
53      return statsCollection;
54    }
55  
56    /**
57     * Sets the stats collection.
58     *
59     * @param statsCollection the new stats collection
60     */
61    public void setStatsCollection(StatsCollection statsCollection) {
62      this.statsCollection = statsCollection;
63    }
64  
65    /**
66     * Gets the max series.
67     *
68     * @return the max series
69     */
70    public int getMaxSeries() {
71      return maxSeries;
72    }
73  
74    /**
75     * Sets the max series.
76     *
77     * @param maxSeries the new max series
78     */
79    public void setMaxSeries(int maxSeries) {
80      this.maxSeries = maxSeries;
81    }
82  
83    /**
84     * Gets the listeners.
85     *
86     * @return the listeners
87     */
88    public List<StatsCollectionListener> getListeners() {
89      return listeners;
90    }
91  
92    /**
93     * Sets the listeners.
94     *
95     * @param listeners the new listeners
96     */
97    public void setListeners(List<StatsCollectionListener> listeners) {
98      this.listeners = listeners;
99    }
100 
101   /**
102    * Collect.
103    *
104    * @throws Exception the exception
105    */
106   public abstract void collect() throws Exception;
107 
108   /**
109    * Builds the delta stats.
110    *
111    * @param name the name
112    * @param value the value
113    *
114    * @return the long
115    *
116    * @throws InterruptedException the interrupted exception
117    */
118   protected long buildDeltaStats(String name, long value) throws InterruptedException {
119     return buildDeltaStats(name, value, System.currentTimeMillis());
120   }
121 
122   /**
123    * Builds the delta stats.
124    *
125    * @param name the name
126    * @param value the value
127    * @param time the time
128    *
129    * @return the long
130    *
131    * @throws InterruptedException the interrupted exception
132    */
133   protected long buildDeltaStats(String name, long value, long time) throws InterruptedException {
134     long delta = 0;
135     if (statsCollection != null) {
136       long previousValue = Utils.toLong(previousData.get(name), 0);
137       delta = value - previousValue;
138       delta = delta > 0 ? delta : 0;
139       buildAbsoluteStats(name, delta, time);
140       previousData.put(name, value);
141     }
142     return delta;
143   }
144 
145   /**
146    * Builds the absolute stats.
147    *
148    * @param name the name
149    * @param value the value
150    *
151    * @throws InterruptedException the interrupted exception
152    */
153   protected void buildAbsoluteStats(String name, long value) throws InterruptedException {
154     buildAbsoluteStats(name, value, System.currentTimeMillis());
155   }
156 
157   /**
158    * Builds the absolute stats.
159    *
160    * @param name the name
161    * @param value the value
162    * @param time the time
163    *
164    * @throws InterruptedException the interrupted exception
165    */
166   protected void buildAbsoluteStats(String name, long value, long time)
167       throws InterruptedException {
168 
169     List<XYDataItem> stats = statsCollection.getStats(name);
170     if (stats == null) {
171       statsCollection.newStats(name, maxSeries);
172     } else {
173       XYDataItem data = new XYDataItem(time, value);
174       statsCollection.lockForUpdate();
175       try {
176         stats.add(data);
177         houseKeepStats(stats);
178       } finally {
179         statsCollection.releaseLock();
180       }
181       if (listeners != null) {
182         StatsCollectionEvent event = new StatsCollectionEvent(name, data);
183         for (StatsCollectionListener listener : listeners) {
184           if (listener.isEnabled()) {
185             listener.statsCollected(event);
186           }
187         }
188       }
189     }
190   }
191 
192   /**
193    * The Class Entry.
194    */
195   private static class Entry {
196 
197     /** The time. */
198     long time;
199 
200     /** The value. */
201     long value;
202 
203     /**
204      * Instantiates a new entry.
205      */
206     public Entry() {
207       // Prevent Emulation by Synthetic Accessor
208     }
209 
210   }
211 
212   /**
213    * If there is a value indicating the accumulated amount of time spent on something it is possible
214    * to build a series of values representing the percentage of time spent on doing something. For
215    * example:
216    *
217    * <p>
218    * at point T1 the system has spent A milliseconds performing tasks at point T2 the system has
219    * spent B milliseconds performing tasks
220    * </p>
221    *
222    * <p>
223    * so between in a timeframe T2-T1 the system spent B-A milliseconds being busy. Thus (B - A)/(T2
224    * - T1) * 100 is the percentage of all time the system spent being busy.
225    * </p>
226    *
227    * @param name the name of the value, which allows the collector to be used for multiple values
228    * @param value time spent on the task in milliseconds (A or B in the example above)
229    * @param time system time in milliseconds (T1 or T2 in the example above)
230    *
231    * @throws InterruptedException if a lock could not be obtained
232    */
233   protected void buildTimePercentageStats(String name, long value, long time)
234       throws InterruptedException {
235 
236     Entry entry = previousData2D.get(name);
237     if (entry == null) {
238       entry = new Entry();
239       entry.value = value;
240       entry.time = time;
241       previousData2D.put(name, entry);
242     } else {
243       double valueDelta = (double) value - entry.value;
244       double timeDelta = (double) time - entry.time;
245       double statValue = valueDelta * 100 / timeDelta;
246       statsCollection.lockForUpdate();
247       try {
248         List<XYDataItem> stats = statsCollection.getStats(name);
249         if (stats == null) {
250           stats = statsCollection.newStats(name, maxSeries);
251         }
252         stats.add(stats.size(), new XYDataItem(time, statValue));
253         houseKeepStats(stats);
254       } finally {
255         statsCollection.releaseLock();
256       }
257     }
258   }
259 
260   /**
261    * Reset stats.
262    *
263    * @param name the name
264    */
265   protected void resetStats(String name) {
266     statsCollection.resetStats(name);
267   }
268 
269   /**
270    * House keep stats.
271    *
272    * @param stats the stats
273    */
274   private void houseKeepStats(List<XYDataItem> stats) {
275     while (stats.size() > maxSeries) {
276       stats.remove(0);
277     }
278   }
279 }