tmf: Add some unit tests to the ITmfStatistics
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / statistics / TmfStateStatistics.java
CommitLineData
200789b3
AM
1/*******************************************************************************
2 * Copyright (c) 2012 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 ******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.core.statistics;
14
15import java.io.File;
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
19
20import org.eclipse.core.resources.IResource;
21import org.eclipse.core.runtime.CoreException;
22import org.eclipse.linuxtools.tmf.core.TmfCommonConstants;
23import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
24import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
25import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
26import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
27import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
28import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
1c0de632
AM
29import org.eclipse.linuxtools.tmf.core.signal.TmfSignal;
30import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
31import org.eclipse.linuxtools.tmf.core.signal.TmfStatsUpdatedSignal;
200789b3
AM
32import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput;
33import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
34import org.eclipse.linuxtools.tmf.core.statesystem.StateSystemManager;
35import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
36
37/**
1c0de632
AM
38 * Implementation of ITmfStatistics which uses a state history for storing its
39 * information.
40 *
41 * It requires building the history first, but gives very fast response times
42 * when built : Queries are O(log n) wrt the size of the trace, and O(1) wrt to
43 * the size of the time interval selected.
200789b3
AM
44 *
45 * @author Alexandre Montplaisir
46 * @since 2.0
47 */
48
1c0de632 49public class TmfStateStatistics implements ITmfStatistics {
200789b3 50
a76f1067
AM
51 /** ID for the statistics state system */
52 public static final String STATE_ID = "org.eclipse.linuxtools.tmf.statistics"; //$NON-NLS-1$
53
1c0de632 54 /** Filename the "statistics state history" file will have */
200789b3
AM
55 private static final String STATS_STATE_FILENAME = "statistics.ht"; //$NON-NLS-1$
56
1c0de632
AM
57 private final ITmfTrace trace;
58
59 /**
200789b3
AM
60 * The state system that's used to stored the statistics. It's hidden from
61 * the trace, so that it doesn't conflict with ITmfTrace.getStateSystem()
62 * (which is something else!)
63 */
64 private final ITmfStateSystem stats;
65
36033ff0
AM
66 /**
67 * Empty constructor. The resulting TmfStatistics object will not be usable,
68 * but it might be needed for sub-classes.
69 */
1c0de632 70 public TmfStateStatistics() {
89c06060 71 stats = null;
1c0de632 72 trace = null;
89c06060
AM
73 }
74
200789b3
AM
75 /**
76 * Constructor
77 *
78 * @param trace
79 * The trace for which we build these statistics
80 * @throws TmfTraceException
81 * If something went wrong trying to initialize the statistics
82 */
1c0de632 83 public TmfStateStatistics(ITmfTrace trace) throws TmfTraceException {
200789b3 84 /* Set up the path to the history tree file we'll use */
1c0de632 85 this.trace = trace;
200789b3
AM
86 IResource resource = trace.getResource();
87 String supplDirectory = null;
88
89 try {
90 // get the directory where the history file will be stored.
91 supplDirectory = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
92 } catch (CoreException e) {
93 throw new TmfTraceException(e.toString(), e);
94 }
95
96 final File htFile = new File(supplDirectory + File.separator + STATS_STATE_FILENAME);
97 final IStateChangeInput htInput = new StatsStateProvider(trace);
98
a76f1067 99 this.stats = StateSystemManager.loadStateHistory(htFile, htInput, STATE_ID, false);
200789b3
AM
100 }
101
e1c43333
AM
102 /**
103 * Manual constructor. This should be used if the trace's Resource is null
104 * (ie, for unit tests). It requires specifying the location of the history
105 * file manually.
106 *
107 * @param trace
108 * The trace for which we build these statistics
109 * @param historyFile
110 * The location of the state history file to build for the stats
111 * @throws TmfTraceException
112 * If the file could not be written to
113 */
114 public TmfStateStatistics(ITmfTrace trace, File historyFile) throws TmfTraceException {
115 this.trace = trace;
116 final IStateChangeInput htInput = new StatsStateProvider(trace);
117 this.stats = StateSystemManager.loadStateHistory(historyFile, htInput, STATE_ID, true);
118 }
119
200789b3 120 // ------------------------------------------------------------------------
1c0de632 121 // ITmfStatistics
200789b3
AM
122 // ------------------------------------------------------------------------
123
1c0de632
AM
124 @Override
125 public void updateStats(final boolean isGlobal, final ITmfTimestamp start,
126 final ITmfTimestamp end) {
127 /*
128 * Since we are currently in a signal handler (ie, in the UI thread),
129 * and since state system queries can be arbitrarily long (O(log n) wrt
130 * the size of the trace), we will run those queries in a separate
131 * thread and update the statistics view out-of-band.
132 */
133 Thread statsThread = new Thread("Statistics update") { //$NON-NLS-1$
134 @Override
135 public void run() {
136 long total;
137 Map<String, Long> map;
138
139 /* Wait until the history building completed */
140 stats.waitUntilBuilt();
141
142 /* Range should be valid for both global and time range queries */
143 total = getEventsInRange(start, end);
144 map = getEventTypesInRange(start, end);
145
146 /* Send the signal to notify the stats viewer to update its display */
147 TmfSignal sig = new TmfStatsUpdatedSignal(this, trace, isGlobal, total, map);
148 TmfSignalManager.dispatchSignal(sig);
149 }
150 };
151 statsThread.start();
152 return;
153
154 }
155
200789b3
AM
156 @Override
157 public long getEventsTotal() {
e1c43333
AM
158 /* We need the complete state history to be built to answer this. */
159 stats.waitUntilBuilt();
160
1c0de632 161 long endTime = stats.getCurrentEndTime();
e1c43333 162 int count = 0;
df310609
AM
163
164 try {
165 final int quark = stats.getQuarkAbsolute(Attributes.TOTAL);
e1c43333 166 count= stats.querySingleState(endTime, quark).getStateValue().unboxInt();
1c0de632
AM
167
168 } catch (TimeRangeException e) {
169 /* Assume there is no events for that range */
170 return 0;
df310609
AM
171 } catch (AttributeNotFoundException e) {
172 e.printStackTrace();
173 } catch (StateValueTypeException e) {
174 e.printStackTrace();
200789b3 175 }
df310609 176
e1c43333 177 return count;
200789b3
AM
178 }
179
180 @Override
181 public Map<String, Long> getEventTypesTotal() {
e1c43333
AM
182 /* We need the complete state history to be built to answer this. */
183 stats.waitUntilBuilt();
184
200789b3 185 Map<String, Long> map = new HashMap<String, Long>();
e1c43333 186 long endTime = stats.getCurrentEndTime();
200789b3
AM
187
188 try {
189 /* Get the list of quarks, one for each even type in the database */
190 int quark = stats.getQuarkAbsolute(Attributes.EVENT_TYPES);
191 List<Integer> quarks = stats.getSubAttributes(quark, false);
192
193 /* Since we want the total we can look only at the end */
194 List<ITmfStateInterval> endState = stats.queryFullState(endTime);
195
196 String curEventName;
197 long eventCount;
198 for (int typeQuark : quarks) {
199 curEventName = stats.getAttributeName(typeQuark);
200 eventCount = endState.get(typeQuark).getStateValue().unboxInt();
201 map.put(curEventName, eventCount);
202 }
203
204 } catch (TimeRangeException e) {
1c0de632 205 /* Assume there is no events, nothing will be put in the map. */
200789b3
AM
206 } catch (AttributeNotFoundException e) {
207 e.printStackTrace();
208 } catch (StateValueTypeException e) {
209 e.printStackTrace();
210 }
211 return map;
212 }
213
214 @Override
215 public long getEventsInRange(ITmfTimestamp start, ITmfTimestamp end) {
e1c43333
AM
216 // FIXME Instead of waiting until the end, we could check the current
217 // end time, and answer as soon as possible...
218 stats.waitUntilBuilt();
219
df310609 220 int countAtStart = 0, countAtEnd = 0;
1c0de632
AM
221 long startTime = checkStartTime(start);
222 long endTime = checkEndTime(end);
df310609
AM
223
224 try {
225 final int quark = stats.getQuarkAbsolute(Attributes.TOTAL);
e1c43333
AM
226 if (startTime == stats.getStartTime()) {
227 countAtStart = 0;
228 } else {
229 /* State system works that way... */
230 countAtStart = stats.querySingleState(startTime - 1, quark).getStateValue().unboxInt();
231 }
1c0de632
AM
232 countAtEnd = stats.querySingleState(endTime, quark).getStateValue().unboxInt();
233
234 } catch (TimeRangeException e) {
235 /* Assume there is no events for that range */
236 return 0;
df310609
AM
237 } catch (AttributeNotFoundException e) {
238 e.printStackTrace();
239 } catch (StateValueTypeException e) {
240 e.printStackTrace();
200789b3 241 }
df310609
AM
242
243 long total = countAtEnd - countAtStart;
200789b3
AM
244 return total;
245 }
246
247 @Override
248 public Map<String, Long> getEventTypesInRange(ITmfTimestamp start, ITmfTimestamp end) {
e1c43333
AM
249 // FIXME Instead of waiting until the end, we could check the current
250 // end time, and answer as soon as possible...
251 stats.waitUntilBuilt();
252
200789b3
AM
253 Map<String, Long> map = new HashMap<String, Long>();
254
255 /* Make sure the start/end times are within the state history, so we
256 * don't get TimeRange exceptions.
257 */
1c0de632
AM
258 long startTime = checkStartTime(start);
259 long endTime = checkEndTime(end);
200789b3
AM
260
261 try {
262 /* Get the list of quarks, one for each even type in the database */
263 int quark = stats.getQuarkAbsolute(Attributes.EVENT_TYPES);
264 List<Integer> quarks = stats.getSubAttributes(quark, false);
265
1c0de632 266 List<ITmfStateInterval> endState = stats.queryFullState(endTime);
200789b3 267
200789b3
AM
268 String curEventName;
269 long countAtStart, countAtEnd, eventCount;
200789b3 270
e1c43333
AM
271 if (startTime == stats.getStartTime()) {
272 /* Only use the values picked up at the end time */
273 for (int typeQuark : quarks) {
274 curEventName = stats.getAttributeName(typeQuark);
275 eventCount = endState.get(typeQuark).getStateValue().unboxInt();
276 if (eventCount == -1) {
277 eventCount = 0;
278 }
279 map.put(curEventName, eventCount);
200789b3 280 }
e1c43333 281 } else {
200789b3 282 /*
e1c43333
AM
283 * Query the start time at -1, so the beginning of the interval
284 * is inclusive.
200789b3 285 */
e1c43333
AM
286 List<ITmfStateInterval> startState = stats.queryFullState(startTime - 1);
287 for (int typeQuark : quarks) {
288 curEventName = stats.getAttributeName(typeQuark);
289 countAtStart = startState.get(typeQuark).getStateValue().unboxInt();
290 countAtEnd = endState.get(typeQuark).getStateValue().unboxInt();
291
292 if (countAtStart == -1) {
293 countAtStart = 0;
294 }
295 if (countAtEnd == -1) {
296 countAtEnd = 0;
297 }
298 eventCount = countAtEnd - countAtStart;
299 map.put(curEventName, eventCount);
200789b3 300 }
200789b3 301 }
e1c43333 302
200789b3 303 } catch (TimeRangeException e) {
1c0de632 304 /* Assume there is no events, nothing will be put in the map. */
200789b3
AM
305 } catch (AttributeNotFoundException e) {
306 /*
1c0de632
AM
307 * These other exception types would show a logic problem however,
308 * so they should not happen.
200789b3
AM
309 */
310 e.printStackTrace();
311 } catch (StateValueTypeException e) {
312 e.printStackTrace();
313 }
314 return map;
315 }
316
1c0de632
AM
317 protected long checkStartTime(ITmfTimestamp startTs) {
318 long start = startTs.normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
200789b3
AM
319 if (start < stats.getStartTime()) {
320 return stats.getStartTime();
321 }
322 return start;
323 }
324
1c0de632
AM
325 protected long checkEndTime(ITmfTimestamp endTs) {
326 long end = endTs.normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
200789b3
AM
327 if (end > stats.getCurrentEndTime()) {
328 return stats.getCurrentEndTime();
329 }
330 return end;
331 }
332
333
334 /**
335 * The attribute names that are used in the state provider
336 */
337 public static class Attributes {
338
df310609
AM
339 /** Total nb of events */
340 public static final String TOTAL = "total"; //$NON-NLS-1$
341
200789b3
AM
342 /** event_types */
343 public static final String EVENT_TYPES = "event_types"; //$NON-NLS-1$<
344 }
345}
This page took 0.040657 seconds and 5 git commands to generate.