Merge branch 'master' into lttng-luna
[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 37 * Implementation of ITmfStatistics which uses a state history for storing its
802017fe
AM
38 * information. In reality, it uses two state histories, one for "event totals"
39 * information (which should ideally use a fast backend), and another one for
40 * the rest (per event type, per CPU, etc.).
1c0de632 41 *
802017fe
AM
42 * Compared to the event-request-based statistics calculations, it adds the
43 * building the history first, but gives much faster response times once built :
44 * Queries are O(log n) wrt the size of the trace, and O(1) wrt to the size of
45 * the time interval selected.
200789b3
AM
46 *
47 * @author Alexandre Montplaisir
48 * @since 2.0
49 */
1c0de632 50public class TmfStateStatistics implements ITmfStatistics {
200789b3 51
802017fe
AM
52 // ------------------------------------------------------------------------
53 // Constants
54 // ------------------------------------------------------------------------
55
56 /**
57 * @deprecated Do not use, it's been replaced by {@link #TOTALS_STATE_ID}
58 *  and {@link #TYPES_STATE_ID}
59 */
60 @Deprecated
a76f1067
AM
61 public static final String STATE_ID = "org.eclipse.linuxtools.tmf.statistics"; //$NON-NLS-1$
62
802017fe
AM
63 /** ID for the "event totals" statistics state system
64 * @since 2.2 */
65 public static final String TOTALS_STATE_ID = "org.eclipse.linuxtools.tmf.statistics.totals"; //$NON-NLS-1$
66
67 /** ID for the "event types" statistics state system
68 * @since 2.2 */
69 public static final String TYPES_STATE_ID = "org.eclipse.linuxtools.tmf.statistics.types"; //$NON-NLS-1$
70
71 /** Filename for the "event totals" state history file */
72 private static final String TOTALS_STATE_FILENAME = "statistics-totals.ht"; //$NON-NLS-1$
73
74 /** Filename for the "event types" state history file */
75 private static final String TYPES_STATE_FILENAME = "statistics-types.ht"; //$NON-NLS-1$
76
77 // ------------------------------------------------------------------------
78 // Fields
79 // ------------------------------------------------------------------------
200789b3 80
1c0de632
AM
81 private final ITmfTrace trace;
82
802017fe
AM
83 /** The event totals state system */
84 private final ITmfStateSystem totalsStats;
85
86 /** The state system for event types */
87 private final ITmfStateSystem typesStats;
88
89 // ------------------------------------------------------------------------
90 // Constructors
91 // ------------------------------------------------------------------------
200789b3 92
36033ff0
AM
93 /**
94 * Empty constructor. The resulting TmfStatistics object will not be usable,
95 * but it might be needed for sub-classes.
96 */
1c0de632 97 public TmfStateStatistics() {
802017fe
AM
98 totalsStats = null;
99 typesStats = null;
1c0de632 100 trace = null;
89c06060
AM
101 }
102
200789b3
AM
103 /**
104 * Constructor
105 *
106 * @param trace
107 * The trace for which we build these statistics
108 * @throws TmfTraceException
109 * If something went wrong trying to initialize the statistics
110 */
1c0de632 111 public TmfStateStatistics(ITmfTrace trace) throws TmfTraceException {
1c0de632 112 this.trace = trace;
e1385db9 113 String directory = TmfTraceManager.getSupplementaryFileDir(trace);
200789b3 114
802017fe
AM
115 final File totalsFile = new File(directory + TOTALS_STATE_FILENAME);
116 final ITmfStateProvider totalsInput = new StatsProviderTotals(trace);
117 this.totalsStats = TmfStateSystemFactory.newFullHistory(totalsFile, totalsInput, false);
118
119 final File typesFile = new File(directory + TYPES_STATE_FILENAME);
120 final ITmfStateProvider typesInput = new StatsProviderEventTypes(trace);
121 this.typesStats = TmfStateSystemFactory.newFullHistory(typesFile, typesInput, false);
122
6c5e0863 123 registerStateSystems();
200789b3
AM
124 }
125
802017fe
AM
126 /**
127 * Old manual constructor.
128 *
129 * @param trace Trace
130 * @param historyFile Full history file
131 * @deprecated Need to use {@link #TmfStateStatistics(ITmfTrace trace,
132 * File fullHistoryFile, File partialHistoryFile)} now.
133 */
134 @Deprecated
135 public TmfStateStatistics(ITmfTrace trace, File historyFile) {
136 this();
137 }
138
e1c43333
AM
139 /**
140 * Manual constructor. This should be used if the trace's Resource is null
141 * (ie, for unit tests). It requires specifying the location of the history
802017fe 142 * files manually.
e1c43333
AM
143 *
144 * @param trace
145 * The trace for which we build these statistics
802017fe
AM
146 * @param totalsHistoryFile
147 * The location of the totals state history file
148 * @param typesHistoryFile
149 * The location of the types state history file
e1c43333
AM
150 * @throws TmfTraceException
151 * If the file could not be written to
802017fe 152 * @since 2.2
e1c43333 153 */
802017fe
AM
154 public TmfStateStatistics(ITmfTrace trace, File totalsHistoryFile,
155 File typesHistoryFile) throws TmfTraceException {
e1c43333 156 this.trace = trace;
802017fe
AM
157 final ITmfStateProvider totalsInput = new StatsProviderTotals(trace);
158 final ITmfStateProvider typesInput = new StatsProviderEventTypes(trace);
159 this.totalsStats = TmfStateSystemFactory.newFullHistory(totalsHistoryFile, totalsInput, true);
160 this.typesStats = TmfStateSystemFactory.newFullHistory(typesHistoryFile, typesInput, true);
6c5e0863
AM
161 registerStateSystems();
162 }
163
164 /**
802017fe 165 * Register the state systems used here into the trace's state system map.
6c5e0863
AM
166 */
167 private void registerStateSystems() {
802017fe
AM
168 trace.registerStateSystem(TOTALS_STATE_ID, totalsStats);
169 trace.registerStateSystem(TYPES_STATE_ID, typesStats);
e1c43333
AM
170 }
171
200789b3 172 // ------------------------------------------------------------------------
1c0de632 173 // ITmfStatistics
200789b3
AM
174 // ------------------------------------------------------------------------
175
1a4205d9
AM
176 @Override
177 public void dispose() {
802017fe
AM
178 totalsStats.dispose();
179 typesStats.dispose();
1a4205d9
AM
180 }
181
1c0de632 182 @Override
8b260d9f
AM
183 public void updateStats(final boolean isGlobal, final long start,
184 final long end) {
1c0de632
AM
185 /*
186 * Since we are currently in a signal handler (ie, in the UI thread),
187 * and since state system queries can be arbitrarily long (O(log n) wrt
188 * the size of the trace), we will run those queries in a separate
189 * thread and update the statistics view out-of-band.
190 */
191 Thread statsThread = new Thread("Statistics update") { //$NON-NLS-1$
192 @Override
193 public void run() {
802017fe
AM
194 /* Wait until the history building is completed */
195 if (!waitUntilBuilt()) {
1a4205d9
AM
196 return;
197 }
1c0de632
AM
198
199 /* Range should be valid for both global and time range queries */
802017fe
AM
200 long total = getEventsInRange(start, end);
201 Map<String, Long> map = getEventTypesInRange(start, end);
1c0de632
AM
202
203 /* Send the signal to notify the stats viewer to update its display */
204 TmfSignal sig = new TmfStatsUpdatedSignal(this, trace, isGlobal, total, map);
205 TmfSignalManager.dispatchSignal(sig);
206 }
207 };
208 statsThread.start();
209 return;
f3f93fa6
AM
210 }
211
212 @Override
213 public List<Long> histogramQuery(final long start, final long end, final int nb) {
214 final List<Long> list = new LinkedList<Long>();
215 final long increment = (end - start) / nb;
216
802017fe
AM
217 if (!totalsStats.waitUntilBuilt()) {
218 return list;
f3f93fa6
AM
219 }
220
221 /*
222 * We will do one state system query per "border", and save the
223 * differences between each border.
224 */
802017fe 225 long prevTotal = (start == totalsStats.getStartTime()) ? 0 : getEventCountAt(start);
f3f93fa6
AM
226 long curTime = start + increment;
227
228 long curTotal, count;
229 for (int i = 0; i < nb - 1; i++) {
230 curTotal = getEventCountAt(curTime);
231 count = curTotal - prevTotal;
232 list.add(count);
233
234 curTime += increment;
235 prevTotal = curTotal;
236 }
237
238 /*
239 * For the last bucket, we'll stretch its end time to the end time of
240 * the requested range, in case it got truncated down.
241 */
242 curTotal = getEventCountAt(end);
243 count = curTotal - prevTotal;
244 list.add(count);
1c0de632 245
f3f93fa6 246 return list;
1c0de632
AM
247 }
248
200789b3
AM
249 @Override
250 public long getEventsTotal() {
e1c43333 251 /* We need the complete state history to be built to answer this. */
802017fe 252 totalsStats.waitUntilBuilt();
e1c43333 253
802017fe 254 long endTime = totalsStats.getCurrentEndTime();
e1c43333 255 int count = 0;
df310609
AM
256
257 try {
802017fe
AM
258 final int quark = totalsStats.getQuarkAbsolute(Attributes.TOTAL);
259 count= totalsStats.querySingleState(endTime, quark).getStateValue().unboxInt();
1c0de632
AM
260
261 } catch (TimeRangeException e) {
262 /* Assume there is no events for that range */
263 return 0;
df310609
AM
264 } catch (AttributeNotFoundException e) {
265 e.printStackTrace();
266 } catch (StateValueTypeException e) {
267 e.printStackTrace();
96345c5a
AM
268 } catch (StateSystemDisposedException e) {
269 e.printStackTrace();
200789b3 270 }
df310609 271
e1c43333 272 return count;
200789b3
AM
273 }
274
275 @Override
276 public Map<String, Long> getEventTypesTotal() {
e1c43333 277 /* We need the complete state history to be built to answer this. */
802017fe 278 typesStats.waitUntilBuilt();
e1c43333 279
200789b3 280 Map<String, Long> map = new HashMap<String, Long>();
802017fe 281 long endTime = typesStats.getCurrentEndTime();
200789b3
AM
282
283 try {
284 /* Get the list of quarks, one for each even type in the database */
802017fe
AM
285 int quark = typesStats.getQuarkAbsolute(Attributes.EVENT_TYPES);
286 List<Integer> quarks = typesStats.getSubAttributes(quark, false);
200789b3
AM
287
288 /* Since we want the total we can look only at the end */
802017fe 289 List<ITmfStateInterval> endState = typesStats.queryFullState(endTime);
200789b3
AM
290
291 String curEventName;
292 long eventCount;
293 for (int typeQuark : quarks) {
802017fe 294 curEventName = typesStats.getAttributeName(typeQuark);
200789b3
AM
295 eventCount = endState.get(typeQuark).getStateValue().unboxInt();
296 map.put(curEventName, eventCount);
297 }
298
299 } catch (TimeRangeException e) {
1c0de632 300 /* Assume there is no events, nothing will be put in the map. */
200789b3
AM
301 } catch (AttributeNotFoundException e) {
302 e.printStackTrace();
303 } catch (StateValueTypeException e) {
304 e.printStackTrace();
96345c5a
AM
305 } catch (StateSystemDisposedException e) {
306 e.printStackTrace();
200789b3
AM
307 }
308 return map;
309 }
310
311 @Override
8b260d9f 312 public long getEventsInRange(long start, long end) {
e1c43333
AM
313 // FIXME Instead of waiting until the end, we could check the current
314 // end time, and answer as soon as possible...
802017fe 315 totalsStats.waitUntilBuilt();
e1c43333 316
f3f93fa6 317 long startCount;
802017fe 318 if (start == totalsStats.getStartTime()) {
f3f93fa6
AM
319 startCount = 0;
320 } else {
321 /*
322 * We want the events happening at "start" to be included, so we'll
323 * need to query one unit before that point.
324 */
325 startCount = getEventCountAt(start - 1);
200789b3 326 }
f3f93fa6 327 long endCount = getEventCountAt(end);
df310609 328
f3f93fa6 329 return endCount - startCount;
200789b3
AM
330 }
331
332 @Override
8b260d9f 333 public Map<String, Long> getEventTypesInRange(long start, long end) {
e1c43333
AM
334 // FIXME Instead of waiting until the end, we could check the current
335 // end time, and answer as soon as possible...
802017fe 336 typesStats.waitUntilBuilt();
e1c43333 337
200789b3
AM
338 Map<String, Long> map = new HashMap<String, Long>();
339
340 /* Make sure the start/end times are within the state history, so we
341 * don't get TimeRange exceptions.
342 */
1c0de632
AM
343 long startTime = checkStartTime(start);
344 long endTime = checkEndTime(end);
200789b3
AM
345
346 try {
347 /* Get the list of quarks, one for each even type in the database */
802017fe
AM
348 int quark = typesStats.getQuarkAbsolute(Attributes.EVENT_TYPES);
349 List<Integer> quarks = typesStats.getSubAttributes(quark, false);
200789b3 350
802017fe 351 List<ITmfStateInterval> endState = typesStats.queryFullState(endTime);
200789b3 352
200789b3
AM
353 String curEventName;
354 long countAtStart, countAtEnd, eventCount;
200789b3 355
802017fe 356 if (startTime == typesStats.getStartTime()) {
e1c43333
AM
357 /* Only use the values picked up at the end time */
358 for (int typeQuark : quarks) {
802017fe 359 curEventName = typesStats.getAttributeName(typeQuark);
e1c43333
AM
360 eventCount = endState.get(typeQuark).getStateValue().unboxInt();
361 if (eventCount == -1) {
362 eventCount = 0;
363 }
364 map.put(curEventName, eventCount);
200789b3 365 }
e1c43333 366 } else {
200789b3 367 /*
e1c43333
AM
368 * Query the start time at -1, so the beginning of the interval
369 * is inclusive.
200789b3 370 */
802017fe 371 List<ITmfStateInterval> startState = typesStats.queryFullState(startTime - 1);
e1c43333 372 for (int typeQuark : quarks) {
802017fe 373 curEventName = typesStats.getAttributeName(typeQuark);
e1c43333
AM
374 countAtStart = startState.get(typeQuark).getStateValue().unboxInt();
375 countAtEnd = endState.get(typeQuark).getStateValue().unboxInt();
376
377 if (countAtStart == -1) {
378 countAtStart = 0;
379 }
380 if (countAtEnd == -1) {
381 countAtEnd = 0;
382 }
383 eventCount = countAtEnd - countAtStart;
384 map.put(curEventName, eventCount);
200789b3 385 }
200789b3 386 }
e1c43333 387
200789b3 388 } catch (TimeRangeException e) {
1c0de632 389 /* Assume there is no events, nothing will be put in the map. */
200789b3
AM
390 } catch (AttributeNotFoundException e) {
391 /*
1c0de632
AM
392 * These other exception types would show a logic problem however,
393 * so they should not happen.
200789b3
AM
394 */
395 e.printStackTrace();
396 } catch (StateValueTypeException e) {
397 e.printStackTrace();
96345c5a
AM
398 } catch (StateSystemDisposedException e) {
399 e.printStackTrace();
200789b3
AM
400 }
401 return map;
402 }
403
802017fe
AM
404 // ------------------------------------------------------------------------
405 // Helper methods
406 // ------------------------------------------------------------------------
407
f3f93fa6
AM
408 private long getEventCountAt(long timestamp) {
409 /* Make sure the target time is within the range of the history */
410 long ts = checkStartTime(timestamp);
411 ts = checkEndTime(ts);
412
413 try {
802017fe
AM
414 final int quark = totalsStats.getQuarkAbsolute(Attributes.TOTAL);
415 long count = totalsStats.querySingleState(ts, quark).getStateValue().unboxInt();
f3f93fa6
AM
416 return count;
417
418 } catch (TimeRangeException e) {
419 /* Assume there is no events for that range */
420 } catch (AttributeNotFoundException e) {
421 e.printStackTrace();
422 } catch (StateValueTypeException e) {
423 e.printStackTrace();
424 } catch (StateSystemDisposedException e) {
425 e.printStackTrace();
426 }
427
428 return 0;
429 }
430
8b260d9f
AM
431 private long checkStartTime(long initialStart) {
432 long start = initialStart;
802017fe
AM
433 if (start < totalsStats.getStartTime()) {
434 return totalsStats.getStartTime();
200789b3
AM
435 }
436 return start;
437 }
438
8b260d9f
AM
439 private long checkEndTime(long initialEnd) {
440 long end = initialEnd;
802017fe
AM
441 if (end > totalsStats.getCurrentEndTime()) {
442 return totalsStats.getCurrentEndTime();
200789b3
AM
443 }
444 return end;
445 }
446
802017fe
AM
447 /**
448 * Wait until both backing state systems are finished building.
449 *
450 * @return If both state systems were built successfully
451 */
452 private boolean waitUntilBuilt() {
453 boolean check1 = totalsStats.waitUntilBuilt();
454 boolean check2 = typesStats.waitUntilBuilt();
455 return (check1 && check2);
456 }
457
200789b3
AM
458
459 /**
460 * The attribute names that are used in the state provider
461 */
462 public static class Attributes {
463
df310609
AM
464 /** Total nb of events */
465 public static final String TOTAL = "total"; //$NON-NLS-1$
466
200789b3
AM
467 /** event_types */
468 public static final String EVENT_TYPES = "event_types"; //$NON-NLS-1$<
469 }
470}
This page took 0.057442 seconds and 5 git commands to generate.