Commit | Line | Data |
---|---|---|
200789b3 | 1 | /******************************************************************************* |
60ae41e1 | 2 | * Copyright (c) 2012, 2014 Ericsson |
200789b3 AM |
3 | * |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Alexandre Montplaisir - Initial API and implementation | |
63fe91fb | 11 | * Patrick Tasse - Fix TimeRangeException |
200789b3 AM |
12 | ******************************************************************************/ |
13 | ||
14 | package org.eclipse.linuxtools.tmf.core.statistics; | |
15 | ||
200789b3 | 16 | import java.util.HashMap; |
f3f93fa6 | 17 | import java.util.LinkedList; |
200789b3 AM |
18 | import java.util.List; |
19 | import java.util.Map; | |
20 | ||
8192f2c6 | 21 | import org.eclipse.jdt.annotation.NonNull; |
200789b3 | 22 | import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; |
96345c5a | 23 | import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; |
200789b3 AM |
24 | import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; |
25 | import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; | |
200789b3 | 26 | import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; |
200789b3 | 27 | import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; |
200789b3 AM |
28 | |
29 | /** | |
1c0de632 | 30 | * Implementation of ITmfStatistics which uses a state history for storing its |
802017fe AM |
31 | * information. In reality, it uses two state histories, one for "event totals" |
32 | * information (which should ideally use a fast backend), and another one for | |
33 | * the rest (per event type, per CPU, etc.). | |
1c0de632 | 34 | * |
802017fe AM |
35 | * Compared to the event-request-based statistics calculations, it adds the |
36 | * building the history first, but gives much faster response times once built : | |
37 | * Queries are O(log n) wrt the size of the trace, and O(1) wrt to the size of | |
38 | * the time interval selected. | |
200789b3 AM |
39 | * |
40 | * @author Alexandre Montplaisir | |
41 | * @since 2.0 | |
42 | */ | |
1c0de632 | 43 | public class TmfStateStatistics implements ITmfStatistics { |
200789b3 | 44 | |
802017fe AM |
45 | // ------------------------------------------------------------------------ |
46 | // Fields | |
47 | // ------------------------------------------------------------------------ | |
200789b3 | 48 | |
802017fe AM |
49 | /** The event totals state system */ |
50 | private final ITmfStateSystem totalsStats; | |
51 | ||
52 | /** The state system for event types */ | |
53 | private final ITmfStateSystem typesStats; | |
54 | ||
55 | // ------------------------------------------------------------------------ | |
56 | // Constructors | |
57 | // ------------------------------------------------------------------------ | |
200789b3 AM |
58 | |
59 | /** | |
60 | * Constructor | |
61 | * | |
8192f2c6 AM |
62 | * @param totals |
63 | * The state system containing the "totals" information | |
64 | * @param eventTypes | |
65 | * The state system containing the "event types" information | |
66 | * @since 3.0 | |
200789b3 | 67 | */ |
d6b46913 | 68 | public TmfStateStatistics(@NonNull ITmfStateSystem totals, @NonNull ITmfStateSystem eventTypes) { |
8192f2c6 AM |
69 | this.totalsStats = totals; |
70 | this.typesStats = eventTypes; | |
802017fe AM |
71 | } |
72 | ||
6c5e0863 | 73 | /** |
8192f2c6 AM |
74 | * Return the state system containing the "totals" values |
75 | * | |
76 | * @return The "totals" state system | |
77 | * @since 3.0 | |
78 | */ | |
79 | public ITmfStateSystem getTotalsSS() { | |
80 | return totalsStats; | |
81 | } | |
82 | ||
83 | /** | |
84 | * Return the state system containing the "event types" values | |
85 | * | |
86 | * @return The "event types" state system | |
87 | * @since 3.0 | |
6c5e0863 | 88 | */ |
8192f2c6 AM |
89 | public ITmfStateSystem getEventTypesSS() { |
90 | return typesStats; | |
e1c43333 AM |
91 | } |
92 | ||
200789b3 | 93 | // ------------------------------------------------------------------------ |
1c0de632 | 94 | // ITmfStatistics |
200789b3 AM |
95 | // ------------------------------------------------------------------------ |
96 | ||
1a4205d9 AM |
97 | @Override |
98 | public void dispose() { | |
802017fe AM |
99 | totalsStats.dispose(); |
100 | typesStats.dispose(); | |
1a4205d9 AM |
101 | } |
102 | ||
f3f93fa6 AM |
103 | @Override |
104 | public List<Long> histogramQuery(final long start, final long end, final int nb) { | |
a4524c1b | 105 | final List<Long> list = new LinkedList<>(); |
f3f93fa6 AM |
106 | final long increment = (end - start) / nb; |
107 | ||
2002c638 | 108 | if (totalsStats.isCancelled()) { |
802017fe | 109 | return list; |
f3f93fa6 AM |
110 | } |
111 | ||
112 | /* | |
113 | * We will do one state system query per "border", and save the | |
114 | * differences between each border. | |
115 | */ | |
802017fe | 116 | long prevTotal = (start == totalsStats.getStartTime()) ? 0 : getEventCountAt(start); |
f3f93fa6 AM |
117 | long curTime = start + increment; |
118 | ||
119 | long curTotal, count; | |
120 | for (int i = 0; i < nb - 1; i++) { | |
121 | curTotal = getEventCountAt(curTime); | |
122 | count = curTotal - prevTotal; | |
123 | list.add(count); | |
124 | ||
125 | curTime += increment; | |
126 | prevTotal = curTotal; | |
127 | } | |
128 | ||
129 | /* | |
130 | * For the last bucket, we'll stretch its end time to the end time of | |
131 | * the requested range, in case it got truncated down. | |
132 | */ | |
133 | curTotal = getEventCountAt(end); | |
134 | count = curTotal - prevTotal; | |
135 | list.add(count); | |
1c0de632 | 136 | |
f3f93fa6 | 137 | return list; |
1c0de632 AM |
138 | } |
139 | ||
200789b3 AM |
140 | @Override |
141 | public long getEventsTotal() { | |
802017fe | 142 | long endTime = totalsStats.getCurrentEndTime(); |
e1c43333 | 143 | int count = 0; |
df310609 AM |
144 | |
145 | try { | |
802017fe AM |
146 | final int quark = totalsStats.getQuarkAbsolute(Attributes.TOTAL); |
147 | count= totalsStats.querySingleState(endTime, quark).getStateValue().unboxInt(); | |
1c0de632 AM |
148 | |
149 | } catch (TimeRangeException e) { | |
150 | /* Assume there is no events for that range */ | |
151 | return 0; | |
55954069 | 152 | } catch (AttributeNotFoundException | StateValueTypeException | StateSystemDisposedException e) { |
96345c5a | 153 | e.printStackTrace(); |
200789b3 | 154 | } |
df310609 | 155 | |
e1c43333 | 156 | return count; |
200789b3 AM |
157 | } |
158 | ||
159 | @Override | |
160 | public Map<String, Long> getEventTypesTotal() { | |
55954069 | 161 | final Map<String, Long> map = new HashMap<>(); |
802017fe | 162 | long endTime = typesStats.getCurrentEndTime(); |
200789b3 AM |
163 | |
164 | try { | |
165 | /* Get the list of quarks, one for each even type in the database */ | |
802017fe AM |
166 | int quark = typesStats.getQuarkAbsolute(Attributes.EVENT_TYPES); |
167 | List<Integer> quarks = typesStats.getSubAttributes(quark, false); | |
200789b3 AM |
168 | |
169 | /* Since we want the total we can look only at the end */ | |
802017fe | 170 | List<ITmfStateInterval> endState = typesStats.queryFullState(endTime); |
200789b3 AM |
171 | |
172 | String curEventName; | |
173 | long eventCount; | |
174 | for (int typeQuark : quarks) { | |
802017fe | 175 | curEventName = typesStats.getAttributeName(typeQuark); |
200789b3 AM |
176 | eventCount = endState.get(typeQuark).getStateValue().unboxInt(); |
177 | map.put(curEventName, eventCount); | |
178 | } | |
179 | ||
180 | } catch (TimeRangeException e) { | |
1c0de632 | 181 | /* Assume there is no events, nothing will be put in the map. */ |
8192f2c6 | 182 | } catch (AttributeNotFoundException | StateValueTypeException | StateSystemDisposedException e) { |
96345c5a | 183 | e.printStackTrace(); |
200789b3 AM |
184 | } |
185 | return map; | |
186 | } | |
187 | ||
188 | @Override | |
8b260d9f | 189 | public long getEventsInRange(long start, long end) { |
f3f93fa6 | 190 | long startCount; |
802017fe | 191 | if (start == totalsStats.getStartTime()) { |
f3f93fa6 AM |
192 | startCount = 0; |
193 | } else { | |
194 | /* | |
195 | * We want the events happening at "start" to be included, so we'll | |
196 | * need to query one unit before that point. | |
197 | */ | |
198 | startCount = getEventCountAt(start - 1); | |
200789b3 | 199 | } |
f3f93fa6 | 200 | long endCount = getEventCountAt(end); |
df310609 | 201 | |
f3f93fa6 | 202 | return endCount - startCount; |
200789b3 AM |
203 | } |
204 | ||
205 | @Override | |
8b260d9f | 206 | public Map<String, Long> getEventTypesInRange(long start, long end) { |
55954069 AM |
207 | final Map<String, Long> map = new HashMap<>(); |
208 | List<Integer> quarks; | |
200789b3 AM |
209 | |
210 | /* Make sure the start/end times are within the state history, so we | |
211 | * don't get TimeRange exceptions. | |
212 | */ | |
63fe91fb PT |
213 | long startTime = checkStartTime(start, typesStats); |
214 | long endTime = checkEndTime(end, typesStats); | |
200789b3 AM |
215 | |
216 | try { | |
217 | /* Get the list of quarks, one for each even type in the database */ | |
802017fe | 218 | int quark = typesStats.getQuarkAbsolute(Attributes.EVENT_TYPES); |
55954069 AM |
219 | quarks = typesStats.getSubAttributes(quark, false); |
220 | } catch (AttributeNotFoundException e) { | |
221 | /* | |
222 | * The state system does not (yet?) have the needed attributes, it | |
223 | * probably means there are no events counted yet. Return the empty | |
224 | * map. | |
225 | */ | |
226 | return map; | |
227 | } | |
200789b3 | 228 | |
55954069 | 229 | try { |
802017fe | 230 | List<ITmfStateInterval> endState = typesStats.queryFullState(endTime); |
200789b3 | 231 | |
802017fe | 232 | if (startTime == typesStats.getStartTime()) { |
e1c43333 AM |
233 | /* Only use the values picked up at the end time */ |
234 | for (int typeQuark : quarks) { | |
55954069 AM |
235 | String curEventName = typesStats.getAttributeName(typeQuark); |
236 | long eventCount = endState.get(typeQuark).getStateValue().unboxInt(); | |
e1c43333 AM |
237 | if (eventCount == -1) { |
238 | eventCount = 0; | |
239 | } | |
240 | map.put(curEventName, eventCount); | |
200789b3 | 241 | } |
e1c43333 | 242 | } else { |
200789b3 | 243 | /* |
e1c43333 AM |
244 | * Query the start time at -1, so the beginning of the interval |
245 | * is inclusive. | |
200789b3 | 246 | */ |
802017fe | 247 | List<ITmfStateInterval> startState = typesStats.queryFullState(startTime - 1); |
e1c43333 | 248 | for (int typeQuark : quarks) { |
55954069 AM |
249 | String curEventName = typesStats.getAttributeName(typeQuark); |
250 | long countAtStart = startState.get(typeQuark).getStateValue().unboxInt(); | |
251 | long countAtEnd = endState.get(typeQuark).getStateValue().unboxInt(); | |
e1c43333 AM |
252 | |
253 | if (countAtStart == -1) { | |
254 | countAtStart = 0; | |
255 | } | |
256 | if (countAtEnd == -1) { | |
257 | countAtEnd = 0; | |
258 | } | |
55954069 | 259 | long eventCount = countAtEnd - countAtStart; |
e1c43333 | 260 | map.put(curEventName, eventCount); |
200789b3 | 261 | } |
200789b3 | 262 | } |
e1c43333 | 263 | |
55954069 AM |
264 | } catch (TimeRangeException | StateSystemDisposedException e) { |
265 | /* Assume there is no (more) events, nothing will be put in the map. */ | |
266 | } catch (StateValueTypeException e) { | |
200789b3 | 267 | /* |
55954069 | 268 | * This exception type would show a logic problem however, |
1c0de632 | 269 | * so they should not happen. |
200789b3 | 270 | */ |
55954069 | 271 | throw new IllegalStateException(); |
200789b3 AM |
272 | } |
273 | return map; | |
274 | } | |
275 | ||
802017fe AM |
276 | // ------------------------------------------------------------------------ |
277 | // Helper methods | |
278 | // ------------------------------------------------------------------------ | |
279 | ||
f3f93fa6 AM |
280 | private long getEventCountAt(long timestamp) { |
281 | /* Make sure the target time is within the range of the history */ | |
63fe91fb PT |
282 | long ts = checkStartTime(timestamp, totalsStats); |
283 | ts = checkEndTime(ts, totalsStats); | |
f3f93fa6 AM |
284 | |
285 | try { | |
802017fe AM |
286 | final int quark = totalsStats.getQuarkAbsolute(Attributes.TOTAL); |
287 | long count = totalsStats.querySingleState(ts, quark).getStateValue().unboxInt(); | |
f3f93fa6 AM |
288 | return count; |
289 | ||
290 | } catch (TimeRangeException e) { | |
291 | /* Assume there is no events for that range */ | |
8192f2c6 | 292 | } catch (AttributeNotFoundException | StateValueTypeException | StateSystemDisposedException e) { |
f3f93fa6 AM |
293 | e.printStackTrace(); |
294 | } | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
63fe91fb | 299 | private static long checkStartTime(long initialStart, ITmfStateSystem ss) { |
8b260d9f | 300 | long start = initialStart; |
63fe91fb PT |
301 | if (start < ss.getStartTime()) { |
302 | return ss.getStartTime(); | |
200789b3 AM |
303 | } |
304 | return start; | |
305 | } | |
306 | ||
63fe91fb | 307 | private static long checkEndTime(long initialEnd, ITmfStateSystem ss) { |
8b260d9f | 308 | long end = initialEnd; |
63fe91fb PT |
309 | if (end > ss.getCurrentEndTime()) { |
310 | return ss.getCurrentEndTime(); | |
200789b3 AM |
311 | } |
312 | return end; | |
313 | } | |
314 | ||
200789b3 AM |
315 | /** |
316 | * The attribute names that are used in the state provider | |
317 | */ | |
318 | public static class Attributes { | |
319 | ||
df310609 AM |
320 | /** Total nb of events */ |
321 | public static final String TOTAL = "total"; //$NON-NLS-1$ | |
322 | ||
200789b3 AM |
323 | /** event_types */ |
324 | public static final String EVENT_TYPES = "event_types"; //$NON-NLS-1$< | |
325 | } | |
326 | } |