1 /*******************************************************************************
2 * Copyright (c) 2012 Ericsson
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
10 * Alexandre Montplaisir - Initial API and implementation
11 ******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.statistics
;
16 import java
.util
.HashMap
;
17 import java
.util
.List
;
20 import org
.eclipse
.core
.resources
.IResource
;
21 import org
.eclipse
.core
.runtime
.CoreException
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfStatsUpdatedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.IStateChangeInput
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.StateSystemManager
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
38 * Implementation of ITmfStatistics which uses a state history for storing its
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.
45 * @author Alexandre Montplaisir
49 public class TmfStateStatistics
implements ITmfStatistics
{
51 /** ID for the statistics state system */
52 public static final String STATE_ID
= "org.eclipse.linuxtools.tmf.statistics"; //$NON-NLS-1$
54 /** Filename the "statistics state history" file will have */
55 private static final String STATS_STATE_FILENAME
= "statistics.ht"; //$NON-NLS-1$
57 private final ITmfTrace trace
;
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!)
64 private final ITmfStateSystem stats
;
67 * Empty constructor. The resulting TmfStatistics object will not be usable,
68 * but it might be needed for sub-classes.
70 public TmfStateStatistics() {
79 * The trace for which we build these statistics
80 * @throws TmfTraceException
81 * If something went wrong trying to initialize the statistics
83 public TmfStateStatistics(ITmfTrace trace
) throws TmfTraceException
{
84 /* Set up the path to the history tree file we'll use */
86 IResource resource
= trace
.getResource();
87 String supplDirectory
= null;
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
);
96 final File htFile
= new File(supplDirectory
+ File
.separator
+ STATS_STATE_FILENAME
);
97 final IStateChangeInput htInput
= new StatsStateProvider(trace
);
99 this.stats
= StateSystemManager
.loadStateHistory(htFile
, htInput
, STATE_ID
, false);
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
108 * The trace for which we build these statistics
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
114 public TmfStateStatistics(ITmfTrace trace
, File historyFile
) throws TmfTraceException
{
116 final IStateChangeInput htInput
= new StatsStateProvider(trace
);
117 this.stats
= StateSystemManager
.loadStateHistory(historyFile
, htInput
, STATE_ID
, true);
120 // ------------------------------------------------------------------------
122 // ------------------------------------------------------------------------
125 public void dispose() {
130 public void updateStats(final boolean isGlobal
, final long start
,
133 * Since we are currently in a signal handler (ie, in the UI thread),
134 * and since state system queries can be arbitrarily long (O(log n) wrt
135 * the size of the trace), we will run those queries in a separate
136 * thread and update the statistics view out-of-band.
138 Thread statsThread
= new Thread("Statistics update") { //$NON-NLS-1$
142 Map
<String
, Long
> map
;
144 /* Wait until the history building completed */
145 if (!stats
.waitUntilBuilt()) {
149 /* Range should be valid for both global and time range queries */
150 total
= getEventsInRange(start
, end
);
151 map
= getEventTypesInRange(start
, end
);
153 /* Send the signal to notify the stats viewer to update its display */
154 TmfSignal sig
= new TmfStatsUpdatedSignal(this, trace
, isGlobal
, total
, map
);
155 TmfSignalManager
.dispatchSignal(sig
);
164 public long getEventsTotal() {
165 /* We need the complete state history to be built to answer this. */
166 stats
.waitUntilBuilt();
168 long endTime
= stats
.getCurrentEndTime();
172 final int quark
= stats
.getQuarkAbsolute(Attributes
.TOTAL
);
173 count
= stats
.querySingleState(endTime
, quark
).getStateValue().unboxInt();
175 } catch (TimeRangeException e
) {
176 /* Assume there is no events for that range */
178 } catch (AttributeNotFoundException e
) {
180 } catch (StateValueTypeException e
) {
182 } catch (StateSystemDisposedException e
) {
190 public Map
<String
, Long
> getEventTypesTotal() {
191 /* We need the complete state history to be built to answer this. */
192 stats
.waitUntilBuilt();
194 Map
<String
, Long
> map
= new HashMap
<String
, Long
>();
195 long endTime
= stats
.getCurrentEndTime();
198 /* Get the list of quarks, one for each even type in the database */
199 int quark
= stats
.getQuarkAbsolute(Attributes
.EVENT_TYPES
);
200 List
<Integer
> quarks
= stats
.getSubAttributes(quark
, false);
202 /* Since we want the total we can look only at the end */
203 List
<ITmfStateInterval
> endState
= stats
.queryFullState(endTime
);
207 for (int typeQuark
: quarks
) {
208 curEventName
= stats
.getAttributeName(typeQuark
);
209 eventCount
= endState
.get(typeQuark
).getStateValue().unboxInt();
210 map
.put(curEventName
, eventCount
);
213 } catch (TimeRangeException e
) {
214 /* Assume there is no events, nothing will be put in the map. */
215 } catch (AttributeNotFoundException e
) {
217 } catch (StateValueTypeException e
) {
219 } catch (StateSystemDisposedException e
) {
226 public long getEventsInRange(long start
, long end
) {
227 // FIXME Instead of waiting until the end, we could check the current
228 // end time, and answer as soon as possible...
229 stats
.waitUntilBuilt();
231 int countAtStart
= 0, countAtEnd
= 0;
232 long startTime
= checkStartTime(start
);
233 long endTime
= checkEndTime(end
);
236 final int quark
= stats
.getQuarkAbsolute(Attributes
.TOTAL
);
237 if (startTime
== stats
.getStartTime()) {
240 /* State system works that way... */
241 countAtStart
= stats
.querySingleState(startTime
- 1, quark
).getStateValue().unboxInt();
243 countAtEnd
= stats
.querySingleState(endTime
, quark
).getStateValue().unboxInt();
245 } catch (TimeRangeException e
) {
246 /* Assume there is no events for that range */
248 } catch (AttributeNotFoundException e
) {
250 } catch (StateValueTypeException e
) {
252 } catch (StateSystemDisposedException e
) {
256 long total
= countAtEnd
- countAtStart
;
261 public Map
<String
, Long
> getEventTypesInRange(long start
, long end
) {
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();
266 Map
<String
, Long
> map
= new HashMap
<String
, Long
>();
268 /* Make sure the start/end times are within the state history, so we
269 * don't get TimeRange exceptions.
271 long startTime
= checkStartTime(start
);
272 long endTime
= checkEndTime(end
);
275 /* Get the list of quarks, one for each even type in the database */
276 int quark
= stats
.getQuarkAbsolute(Attributes
.EVENT_TYPES
);
277 List
<Integer
> quarks
= stats
.getSubAttributes(quark
, false);
279 List
<ITmfStateInterval
> endState
= stats
.queryFullState(endTime
);
282 long countAtStart
, countAtEnd
, eventCount
;
284 if (startTime
== stats
.getStartTime()) {
285 /* Only use the values picked up at the end time */
286 for (int typeQuark
: quarks
) {
287 curEventName
= stats
.getAttributeName(typeQuark
);
288 eventCount
= endState
.get(typeQuark
).getStateValue().unboxInt();
289 if (eventCount
== -1) {
292 map
.put(curEventName
, eventCount
);
296 * Query the start time at -1, so the beginning of the interval
299 List
<ITmfStateInterval
> startState
= stats
.queryFullState(startTime
- 1);
300 for (int typeQuark
: quarks
) {
301 curEventName
= stats
.getAttributeName(typeQuark
);
302 countAtStart
= startState
.get(typeQuark
).getStateValue().unboxInt();
303 countAtEnd
= endState
.get(typeQuark
).getStateValue().unboxInt();
305 if (countAtStart
== -1) {
308 if (countAtEnd
== -1) {
311 eventCount
= countAtEnd
- countAtStart
;
312 map
.put(curEventName
, eventCount
);
316 } catch (TimeRangeException e
) {
317 /* Assume there is no events, nothing will be put in the map. */
318 } catch (AttributeNotFoundException e
) {
320 * These other exception types would show a logic problem however,
321 * so they should not happen.
324 } catch (StateValueTypeException e
) {
326 } catch (StateSystemDisposedException e
) {
332 private long checkStartTime(long initialStart
) {
333 long start
= initialStart
;
334 if (start
< stats
.getStartTime()) {
335 return stats
.getStartTime();
340 private long checkEndTime(long initialEnd
) {
341 long end
= initialEnd
;
342 if (end
> stats
.getCurrentEndTime()) {
343 return stats
.getCurrentEndTime();
350 * The attribute names that are used in the state provider
352 public static class Attributes
{
354 /** Total nb of events */
355 public static final String TOTAL
= "total"; //$NON-NLS-1$
358 public static final String EVENT_TYPES
= "event_types"; //$NON-NLS-1$<