Merge branch 'master' into lttng-luna
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / statistics / TmfEventsStatistics.java
CommitLineData
1c0de632 1/*******************************************************************************
61759503 2 * Copyright (c) 2012, 2013 Ericsson
1c0de632
AM
3 *
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
8 *
9 * Contributors:
10 * Alexandre Montplaisir - Initial API and implementation
11 ******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.core.statistics;
14
f3f93fa6 15import java.util.Collection;
1c0de632 16import java.util.HashMap;
f3f93fa6
AM
17import java.util.LinkedList;
18import java.util.List;
1c0de632 19import java.util.Map;
f3f93fa6 20import java.util.TreeMap;
1c0de632
AM
21
22import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
6debe8aa 23import org.eclipse.linuxtools.tmf.core.event.ITmfLostEvent;
fd3f1eff 24import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
1c0de632
AM
25import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
26import org.eclipse.linuxtools.tmf.core.signal.TmfSignal;
27import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
28import org.eclipse.linuxtools.tmf.core.signal.TmfStatsUpdatedSignal;
3bd46eef
AM
29import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
30import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
31import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
1c0de632
AM
32import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
33
34/**
35 * Implementation of ITmfStatistics which uses event requests to the trace to
36 * retrieve its information.
37 *
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.
41 *
42 * @author Alexandre Montplaisir
43 * @since 2.0
44 */
45public class TmfEventsStatistics implements ITmfStatistics {
46
8b260d9f
AM
47 /* All timestamps should be stored in nanoseconds in the statistics backend */
48 private static final int SCALE = ITmfTimestamp.NANOSECOND_SCALE;
49
1c0de632
AM
50 private final ITmfTrace trace;
51
52 /* Event request objects for the time-range request. */
53 private StatsTotalRequest totalRequest = null;
54 private StatsPerTypeRequest perTypeRequest = null;
55
56 /**
57 * Constructor
58 *
59 * @param trace
60 * The trace for which we are building the statistics
61 */
62 public TmfEventsStatistics(ITmfTrace trace) {
63 this.trace = trace;
64 }
65
1a4205d9
AM
66 @Override
67 public void dispose() {
68 cancelOngoingRequests();
69 }
70
1c0de632 71 @Override
8b260d9f 72 public void updateStats(final boolean isGlobal, long start, long end) {
1c0de632
AM
73 cancelOngoingRequests();
74
75 /*
76 * Prepare and send the event requests. This needs to be done in the
77 * same thread, since it will be run by TmfStatisticsViewer's signal
78 * handlers, to ensure they get correctly coalesced.
79 */
8b260d9f
AM
80 ITmfTimestamp startTS = new TmfTimestamp(start, SCALE);
81 ITmfTimestamp endTS = new TmfTimestamp(end, SCALE);
82 TmfTimeRange range = isGlobal ? TmfTimeRange.ETERNITY : new TmfTimeRange(startTS, endTS);
1c0de632
AM
83 final StatsTotalRequest totalReq = new StatsTotalRequest(trace, range);
84 final StatsPerTypeRequest perTypeReq = new StatsPerTypeRequest(trace, range);
85
86 /*
87 * Only allow one time-range request at a time (there should be only one
88 * global request at the beginning anyway, no need to track those).
89 */
90 if (!isGlobal) {
91 this.totalRequest = totalReq;
92 this.perTypeRequest = perTypeReq;
93 }
94
95 trace.sendRequest(totalReq);
96 trace.sendRequest(perTypeReq);
97
98 /*
99 * This thread can now return. Start a new thread that will wait until
100 * the request are done and will then send the results.
101 */
102 Thread statsThread = new Thread("Statistics update") { //$NON-NLS-1$
103 @Override
104 public void run() {
105 /* Wait for both requests to complete */
106 try {
107 totalReq.waitForCompletion();
108 perTypeReq.waitForCompletion();
109 } catch (InterruptedException e) {
110 e.printStackTrace();
111 }
112
113 /*
114 * If the request was cancelled, this means a newer one was
115 * sent, discard the current one and return without sending
116 * the signal.
117 */
118 if (totalReq.isCancelled() || perTypeReq.isCancelled()) {
119 return;
120 }
121
122 /* If it completed successfully, retrieve the results. */
123 long total = totalReq.getResult();
124 Map<String, Long> map = perTypeReq.getResults();
125
126 /* Send the signal to notify the stats viewer to update its display. */
127 TmfSignal sig = new TmfStatsUpdatedSignal(this, trace, isGlobal, total, map);
128 TmfSignalManager.dispatchSignal(sig);
129 }
130 };
131 statsThread.start();
132 return;
133 }
134
f3f93fa6
AM
135 @Override
136 public List<Long> histogramQuery(long start, long end, int nb) {
137 final long[] borders = new long[nb];
138 final long increment = (end - start) / nb;
139
140 long curTime = start;
141 for (int i = 0; i < nb; i++) {
142 borders[i] = curTime;
143 curTime += increment;
144 }
145
146 HistogramQueryRequest req = new HistogramQueryRequest(borders, end);
147 sendAndWait(req);
148
149 List<Long> results = new LinkedList<Long>(req.getResults());
150 return results;
151
152 }
153
1c0de632
AM
154 private synchronized void cancelOngoingRequests() {
155 if (totalRequest != null && totalRequest.isRunning()) {
156 totalRequest.cancel();
157 }
158 if (perTypeRequest != null && perTypeRequest.isRunning()) {
159 perTypeRequest.cancel();
160 }
161 }
162
163 @Override
164 public long getEventsTotal() {
165 StatsTotalRequest request = new StatsTotalRequest(trace, TmfTimeRange.ETERNITY);
166 sendAndWait(request);
167
168 long total = request.getResult();
169 return total;
170 }
171
172 @Override
173 public Map<String, Long> getEventTypesTotal() {
174 StatsPerTypeRequest request = new StatsPerTypeRequest(trace, TmfTimeRange.ETERNITY);
175 sendAndWait(request);
176
177 Map<String, Long> stats = request.getResults();
178 return stats;
179 }
180
181 @Override
8b260d9f
AM
182 public long getEventsInRange(long start, long end) {
183 ITmfTimestamp startTS = new TmfTimestamp(start, SCALE);
184 ITmfTimestamp endTS = new TmfTimestamp(end, SCALE);
185 TmfTimeRange range = new TmfTimeRange(startTS, endTS);
186
1c0de632
AM
187 StatsTotalRequest request = new StatsTotalRequest(trace, range);
188 sendAndWait(request);
189
190 long total = request.getResult();
191 return total;
192 }
193
194 @Override
8b260d9f
AM
195 public Map<String, Long> getEventTypesInRange(long start, long end) {
196 ITmfTimestamp startTS = new TmfTimestamp(start, SCALE);
197 ITmfTimestamp endTS = new TmfTimestamp(end, SCALE);
198 TmfTimeRange range = new TmfTimeRange(startTS, endTS);
199
1c0de632
AM
200 StatsPerTypeRequest request = new StatsPerTypeRequest(trace, range);
201 sendAndWait(request);
202
203 Map<String, Long> stats = request.getResults();
204 return stats;
205 }
206
207 private void sendAndWait(TmfEventRequest request) {
208 trace.sendRequest(request);
209 try {
210 request.waitForCompletion();
211 } catch (InterruptedException e) {
212 e.printStackTrace();
213 }
214 }
215
216
217 /**
218 * Event request to get the total number of events
219 */
220 private class StatsTotalRequest extends TmfEventRequest {
221
222 /* Total number of events the request has found */
223 private long total;
224
225 public StatsTotalRequest(ITmfTrace trace, TmfTimeRange range) {
fd3f1eff
AM
226 super(trace.getEventType(), range, 0, TmfEventRequest.ALL_DATA,
227 ITmfEventRequest.ExecutionType.BACKGROUND);
1c0de632
AM
228 total = 0;
229 }
230
231 public long getResult() {
232 return total;
233 }
234
235 @Override
236 public void handleData(final ITmfEvent event) {
237 super.handleData(event);
6debe8aa
AM
238 if (!(event instanceof ITmfLostEvent) && event.getTrace() == trace) {
239 total += 1;
1c0de632
AM
240 }
241 }
242 }
243
244
245 /**
246 * Event request to get the counts per event type
247 */
248 private class StatsPerTypeRequest extends TmfEventRequest {
249
250 /* Map in which the results are saved */
251 private final Map<String, Long> stats;
252
253 public StatsPerTypeRequest(ITmfTrace trace, TmfTimeRange range) {
fd3f1eff
AM
254 super(trace.getEventType(), range, 0, TmfEventRequest.ALL_DATA,
255 ITmfEventRequest.ExecutionType.BACKGROUND);
1c0de632
AM
256 this.stats = new HashMap<String, Long>();
257 }
258
259 public Map<String, Long> getResults() {
260 return stats;
261 }
262
263 @Override
5419a136
AM
264 public void handleData(final ITmfEvent event) {
265 super.handleData(event);
6debe8aa 266 if (event != null && event.getTrace() == trace) {
e8f9ac01 267 String eventType = event.getType().getName();
6debe8aa
AM
268 /*
269 * Special handling for lost events: instead of counting just
270 * one, we will count how many actual events it represents.
271 */
272 if (event instanceof ITmfLostEvent) {
273 ITmfLostEvent le = (ITmfLostEvent) event;
e8f9ac01 274 incrementStats(eventType, le.getNbLostEvents());
6debe8aa 275 return;
1c0de632 276 }
6debe8aa
AM
277
278 /* For standard event types, just increment by one */
6debe8aa 279 incrementStats(eventType, 1L);
1c0de632
AM
280 }
281 }
282
6debe8aa
AM
283 private void incrementStats(String key, long count) {
284 if (stats.containsKey(key)) {
285 long curValue = stats.get(key);
286 stats.put(key, curValue + count);
1c0de632 287 } else {
6debe8aa 288 stats.put(key, count);
1c0de632
AM
289 }
290 }
291 }
292
f3f93fa6
AM
293 /**
294 * Event request for histogram queries. It is much faster to do one event
295 * request then set the results accordingly than doing thousands of them one
296 * by one.
297 */
298 private class HistogramQueryRequest extends TmfEventRequest {
299
300 /** Map of <borders, number of events> */
301 private final TreeMap<Long, Long> results;
302
303 /**
304 * New histogram request
305 *
306 * @param borders
307 * The array of borders (not including the end time). The
308 * first element should be the start time of the queries.
309 * @param endTime
310 * The end time of the query. Not used in the results map,
311 * but we need to know when to stop the event request.
312 */
313 public HistogramQueryRequest(long[] borders, long endTime) {
314 super(trace.getEventType(),
315 new TmfTimeRange(
316 new TmfTimestamp(borders[0], SCALE),
317 new TmfTimestamp(endTime, SCALE)),
7184fc40 318 0,
fd3f1eff
AM
319 TmfEventRequest.ALL_DATA,
320 ITmfEventRequest.ExecutionType.BACKGROUND);
f3f93fa6
AM
321
322 /* Prepare the results map, with all counts at 0 */
323 results = new TreeMap<Long, Long>();
324 for (long border : borders) {
325 results.put(border, 0L);
326 }
327 }
328
329 public Collection<Long> getResults() {
330 return results.values();
331 }
332
333 @Override
5419a136
AM
334 public void handleData(ITmfEvent event) {
335 super.handleData(event);
f3f93fa6
AM
336 if ((event != null) && (event.getTrace() == trace)) {
337 long ts = event.getTimestamp().normalize(0, SCALE).getValue();
338 Long key = results.floorKey(ts);
339 if (key != null) {
340 incrementValue(key);
341 }
342 }
343 }
344
345 private void incrementValue(Long key) {
346 long value = results.get(key);
347 value++;
348 results.put(key, value);
349 }
350 }
351
1c0de632 352}
This page took 0.048854 seconds and 5 git commands to generate.