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