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 ******************************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.core
.statistics
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.util
.Collection
;
18 import java
.util
.HashMap
;
19 import java
.util
.LinkedList
;
20 import java
.util
.List
;
22 import java
.util
.TreeMap
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
26 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfLostEvent
;
27 import org
.eclipse
.tracecompass
.tmf
.core
.request
.ITmfEventRequest
;
28 import org
.eclipse
.tracecompass
.tmf
.core
.request
.TmfEventRequest
;
29 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
30 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
31 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
32 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
35 * Implementation of ITmfStatistics which uses event requests to the trace to
36 * retrieve its information.
38 * There is almost no setup time, but queries themselves are longer than with a
39 * TmfStateStatistics. Queries are O(n * m), where n is the size of the trace,
40 * and m is the portion of the trace covered by the selected interval.
42 * @author Alexandre Montplaisir
44 public class TmfEventsStatistics
implements ITmfStatistics
{
46 /* All timestamps should be stored in nanoseconds in the statistics backend */
47 private static final int SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
49 private final ITmfTrace trace
;
51 /* Event request objects for the time-range request. */
52 private StatsTotalRequest totalRequest
= null;
53 private StatsPerTypeRequest perTypeRequest
= null;
59 * The trace for which we are building the statistics
61 public TmfEventsStatistics(ITmfTrace trace
) {
66 public void dispose() {
67 cancelOngoingRequests();
71 public List
<Long
> histogramQuery(long start
, long end
, int nb
) {
72 final long[] borders
= new long[nb
];
73 final long increment
= (end
- start
) / nb
;
76 for (int i
= 0; i
< nb
; i
++) {
81 HistogramQueryRequest req
= new HistogramQueryRequest(borders
, end
);
84 List
<Long
> results
= new LinkedList
<>(req
.getResults());
89 private synchronized void cancelOngoingRequests() {
90 if (totalRequest
!= null && totalRequest
.isRunning()) {
91 totalRequest
.cancel();
93 if (perTypeRequest
!= null && perTypeRequest
.isRunning()) {
94 perTypeRequest
.cancel();
99 public long getEventsTotal() {
100 StatsTotalRequest request
= new StatsTotalRequest(trace
, TmfTimeRange
.ETERNITY
);
101 sendAndWait(request
);
103 long total
= request
.getResult();
108 public Map
<@NonNull String
, @NonNull Long
> getEventTypesTotal() {
109 StatsPerTypeRequest request
= new StatsPerTypeRequest(trace
, TmfTimeRange
.ETERNITY
);
110 sendAndWait(request
);
112 return request
.getResults();
116 public long getEventsInRange(long start
, long end
) {
117 ITmfTimestamp startTS
= new TmfTimestamp(start
, SCALE
);
118 ITmfTimestamp endTS
= new TmfTimestamp(end
, SCALE
);
119 TmfTimeRange range
= new TmfTimeRange(startTS
, endTS
);
121 StatsTotalRequest request
= new StatsTotalRequest(trace
, range
);
122 sendAndWait(request
);
124 long total
= request
.getResult();
129 public Map
<String
, Long
> getEventTypesInRange(long start
, long end
) {
130 ITmfTimestamp startTS
= new TmfTimestamp(start
, SCALE
);
131 ITmfTimestamp endTS
= new TmfTimestamp(end
, SCALE
);
132 TmfTimeRange range
= new TmfTimeRange(startTS
, endTS
);
134 StatsPerTypeRequest request
= new StatsPerTypeRequest(trace
, range
);
135 sendAndWait(request
);
137 Map
<String
, Long
> stats
= request
.getResults();
141 private void sendAndWait(TmfEventRequest request
) {
142 trace
.sendRequest(request
);
144 request
.waitForCompletion();
145 } catch (InterruptedException e
) {
152 * Event request to get the total number of events
154 private class StatsTotalRequest
extends TmfEventRequest
{
156 /* Total number of events the request has found */
159 public StatsTotalRequest(ITmfTrace trace
, TmfTimeRange range
) {
160 super(trace
.getEventType(), range
, 0, ITmfEventRequest
.ALL_DATA
,
161 ITmfEventRequest
.ExecutionType
.BACKGROUND
);
165 public long getResult() {
170 public void handleData(final ITmfEvent event
) {
171 super.handleData(event
);
172 if (!(event
instanceof ITmfLostEvent
) && event
.getTrace() == trace
) {
180 * Event request to get the counts per event type
182 private class StatsPerTypeRequest
extends TmfEventRequest
{
184 /* Map in which the results are saved */
185 private final Map
<@NonNull String
, @NonNull Long
> stats
;
187 public StatsPerTypeRequest(ITmfTrace trace
, TmfTimeRange range
) {
188 super(trace
.getEventType(), range
, 0, ITmfEventRequest
.ALL_DATA
,
189 ITmfEventRequest
.ExecutionType
.BACKGROUND
);
190 this.stats
= new HashMap
<>();
193 public Map
<@NonNull String
, @NonNull Long
> getResults() {
198 public void handleData(final ITmfEvent event
) {
199 super.handleData(event
);
200 if (event
.getTrace() == trace
) {
201 String eventType
= event
.getName();
203 * Special handling for lost events: instead of counting just
204 * one, we will count how many actual events it represents.
206 if (event
instanceof ITmfLostEvent
) {
207 ITmfLostEvent le
= (ITmfLostEvent
) event
;
208 incrementStats(eventType
, le
.getNbLostEvents());
212 /* For standard event types, just increment by one */
213 incrementStats(eventType
, 1L);
217 private void incrementStats(@NonNull String key
, long count
) {
218 if (stats
.containsKey(key
)) {
219 long curValue
= checkNotNull(stats
.get(key
));
220 stats
.put(key
, curValue
+ count
);
222 stats
.put(key
, count
);
228 * Event request for histogram queries. It is much faster to do one event
229 * request then set the results accordingly than doing thousands of them one
232 private class HistogramQueryRequest
extends TmfEventRequest
{
234 /** Map of <borders, number of events> */
235 private final TreeMap
<Long
, Long
> results
;
238 * New histogram request
241 * The array of borders (not including the end time). The
242 * first element should be the start time of the queries.
244 * The end time of the query. Not used in the results map,
245 * but we need to know when to stop the event request.
247 public HistogramQueryRequest(long[] borders
, long endTime
) {
248 super(trace
.getEventType(),
250 new TmfTimestamp(borders
[0], SCALE
),
251 new TmfTimestamp(endTime
, SCALE
)),
253 ITmfEventRequest
.ALL_DATA
,
254 ITmfEventRequest
.ExecutionType
.BACKGROUND
);
256 /* Prepare the results map, with all counts at 0 */
257 results
= new TreeMap
<>();
258 for (long border
: borders
) {
259 results
.put(border
, 0L);
263 public Collection
<Long
> getResults() {
264 return results
.values();
268 public void handleData(ITmfEvent event
) {
269 super.handleData(event
);
270 if (event
.getTrace() == trace
) {
271 long ts
= event
.getTimestamp().toNanos();
272 Long key
= results
.floorKey(ts
);
279 private void incrementValue(Long key
) {
280 long value
= checkNotNull(results
.get(key
));
282 results
.put(key
, value
);