tmf: Automatically sync experiments set up with the same hosts
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / trace / TmfTraceUtils.java
CommitLineData
b8585c7c
AM
1/*******************************************************************************
2 * Copyright (c) 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
13package org.eclipse.tracecompass.tmf.core.trace;
14
aa353506
AM
15import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
d26d67f5
BH
17import java.io.BufferedInputStream;
18import java.io.File;
19import java.io.FileInputStream;
20import java.io.IOException;
daf3c7eb
MK
21import java.util.ArrayList;
22import java.util.List;
c93f91d9 23import java.util.Optional;
dba71686 24import java.util.function.Predicate;
b8585c7c 25
f8a23812 26import org.eclipse.core.runtime.IProgressMonitor;
df2597e0 27import org.eclipse.jdt.annotation.NonNull;
1d83ed07 28import org.eclipse.jdt.annotation.NonNullByDefault;
b8585c7c 29import org.eclipse.jdt.annotation.Nullable;
c15e897d 30import org.eclipse.tracecompass.common.core.StreamUtils;
b8585c7c 31import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
daf3c7eb 32import org.eclipse.tracecompass.tmf.core.component.ITmfEventProvider;
b1aad44e 33import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
35f39420 34import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
dba71686 35import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
b8585c7c 36
daf3c7eb 37import com.google.common.collect.Iterables;
c93f91d9 38import com.google.common.collect.Lists;
daf3c7eb 39
b8585c7c
AM
40/**
41 * Utility methods for ITmfTrace's.
42 *
43 * @author Alexandre Montplaisir
44 */
1d83ed07 45@NonNullByDefault
b8585c7c
AM
46public final class TmfTraceUtils {
47
d26d67f5
BH
48 private static final int MAX_NB_BINARY_BYTES = 2048;
49
b1aad44e
GB
50 private TmfTraceUtils() {
51 }
b8585c7c
AM
52
53 /**
daf3c7eb
MK
54 * Return the first result of the first analysis module belonging to this trace or its children,
55 * with the specified ID and class.
b8585c7c
AM
56 *
57 * @param trace
58 * The trace for which you want the modules
59 * @param moduleClass
60 * Returned modules must extend this class
61 * @param id
62 * The ID of the analysis module
63 * @return The analysis module with specified class and ID, or null if no
64 * such module exists.
65 */
66 public static @Nullable <T extends IAnalysisModule> T getAnalysisModuleOfClass(ITmfTrace trace,
67 Class<T> moduleClass, String id) {
68 Iterable<T> modules = getAnalysisModulesOfClass(trace, moduleClass);
69 for (T module : modules) {
70 if (id.equals(module.getId())) {
71 return module;
72 }
73 }
74 return null;
75 }
76
77 /**
daf3c7eb
MK
78 * Return the analysis modules that are of a given class. The modules will be
79 * cast to the requested class. If the trace has children, the childrens modules
80 * are also returned.
b8585c7c
AM
81 *
82 * @param trace
daf3c7eb
MK
83 * The trace for which you want the modules, the children trace modules
84 * are added as well.
b8585c7c
AM
85 * @param moduleClass
86 * Returned modules must extend this class
87 * @return List of modules of class moduleClass
88 */
df2597e0 89 public static <T> Iterable<@NonNull T> getAnalysisModulesOfClass(ITmfTrace trace, Class<T> moduleClass) {
b8585c7c 90 Iterable<IAnalysisModule> analysisModules = trace.getAnalysisModules();
daf3c7eb 91 List<@NonNull T> modules = new ArrayList<>();
b1aad44e 92 for (IAnalysisModule module : analysisModules) {
b8585c7c 93 if (moduleClass.isAssignableFrom(module.getClass())) {
aa353506 94 modules.add(checkNotNull(moduleClass.cast(module)));
b8585c7c
AM
95 }
96 }
daf3c7eb
MK
97 for (ITmfEventProvider child : trace.getChildren()) {
98 if (child instanceof ITmfTrace) {
99 ITmfTrace childTrace = (ITmfTrace) child;
100 Iterables.addAll(modules, getAnalysisModulesOfClass(childTrace, moduleClass));
101 }
102 }
b8585c7c
AM
103 return modules;
104 }
35f39420
AM
105
106 /**
b1aad44e
GB
107 * Return the first result of the first aspect that resolves as non null for
108 * the event received in parameter. If the returned value is not null, it
109 * can be safely cast to the aspect's class proper return type.
35f39420
AM
110 *
111 * @param trace
112 * The trace for which you want the event aspects
113 * @param aspectClass
b1aad44e
GB
114 * The class of the aspect(s) to resolve
115 * @param event
116 * The event for which to get the aspect
117 * @return The first result of the
118 * {@link ITmfEventAspect#resolve(ITmfEvent)} that returns non null
119 * for the event or {@code null} otherwise
35f39420 120 */
c15e897d 121 public static <T extends ITmfEventAspect<?>> @Nullable Object resolveEventAspectOfClassForEvent(
1d83ed07 122 ITmfTrace trace, Class<T> aspectClass, ITmfEvent event) {
c15e897d
AM
123 return StreamUtils.getStream(trace.getEventAspects())
124 .filter(aspect -> aspectClass.isAssignableFrom(aspect.getClass()))
125 .map(aspect -> aspect.resolve(event))
126 .filter(obj -> obj != null)
127 .findFirst().orElse(null);
35f39420 128 }
d26d67f5 129
b3867ecc 130 /**
c15e897d
AM
131 * Return the first result of the first aspect that resolves as a non-null
132 * Integer for the event received in parameter. If no matching aspects are
133 * found then null is returned.
b3867ecc
MAL
134 *
135 * @param trace
136 * The trace for which you want the event aspects
137 * @param aspectClass
138 * The class of the aspect(s) to resolve
139 * @param event
140 * The event for which to get the aspect
141 * @return Integer of the first result of the
142 * {@link ITmfEventAspect#resolve(ITmfEvent)} that returns non null
143 * for the event or {@code null} otherwise
144 * @since 2.0
145 */
c15e897d 146 public static <T extends ITmfEventAspect<Integer>> @Nullable Integer resolveIntEventAspectOfClassForEvent(
b3867ecc 147 ITmfTrace trace, Class<T> aspectClass, ITmfEvent event) {
c15e897d
AM
148 return StreamUtils.getStream(trace.getEventAspects())
149 .filter(aspect -> aspectClass.isAssignableFrom(aspect.getClass()))
150 /* Enforced by the T parameter bounding */
151 .map(aspect -> (Integer) aspect.resolve(event))
152 .filter(obj -> obj != null)
153 .findFirst().orElse(null);
b3867ecc
MAL
154 }
155
d26d67f5
BH
156 /**
157 * Checks for text file.
158 *
159 * Note that it checks for binary value 0 in the first MAX_NB_BINARY_BYTES
160 * bytes to determine if the file is text.
161 *
162 * @param file
163 * the file to check. Caller has to make sure that file exists.
164 * @return true if it is binary else false
165 * @throws IOException
166 * if IOException occurs
066b02aa 167 * @since 1.2
d26d67f5
BH
168 */
169 public static boolean isText(File file) throws IOException {
170 try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file))) {
171 int count = 0;
172 int val = bufferedInputStream.read();
173 while ((count < MAX_NB_BINARY_BYTES) && (val >= 0)) {
174 if (val == 0) {
175 return false;
176 }
177 count++;
178 val = bufferedInputStream.read();
179 }
180 }
181 return true;
182 }
dba71686
AM
183
184 // ------------------------------------------------------------------------
185 // Event matching methods
186 // ------------------------------------------------------------------------
187
188 /**
189 * Retrieve from a trace the next event, from a starting rank, matching the
190 * given predicate.
191 *
192 * @param trace
193 * The trace
194 * @param startRank
195 * The rank of the event at which to start searching. Use
196 * <code>0</code> to search from the start of the trace.
197 * @param predicate
198 * The predicate to test events against
f8a23812
AM
199 * @param monitor
200 * Optional progress monitor that can be used to cancel the
201 * operation
dba71686
AM
202 * @return The first event matching the predicate, or null if the end of the
203 * trace was reached and no event was found
dc281431 204 * @since 2.1
dba71686 205 */
f8a23812
AM
206 public static @Nullable ITmfEvent getNextEventMatching(ITmfTrace trace, long startRank,
207 Predicate<ITmfEvent> predicate, @Nullable IProgressMonitor monitor) {
1353a51a
AM
208 if (monitor != null && monitor.isCanceled()) {
209 return null;
210 }
211
dba71686
AM
212 /* rank + 1 because we do not want to include the start event itself in the search */
213 EventMatchingRequest req = new EventMatchingRequest(startRank + 1, predicate, false);
214 trace.sendRequest(req);
215 try {
f8a23812
AM
216 /* Check periodically if the job was cancelled */
217 req.waitForStart();
218 while (req.isRunning()) {
219 Thread.sleep(200);
220 if (monitor != null && monitor.isCanceled()) {
221 req.cancel();
222 return null;
223 }
224 }
dba71686
AM
225 req.waitForCompletion();
226 } catch (InterruptedException e) {
227 return null;
228 }
229
230 return req.getFoundEvent();
231 }
232
233 /**
234 * Retrieve from a trace the previous event, from a given rank, matching the
235 * given predicate.
236 *
237 * @param trace
238 * The trace
239 * @param startRank
240 * The rank of the event at which to start searching backwards.
241 * @param predicate
242 * The predicate to test events against
f8a23812
AM
243 * @param monitor Optional progress monitor that can be used to cancel the
244 * operation
dba71686
AM
245 * @return The first event found matching the predicate, or null if the
246 * beginning of the trace was reached and no event was found
dc281431 247 * @since 2.1
dba71686 248 */
f8a23812
AM
249 public static @Nullable ITmfEvent getPreviousEventMatching(ITmfTrace trace, long startRank,
250 Predicate<ITmfEvent> predicate, @Nullable IProgressMonitor monitor) {
1353a51a
AM
251 if (monitor != null && monitor.isCanceled()) {
252 return null;
253 }
dba71686 254 /*
c93f91d9
MK
255 * We are going to do a series of queries matching the trace's cache
256 * size in length (which should minimize on-disk seeks), then iterate on
257 * the found events in reverse order until we find a match.
dba71686 258 */
c93f91d9 259 int step = trace.getCacheSize();
dba71686
AM
260
261 /*
262 * If we are close to the beginning of the trace, make sure we only look
263 * for the events before the startRank.
264 */
c93f91d9
MK
265 if (startRank < step) {
266 step = (int) startRank;
267 }
dba71686
AM
268
269 long currentRank = startRank;
270 try {
271 while (currentRank > 0) {
272 currentRank = Math.max(currentRank - step, 0);
273
c93f91d9
MK
274 List<ITmfEvent> list = new ArrayList<>(step);
275 ArrayFillingRequest req = new ArrayFillingRequest(currentRank, step, list);
dba71686 276 trace.sendRequest(req);
f8a23812
AM
277
278 /* Check periodically if the job was cancelled */
279 req.waitForStart();
280 while (req.isRunning()) {
281 Thread.sleep(200);
282 if (monitor != null && monitor.isCanceled()) {
283 req.cancel();
284 return null;
285 }
286 }
dba71686
AM
287 req.waitForCompletion();
288
c93f91d9
MK
289 Optional<ITmfEvent> matchingEvent = Lists.reverse(list).stream()
290 .filter(predicate)
291 .findFirst();
292
293 if (matchingEvent.isPresent()) {
294 /* We found an event matching, return it! */
295 return matchingEvent.get();
dba71686
AM
296 }
297 /* Keep searching, next loop */
298
299 }
300 } catch (InterruptedException e) {
301 return null;
302 }
303
304 /*
305 * We searched up to the beginning of the trace and didn't find
306 * anything.
307 */
308 return null;
309
310 }
311
312 /**
313 * Event request looking for an event matching a Predicate.
314 */
315 private static class EventMatchingRequest extends TmfEventRequest {
316
317 private final Predicate<ITmfEvent> fPredicate;
318 private final boolean fReturnLast;
319
320 private @Nullable ITmfEvent fFoundEvent = null;
321
322 /**
323 * Basic constructor, will query the trace until the end.
324 *
325 * @param startRank
326 * The rank at which to start, use 0 for the beginning
327 * @param predicate
328 * The predicate to test against each event
329 * @param returnLast
330 * Should we return the last or first event found. If false,
331 * the request ends as soon as a matching event is found. If
332 * false, we will go through all events to find a possible
333 * last-match.
334 */
335 public EventMatchingRequest(long startRank, Predicate<ITmfEvent> predicate, boolean returnLast) {
336 super(ITmfEvent.class, startRank, ALL_DATA, ExecutionType.FOREGROUND);
337 fPredicate = predicate;
338 fReturnLast = returnLast;
339 }
340
341 /**
342 * Basic constructor, will query the trace the limit is reached.
343 *
344 * @param startRank
345 * The rank at which to start, use 0 for the beginning
346 * @param limit
347 * The limit on the number of events
348 * @param predicate
349 * The predicate to test against each event
350 * @param returnLast
351 * Should we return the last or first event found. If false,
352 * the request ends as soon as a matching event is found. If
353 * false, we will go through all events to find a possible
354 * last-match.
355 */
356 public EventMatchingRequest(long startRank, int limit, Predicate<ITmfEvent> predicate, boolean returnLast) {
357 super(ITmfEvent.class, startRank, limit, ExecutionType.FOREGROUND);
358 fPredicate = predicate;
359 fReturnLast = returnLast;
360 }
361
362 public @Nullable ITmfEvent getFoundEvent() {
363 return fFoundEvent;
364 }
365
366 @Override
367 public void handleData(ITmfEvent event) {
368 super.handleData(event);
369
370 if (fPredicate.test(event)) {
371 fFoundEvent = event;
372 if (!fReturnLast) {
373 this.done();
374 }
375 }
376 }
377 }
c93f91d9
MK
378
379 /**
380 * Event request that simply puts all returned events into a list passed in
381 * parameter.
382 */
383 private static class ArrayFillingRequest extends TmfEventRequest {
384
385 private final List<ITmfEvent> fList;
386
387 public ArrayFillingRequest(long startRank, int limit, List<ITmfEvent> listToFill) {
388 super(ITmfEvent.class, startRank, limit, ExecutionType.FOREGROUND);
389 fList = listToFill;
390 }
391
392 @Override
393 public void handleData(ITmfEvent event) {
394 super.handleData(event);
395 fList.add(event);
396 }
397
398 }
b8585c7c 399}
This page took 0.077688 seconds and 5 git commands to generate.