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