Add null-checks for Map.get()
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / statistics / TmfEventsStatistics.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 Ericsson
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
13 package org.eclipse.tracecompass.tmf.core.statistics;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.util.Collection;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.TreeMap;
23
24 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
25 import org.eclipse.tracecompass.tmf.core.event.ITmfLostEvent;
26 import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
27 import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
28 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
29 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
30 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
31 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
32
33 /**
34 * Implementation of ITmfStatistics which uses event requests to the trace to
35 * retrieve its information.
36 *
37 * There is almost no setup time, but queries themselves are longer than with a
38 * TmfStateStatistics. Queries are O(n * m), where n is the size of the trace,
39 * and m is the portion of the trace covered by the selected interval.
40 *
41 * @author Alexandre Montplaisir
42 */
43 public class TmfEventsStatistics implements ITmfStatistics {
44
45 /* All timestamps should be stored in nanoseconds in the statistics backend */
46 private static final int SCALE = ITmfTimestamp.NANOSECOND_SCALE;
47
48 private final ITmfTrace trace;
49
50 /* Event request objects for the time-range request. */
51 private StatsTotalRequest totalRequest = null;
52 private StatsPerTypeRequest perTypeRequest = null;
53
54 /**
55 * Constructor
56 *
57 * @param trace
58 * The trace for which we are building the statistics
59 */
60 public TmfEventsStatistics(ITmfTrace trace) {
61 this.trace = trace;
62 }
63
64 @Override
65 public void dispose() {
66 cancelOngoingRequests();
67 }
68
69 @Override
70 public List<Long> histogramQuery(long start, long end, int nb) {
71 final long[] borders = new long[nb];
72 final long increment = (end - start) / nb;
73
74 long curTime = start;
75 for (int i = 0; i < nb; i++) {
76 borders[i] = curTime;
77 curTime += increment;
78 }
79
80 HistogramQueryRequest req = new HistogramQueryRequest(borders, end);
81 sendAndWait(req);
82
83 List<Long> results = new LinkedList<>(req.getResults());
84 return results;
85
86 }
87
88 private synchronized void cancelOngoingRequests() {
89 if (totalRequest != null && totalRequest.isRunning()) {
90 totalRequest.cancel();
91 }
92 if (perTypeRequest != null && perTypeRequest.isRunning()) {
93 perTypeRequest.cancel();
94 }
95 }
96
97 @Override
98 public long getEventsTotal() {
99 StatsTotalRequest request = new StatsTotalRequest(trace, TmfTimeRange.ETERNITY);
100 sendAndWait(request);
101
102 long total = request.getResult();
103 return total;
104 }
105
106 @Override
107 public Map<String, Long> getEventTypesTotal() {
108 StatsPerTypeRequest request = new StatsPerTypeRequest(trace, TmfTimeRange.ETERNITY);
109 sendAndWait(request);
110
111 Map<String, Long> stats = request.getResults();
112 return stats;
113 }
114
115 @Override
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);
120
121 StatsTotalRequest request = new StatsTotalRequest(trace, range);
122 sendAndWait(request);
123
124 long total = request.getResult();
125 return total;
126 }
127
128 @Override
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);
133
134 StatsPerTypeRequest request = new StatsPerTypeRequest(trace, range);
135 sendAndWait(request);
136
137 Map<String, Long> stats = request.getResults();
138 return stats;
139 }
140
141 private void sendAndWait(TmfEventRequest request) {
142 trace.sendRequest(request);
143 try {
144 request.waitForCompletion();
145 } catch (InterruptedException e) {
146 e.printStackTrace();
147 }
148 }
149
150
151 /**
152 * Event request to get the total number of events
153 */
154 private class StatsTotalRequest extends TmfEventRequest {
155
156 /* Total number of events the request has found */
157 private long total;
158
159 public StatsTotalRequest(ITmfTrace trace, TmfTimeRange range) {
160 super(trace.getEventType(), range, 0, ITmfEventRequest.ALL_DATA,
161 ITmfEventRequest.ExecutionType.BACKGROUND);
162 total = 0;
163 }
164
165 public long getResult() {
166 return total;
167 }
168
169 @Override
170 public void handleData(final ITmfEvent event) {
171 super.handleData(event);
172 if (!(event instanceof ITmfLostEvent) && event.getTrace() == trace) {
173 total += 1;
174 }
175 }
176 }
177
178
179 /**
180 * Event request to get the counts per event type
181 */
182 private class StatsPerTypeRequest extends TmfEventRequest {
183
184 /* Map in which the results are saved */
185 private final Map<String, Long> stats;
186
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<>();
191 }
192
193 public Map<String, Long> getResults() {
194 return stats;
195 }
196
197 @Override
198 public void handleData(final ITmfEvent event) {
199 super.handleData(event);
200 if (event.getTrace() == trace) {
201 String eventType = event.getName();
202 /*
203 * Special handling for lost events: instead of counting just
204 * one, we will count how many actual events it represents.
205 */
206 if (event instanceof ITmfLostEvent) {
207 ITmfLostEvent le = (ITmfLostEvent) event;
208 incrementStats(eventType, le.getNbLostEvents());
209 return;
210 }
211
212 /* For standard event types, just increment by one */
213 incrementStats(eventType, 1L);
214 }
215 }
216
217 private void incrementStats(String key, long count) {
218 if (stats.containsKey(key)) {
219 long curValue = checkNotNull(stats.get(key));
220 stats.put(key, curValue + count);
221 } else {
222 stats.put(key, count);
223 }
224 }
225 }
226
227 /**
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
230 * by one.
231 */
232 private class HistogramQueryRequest extends TmfEventRequest {
233
234 /** Map of <borders, number of events> */
235 private final TreeMap<Long, Long> results;
236
237 /**
238 * New histogram request
239 *
240 * @param borders
241 * The array of borders (not including the end time). The
242 * first element should be the start time of the queries.
243 * @param endTime
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.
246 */
247 public HistogramQueryRequest(long[] borders, long endTime) {
248 super(trace.getEventType(),
249 new TmfTimeRange(
250 new TmfTimestamp(borders[0], SCALE),
251 new TmfTimestamp(endTime, SCALE)),
252 0,
253 ITmfEventRequest.ALL_DATA,
254 ITmfEventRequest.ExecutionType.BACKGROUND);
255
256 /* Prepare the results map, with all counts at 0 */
257 results = new TreeMap<>();
258 for (long border : borders) {
259 results.put(border, 0L);
260 }
261 }
262
263 public Collection<Long> getResults() {
264 return results.values();
265 }
266
267 @Override
268 public void handleData(ITmfEvent event) {
269 super.handleData(event);
270 if (event.getTrace() == trace) {
271 long ts = event.getTimestamp().normalize(0, SCALE).getValue();
272 Long key = results.floorKey(ts);
273 if (key != null) {
274 incrementValue(key);
275 }
276 }
277 }
278
279 private void incrementValue(Long key) {
280 long value = checkNotNull(results.get(key));
281 value++;
282 results.put(key, value);
283 }
284 }
285
286 }
This page took 0.037242 seconds and 5 git commands to generate.