1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 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
;
15 import java
.util
.HashMap
;
16 import java
.util
.LinkedList
;
17 import java
.util
.List
;
20 import org
.eclipse
.jdt
.annotation
.NonNull
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
29 * Implementation of ITmfStatistics which uses a state history for storing its
30 * information. In reality, it uses two state histories, one for "event totals"
31 * information (which should ideally use a fast backend), and another one for
32 * the rest (per event type, per CPU, etc.).
34 * Compared to the event-request-based statistics calculations, it adds the
35 * building the history first, but gives much faster response times once built :
36 * Queries are O(log n) wrt the size of the trace, and O(1) wrt to the size of
37 * the time interval selected.
39 * @author Alexandre Montplaisir
42 public class TmfStateStatistics
implements ITmfStatistics
{
44 // ------------------------------------------------------------------------
46 // ------------------------------------------------------------------------
48 /** The event totals state system */
49 private final ITmfStateSystem totalsStats
;
51 /** The state system for event types */
52 private final ITmfStateSystem typesStats
;
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
62 * The state system containing the "totals" information
64 * The state system containing the "event types" information
67 public TmfStateStatistics(@NonNull ITmfStateSystem totals
, @NonNull ITmfStateSystem eventTypes
) {
68 this.totalsStats
= totals
;
69 this.typesStats
= eventTypes
;
73 * Return the state system containing the "totals" values
75 * @return The "totals" state system
78 public ITmfStateSystem
getTotalsSS() {
83 * Return the state system containing the "event types" values
85 * @return The "event types" state system
88 public ITmfStateSystem
getEventTypesSS() {
92 // ------------------------------------------------------------------------
94 // ------------------------------------------------------------------------
97 public void dispose() {
98 totalsStats
.dispose();
103 public List
<Long
> histogramQuery(final long start
, final long end
, final int nb
) {
104 final List
<Long
> list
= new LinkedList
<>();
105 final long increment
= (end
- start
) / nb
;
107 if (totalsStats
.isCancelled()) {
112 * We will do one state system query per "border", and save the
113 * differences between each border.
115 long prevTotal
= (start
== totalsStats
.getStartTime()) ?
0 : getEventCountAt(start
);
116 long curTime
= start
+ increment
;
118 long curTotal
, count
;
119 for (int i
= 0; i
< nb
- 1; i
++) {
120 curTotal
= getEventCountAt(curTime
);
121 count
= curTotal
- prevTotal
;
124 curTime
+= increment
;
125 prevTotal
= curTotal
;
129 * For the last bucket, we'll stretch its end time to the end time of
130 * the requested range, in case it got truncated down.
132 curTotal
= getEventCountAt(end
);
133 count
= curTotal
- prevTotal
;
140 public long getEventsTotal() {
141 long endTime
= totalsStats
.getCurrentEndTime();
145 final int quark
= totalsStats
.getQuarkAbsolute(Attributes
.TOTAL
);
146 count
= totalsStats
.querySingleState(endTime
, quark
).getStateValue().unboxInt();
148 } catch (TimeRangeException e
) {
149 /* Assume there is no events for that range */
151 } catch (AttributeNotFoundException
| StateValueTypeException
| StateSystemDisposedException e
) {
159 public Map
<String
, Long
> getEventTypesTotal() {
160 final Map
<String
, Long
> map
= new HashMap
<>();
161 long endTime
= typesStats
.getCurrentEndTime();
164 /* Get the list of quarks, one for each even type in the database */
165 int quark
= typesStats
.getQuarkAbsolute(Attributes
.EVENT_TYPES
);
166 List
<Integer
> quarks
= typesStats
.getSubAttributes(quark
, false);
168 /* Since we want the total we can look only at the end */
169 List
<ITmfStateInterval
> endState
= typesStats
.queryFullState(endTime
);
173 for (int typeQuark
: quarks
) {
174 curEventName
= typesStats
.getAttributeName(typeQuark
);
175 eventCount
= endState
.get(typeQuark
).getStateValue().unboxInt();
176 map
.put(curEventName
, eventCount
);
179 } catch (TimeRangeException e
) {
180 /* Assume there is no events, nothing will be put in the map. */
181 } catch (AttributeNotFoundException
| StateValueTypeException
| StateSystemDisposedException e
) {
188 public long getEventsInRange(long start
, long end
) {
190 if (start
== totalsStats
.getStartTime()) {
194 * We want the events happening at "start" to be included, so we'll
195 * need to query one unit before that point.
197 startCount
= getEventCountAt(start
- 1);
199 long endCount
= getEventCountAt(end
);
201 return endCount
- startCount
;
205 public Map
<String
, Long
> getEventTypesInRange(long start
, long end
) {
206 final Map
<String
, Long
> map
= new HashMap
<>();
207 List
<Integer
> quarks
;
209 /* Make sure the start/end times are within the state history, so we
210 * don't get TimeRange exceptions.
212 long startTime
= checkStartTime(start
);
213 long endTime
= checkEndTime(end
);
216 /* Get the list of quarks, one for each even type in the database */
217 int quark
= typesStats
.getQuarkAbsolute(Attributes
.EVENT_TYPES
);
218 quarks
= typesStats
.getSubAttributes(quark
, false);
219 } catch (AttributeNotFoundException e
) {
221 * The state system does not (yet?) have the needed attributes, it
222 * probably means there are no events counted yet. Return the empty
229 List
<ITmfStateInterval
> endState
= typesStats
.queryFullState(endTime
);
231 if (startTime
== typesStats
.getStartTime()) {
232 /* Only use the values picked up at the end time */
233 for (int typeQuark
: quarks
) {
234 String curEventName
= typesStats
.getAttributeName(typeQuark
);
235 long eventCount
= endState
.get(typeQuark
).getStateValue().unboxInt();
236 if (eventCount
== -1) {
239 map
.put(curEventName
, eventCount
);
243 * Query the start time at -1, so the beginning of the interval
246 List
<ITmfStateInterval
> startState
= typesStats
.queryFullState(startTime
- 1);
247 for (int typeQuark
: quarks
) {
248 String curEventName
= typesStats
.getAttributeName(typeQuark
);
249 long countAtStart
= startState
.get(typeQuark
).getStateValue().unboxInt();
250 long countAtEnd
= endState
.get(typeQuark
).getStateValue().unboxInt();
252 if (countAtStart
== -1) {
255 if (countAtEnd
== -1) {
258 long eventCount
= countAtEnd
- countAtStart
;
259 map
.put(curEventName
, eventCount
);
263 } catch (TimeRangeException
| StateSystemDisposedException e
) {
264 /* Assume there is no (more) events, nothing will be put in the map. */
265 } catch (StateValueTypeException e
) {
267 * This exception type would show a logic problem however,
268 * so they should not happen.
270 throw new IllegalStateException();
275 // ------------------------------------------------------------------------
277 // ------------------------------------------------------------------------
279 private long getEventCountAt(long timestamp
) {
280 /* Make sure the target time is within the range of the history */
281 long ts
= checkStartTime(timestamp
);
282 ts
= checkEndTime(ts
);
285 final int quark
= totalsStats
.getQuarkAbsolute(Attributes
.TOTAL
);
286 long count
= totalsStats
.querySingleState(ts
, quark
).getStateValue().unboxInt();
289 } catch (TimeRangeException e
) {
290 /* Assume there is no events for that range */
291 } catch (AttributeNotFoundException
| StateValueTypeException
| StateSystemDisposedException e
) {
298 private long checkStartTime(long initialStart
) {
299 long start
= initialStart
;
300 if (start
< totalsStats
.getStartTime()) {
301 return totalsStats
.getStartTime();
306 private long checkEndTime(long initialEnd
) {
307 long end
= initialEnd
;
308 if (end
> totalsStats
.getCurrentEndTime()) {
309 return totalsStats
.getCurrentEndTime();
315 * The attribute names that are used in the state provider
317 public static class Attributes
{
319 /** Total nb of events */
320 public static final String TOTAL
= "total"; //$NON-NLS-1$
323 public static final String EVENT_TYPES
= "event_types"; //$NON-NLS-1$<