1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 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 * Patrick Tasse - Fix TimeRangeException
12 ******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.core
.statistics
;
16 import java
.util
.HashMap
;
17 import java
.util
.LinkedList
;
18 import java
.util
.List
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
30 * Implementation of ITmfStatistics which uses a state history for storing its
31 * information. In reality, it uses two state histories, one for "event totals"
32 * information (which should ideally use a fast backend), and another one for
33 * the rest (per event type, per CPU, etc.).
35 * Compared to the event-request-based statistics calculations, it adds the
36 * building the history first, but gives much faster response times once built :
37 * Queries are O(log n) wrt the size of the trace, and O(1) wrt to the size of
38 * the time interval selected.
40 * @author Alexandre Montplaisir
43 public class TmfStateStatistics
implements ITmfStatistics
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
49 /** The event totals state system */
50 private final ITmfStateSystem totalsStats
;
52 /** The state system for event types */
53 private final ITmfStateSystem typesStats
;
55 // ------------------------------------------------------------------------
57 // ------------------------------------------------------------------------
63 * The state system containing the "totals" information
65 * The state system containing the "event types" information
68 public TmfStateStatistics(@NonNull ITmfStateSystem totals
, @NonNull ITmfStateSystem eventTypes
) {
69 this.totalsStats
= totals
;
70 this.typesStats
= eventTypes
;
74 * Return the state system containing the "totals" values
76 * @return The "totals" state system
79 public ITmfStateSystem
getTotalsSS() {
84 * Return the state system containing the "event types" values
86 * @return The "event types" state system
89 public ITmfStateSystem
getEventTypesSS() {
93 // ------------------------------------------------------------------------
95 // ------------------------------------------------------------------------
98 public void dispose() {
99 totalsStats
.dispose();
100 typesStats
.dispose();
104 public List
<Long
> histogramQuery(final long start
, final long end
, final int nb
) {
105 final List
<Long
> list
= new LinkedList
<>();
106 final long increment
= (end
- start
) / nb
;
108 if (totalsStats
.isCancelled()) {
113 * We will do one state system query per "border", and save the
114 * differences between each border.
116 long prevTotal
= (start
== totalsStats
.getStartTime()) ?
0 : getEventCountAt(start
);
117 long curTime
= start
+ increment
;
119 long curTotal
, count
;
120 for (int i
= 0; i
< nb
- 1; i
++) {
121 curTotal
= getEventCountAt(curTime
);
122 count
= curTotal
- prevTotal
;
125 curTime
+= increment
;
126 prevTotal
= curTotal
;
130 * For the last bucket, we'll stretch its end time to the end time of
131 * the requested range, in case it got truncated down.
133 curTotal
= getEventCountAt(end
);
134 count
= curTotal
- prevTotal
;
141 public long getEventsTotal() {
142 long endTime
= totalsStats
.getCurrentEndTime();
146 final int quark
= totalsStats
.getQuarkAbsolute(Attributes
.TOTAL
);
147 count
= totalsStats
.querySingleState(endTime
, quark
).getStateValue().unboxInt();
149 } catch (TimeRangeException e
) {
150 /* Assume there is no events for that range */
152 } catch (AttributeNotFoundException
| StateValueTypeException
| StateSystemDisposedException e
) {
160 public Map
<String
, Long
> getEventTypesTotal() {
161 final Map
<String
, Long
> map
= new HashMap
<>();
162 long endTime
= typesStats
.getCurrentEndTime();
165 /* Get the list of quarks, one for each even type in the database */
166 int quark
= typesStats
.getQuarkAbsolute(Attributes
.EVENT_TYPES
);
167 List
<Integer
> quarks
= typesStats
.getSubAttributes(quark
, false);
169 /* Since we want the total we can look only at the end */
170 List
<ITmfStateInterval
> endState
= typesStats
.queryFullState(endTime
);
174 for (int typeQuark
: quarks
) {
175 curEventName
= typesStats
.getAttributeName(typeQuark
);
176 eventCount
= endState
.get(typeQuark
).getStateValue().unboxInt();
177 map
.put(curEventName
, eventCount
);
180 } catch (TimeRangeException e
) {
181 /* Assume there is no events, nothing will be put in the map. */
182 } catch (AttributeNotFoundException
| StateValueTypeException
| StateSystemDisposedException e
) {
189 public long getEventsInRange(long start
, long end
) {
191 if (start
== totalsStats
.getStartTime()) {
195 * We want the events happening at "start" to be included, so we'll
196 * need to query one unit before that point.
198 startCount
= getEventCountAt(start
- 1);
200 long endCount
= getEventCountAt(end
);
202 return endCount
- startCount
;
206 public Map
<String
, Long
> getEventTypesInRange(long start
, long end
) {
207 final Map
<String
, Long
> map
= new HashMap
<>();
208 List
<Integer
> quarks
;
210 /* Make sure the start/end times are within the state history, so we
211 * don't get TimeRange exceptions.
213 long startTime
= checkStartTime(start
, typesStats
);
214 long endTime
= checkEndTime(end
, typesStats
);
217 /* Get the list of quarks, one for each even type in the database */
218 int quark
= typesStats
.getQuarkAbsolute(Attributes
.EVENT_TYPES
);
219 quarks
= typesStats
.getSubAttributes(quark
, false);
220 } catch (AttributeNotFoundException e
) {
222 * The state system does not (yet?) have the needed attributes, it
223 * probably means there are no events counted yet. Return the empty
230 List
<ITmfStateInterval
> endState
= typesStats
.queryFullState(endTime
);
232 if (startTime
== typesStats
.getStartTime()) {
233 /* Only use the values picked up at the end time */
234 for (int typeQuark
: quarks
) {
235 String curEventName
= typesStats
.getAttributeName(typeQuark
);
236 long eventCount
= endState
.get(typeQuark
).getStateValue().unboxInt();
237 if (eventCount
== -1) {
240 map
.put(curEventName
, eventCount
);
244 * Query the start time at -1, so the beginning of the interval
247 List
<ITmfStateInterval
> startState
= typesStats
.queryFullState(startTime
- 1);
248 for (int typeQuark
: quarks
) {
249 String curEventName
= typesStats
.getAttributeName(typeQuark
);
250 long countAtStart
= startState
.get(typeQuark
).getStateValue().unboxInt();
251 long countAtEnd
= endState
.get(typeQuark
).getStateValue().unboxInt();
253 if (countAtStart
== -1) {
256 if (countAtEnd
== -1) {
259 long eventCount
= countAtEnd
- countAtStart
;
260 map
.put(curEventName
, eventCount
);
264 } catch (TimeRangeException
| StateSystemDisposedException e
) {
265 /* Assume there is no (more) events, nothing will be put in the map. */
266 } catch (StateValueTypeException e
) {
268 * This exception type would show a logic problem however,
269 * so they should not happen.
271 throw new IllegalStateException();
276 // ------------------------------------------------------------------------
278 // ------------------------------------------------------------------------
280 private long getEventCountAt(long timestamp
) {
281 /* Make sure the target time is within the range of the history */
282 long ts
= checkStartTime(timestamp
, totalsStats
);
283 ts
= checkEndTime(ts
, totalsStats
);
286 final int quark
= totalsStats
.getQuarkAbsolute(Attributes
.TOTAL
);
287 long count
= totalsStats
.querySingleState(ts
, quark
).getStateValue().unboxInt();
290 } catch (TimeRangeException e
) {
291 /* Assume there is no events for that range */
292 } catch (AttributeNotFoundException
| StateValueTypeException
| StateSystemDisposedException e
) {
299 private static long checkStartTime(long initialStart
, ITmfStateSystem ss
) {
300 long start
= initialStart
;
301 if (start
< ss
.getStartTime()) {
302 return ss
.getStartTime();
307 private static long checkEndTime(long initialEnd
, ITmfStateSystem ss
) {
308 long end
= initialEnd
;
309 if (end
> ss
.getCurrentEndTime()) {
310 return ss
.getCurrentEndTime();
316 * The attribute names that are used in the state provider
318 public static class Attributes
{
320 /** Total nb of events */
321 public static final String TOTAL
= "total"; //$NON-NLS-1$
324 public static final String EVENT_TYPES
= "event_types"; //$NON-NLS-1$<