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
.Collection
;
16 import java
.util
.HashMap
;
17 import java
.util
.LinkedList
;
18 import java
.util
.List
;
20 import java
.util
.TreeMap
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfLostEvent
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfDataRequest
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfEventRequest
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalManager
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfStatsUpdatedSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
36 * Implementation of ITmfStatistics which uses event requests to the trace to
37 * retrieve its information.
39 * There is almost no setup time, but queries themselves are longer than with a
40 * TmfStateStatistics. Queries are O(n * m), where n is the size of the trace,
41 * and m is the portion of the trace covered by the selected interval.
43 * @author Alexandre Montplaisir
46 public class TmfEventsStatistics
implements ITmfStatistics
{
48 /* All timestamps should be stored in nanoseconds in the statistics backend */
49 private static final int SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
51 private final ITmfTrace trace
;
53 /* Event request objects for the time-range request. */
54 private StatsTotalRequest totalRequest
= null;
55 private StatsPerTypeRequest perTypeRequest
= null;
61 * The trace for which we are building the statistics
63 public TmfEventsStatistics(ITmfTrace trace
) {
68 public void dispose() {
69 cancelOngoingRequests();
73 public void updateStats(final boolean isGlobal
, long start
, long end
) {
74 cancelOngoingRequests();
77 * Prepare and send the event requests. This needs to be done in the
78 * same thread, since it will be run by TmfStatisticsViewer's signal
79 * handlers, to ensure they get correctly coalesced.
81 ITmfTimestamp startTS
= new TmfTimestamp(start
, SCALE
);
82 ITmfTimestamp endTS
= new TmfTimestamp(end
, SCALE
);
83 TmfTimeRange range
= isGlobal ? TmfTimeRange
.ETERNITY
: new TmfTimeRange(startTS
, endTS
);
84 final StatsTotalRequest totalReq
= new StatsTotalRequest(trace
, range
);
85 final StatsPerTypeRequest perTypeReq
= new StatsPerTypeRequest(trace
, range
);
88 * Only allow one time-range request at a time (there should be only one
89 * global request at the beginning anyway, no need to track those).
92 this.totalRequest
= totalReq
;
93 this.perTypeRequest
= perTypeReq
;
96 trace
.sendRequest(totalReq
);
97 trace
.sendRequest(perTypeReq
);
100 * This thread can now return. Start a new thread that will wait until
101 * the request are done and will then send the results.
103 Thread statsThread
= new Thread("Statistics update") { //$NON-NLS-1$
106 /* Wait for both requests to complete */
108 totalReq
.waitForCompletion();
109 perTypeReq
.waitForCompletion();
110 } catch (InterruptedException e
) {
115 * If the request was cancelled, this means a newer one was
116 * sent, discard the current one and return without sending
119 if (totalReq
.isCancelled() || perTypeReq
.isCancelled()) {
123 /* If it completed successfully, retrieve the results. */
124 long total
= totalReq
.getResult();
125 Map
<String
, Long
> map
= perTypeReq
.getResults();
127 /* Send the signal to notify the stats viewer to update its display. */
128 TmfSignal sig
= new TmfStatsUpdatedSignal(this, trace
, isGlobal
, total
, map
);
129 TmfSignalManager
.dispatchSignal(sig
);
137 public List
<Long
> histogramQuery(long start
, long end
, int nb
) {
138 final long[] borders
= new long[nb
];
139 final long increment
= (end
- start
) / nb
;
141 long curTime
= start
;
142 for (int i
= 0; i
< nb
; i
++) {
143 borders
[i
] = curTime
;
144 curTime
+= increment
;
147 HistogramQueryRequest req
= new HistogramQueryRequest(borders
, end
);
150 List
<Long
> results
= new LinkedList
<Long
>(req
.getResults());
155 private synchronized void cancelOngoingRequests() {
156 if (totalRequest
!= null && totalRequest
.isRunning()) {
157 totalRequest
.cancel();
159 if (perTypeRequest
!= null && perTypeRequest
.isRunning()) {
160 perTypeRequest
.cancel();
165 public long getEventsTotal() {
166 StatsTotalRequest request
= new StatsTotalRequest(trace
, TmfTimeRange
.ETERNITY
);
167 sendAndWait(request
);
169 long total
= request
.getResult();
174 public Map
<String
, Long
> getEventTypesTotal() {
175 StatsPerTypeRequest request
= new StatsPerTypeRequest(trace
, TmfTimeRange
.ETERNITY
);
176 sendAndWait(request
);
178 Map
<String
, Long
> stats
= request
.getResults();
183 public long getEventsInRange(long start
, long end
) {
184 ITmfTimestamp startTS
= new TmfTimestamp(start
, SCALE
);
185 ITmfTimestamp endTS
= new TmfTimestamp(end
, SCALE
);
186 TmfTimeRange range
= new TmfTimeRange(startTS
, endTS
);
188 StatsTotalRequest request
= new StatsTotalRequest(trace
, range
);
189 sendAndWait(request
);
191 long total
= request
.getResult();
196 public Map
<String
, Long
> getEventTypesInRange(long start
, long end
) {
197 ITmfTimestamp startTS
= new TmfTimestamp(start
, SCALE
);
198 ITmfTimestamp endTS
= new TmfTimestamp(end
, SCALE
);
199 TmfTimeRange range
= new TmfTimeRange(startTS
, endTS
);
201 StatsPerTypeRequest request
= new StatsPerTypeRequest(trace
, range
);
202 sendAndWait(request
);
204 Map
<String
, Long
> stats
= request
.getResults();
208 private void sendAndWait(TmfEventRequest request
) {
209 trace
.sendRequest(request
);
211 request
.waitForCompletion();
212 } catch (InterruptedException e
) {
219 * Event request to get the total number of events
221 private class StatsTotalRequest
extends TmfEventRequest
{
223 /* Total number of events the request has found */
226 public StatsTotalRequest(ITmfTrace trace
, TmfTimeRange range
) {
227 super(trace
.getEventType(), range
, 0, TmfDataRequest
.ALL_DATA
,
228 ITmfDataRequest
.ExecutionType
.BACKGROUND
);
232 public long getResult() {
237 public void handleData(final ITmfEvent event
) {
238 super.handleData(event
);
239 if (!(event
instanceof ITmfLostEvent
) && event
.getTrace() == trace
) {
247 * Event request to get the counts per event type
249 private class StatsPerTypeRequest
extends TmfEventRequest
{
251 /* Map in which the results are saved */
252 private final Map
<String
, Long
> stats
;
254 public StatsPerTypeRequest(ITmfTrace trace
, TmfTimeRange range
) {
255 super(trace
.getEventType(), range
, 0, TmfDataRequest
.ALL_DATA
,
256 ITmfDataRequest
.ExecutionType
.BACKGROUND
);
257 this.stats
= new HashMap
<String
, Long
>();
260 public Map
<String
, Long
> getResults() {
265 public void handleData(final ITmfEvent event
) {
266 super.handleData(event
);
267 if (event
!= null && event
.getTrace() == trace
) {
269 * Special handling for lost events: instead of counting just
270 * one, we will count how many actual events it represents.
272 if (event
instanceof ITmfLostEvent
) {
273 ITmfLostEvent le
= (ITmfLostEvent
) event
;
274 incrementStats(Messages
.LostEventsName
, le
.getNbLostEvents());
278 /* For standard event types, just increment by one */
279 String eventType
= event
.getType().getName();
280 incrementStats(eventType
, 1L);
284 private void incrementStats(String key
, long count
) {
285 if (stats
.containsKey(key
)) {
286 long curValue
= stats
.get(key
);
287 stats
.put(key
, curValue
+ count
);
289 stats
.put(key
, count
);
295 * Event request for histogram queries. It is much faster to do one event
296 * request then set the results accordingly than doing thousands of them one
299 private class HistogramQueryRequest
extends TmfEventRequest
{
301 /** Map of <borders, number of events> */
302 private final TreeMap
<Long
, Long
> results
;
305 * New histogram request
308 * The array of borders (not including the end time). The
309 * first element should be the start time of the queries.
311 * The end time of the query. Not used in the results map,
312 * but we need to know when to stop the event request.
314 public HistogramQueryRequest(long[] borders
, long endTime
) {
315 super(trace
.getEventType(),
317 new TmfTimestamp(borders
[0], SCALE
),
318 new TmfTimestamp(endTime
, SCALE
)),
320 TmfDataRequest
.ALL_DATA
,
321 ITmfDataRequest
.ExecutionType
.BACKGROUND
);
323 /* Prepare the results map, with all counts at 0 */
324 results
= new TreeMap
<Long
, Long
>();
325 for (long border
: borders
) {
326 results
.put(border
, 0L);
330 public Collection
<Long
> getResults() {
331 return results
.values();
335 public void handleData(ITmfEvent event
) {
336 super.handleData(event
);
337 if ((event
!= null) && (event
.getTrace() == trace
)) {
338 long ts
= event
.getTimestamp().normalize(0, SCALE
).getValue();
339 Long key
= results
.floorKey(ts
);
346 private void incrementValue(Long key
) {
347 long value
= results
.get(key
);
349 results
.put(key
, value
);