tmf: annotate TmfContext#location as nullable
[deliverable/tracecompass.git] / btf / org.eclipse.tracecompass.btf.core / src / org / eclipse / tracecompass / btf / core / trace / BtfTrace.java
CommitLineData
ff71e543 1/*******************************************************************************
3a723766 2 * Copyright (c) 2014, 2015 Ericsson
ff71e543
MK
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 * Matthew Khouzam - Initial API and implementation
3a723766 11 * Patrick Tasse - Fix parsing of instance numbers
ff71e543
MK
12 *******************************************************************************/
13
7ce90559 14package org.eclipse.tracecompass.btf.core.trace;
ff71e543
MK
15
16import java.io.File;
17import java.io.FileNotFoundException;
18import java.io.IOException;
19import java.io.RandomAccessFile;
20import java.nio.ByteBuffer;
21import java.text.ParseException;
22import java.text.SimpleDateFormat;
23import java.util.Date;
24import java.util.HashMap;
25import java.util.Map;
26import java.util.TreeMap;
27
28import org.eclipse.core.resources.IProject;
29import org.eclipse.core.resources.IResource;
30import org.eclipse.core.runtime.IStatus;
31import org.eclipse.core.runtime.Status;
66838307 32import org.eclipse.jdt.annotation.NonNull;
7ce90559
AM
33import org.eclipse.tracecompass.btf.core.Activator;
34import org.eclipse.tracecompass.btf.core.event.BtfEvent;
35import org.eclipse.tracecompass.btf.core.event.BtfEventType;
2bdf0193
AM
36import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
37import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
b04903a2 38import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
2bdf0193
AM
39import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
40import org.eclipse.tracecompass.tmf.core.io.BufferedRandomAccessFile;
41import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTxtTraceContext;
234838b2 42import org.eclipse.tracecompass.tmf.core.project.model.ITmfPropertiesProvider;
0bc16991
MAL
43import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
44import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
2bdf0193
AM
45import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
46import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
2bdf0193
AM
47import org.eclipse.tracecompass.tmf.core.trace.TmfContext;
48import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
d26d67f5 49import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
2bdf0193
AM
50import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
51import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
52import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
53import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
54import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
55import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
56import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
57import org.eclipse.tracecompass.tmf.core.trace.location.TmfLongLocation;
ff71e543
MK
58
59import com.google.common.collect.ImmutableMap;
60
61/**
62 * BTF reader. Reads Best Trace Format traces.
63 *
64 * @author Matthew Khouzam
65 */
234838b2 66public class BtfTrace extends TmfTrace implements ITmfPersistentlyIndexable, ITmfPropertiesProvider {
ff71e543 67
73604f55
MK
68 private static final int MAX_FIELDS = 7;
69
70 private static final long MICROSECONDS_IN_A_SECOND = 1000000L;
71
ff71e543
MK
72 private static final String VERSION = "#version"; //$NON-NLS-1$
73 private static final String CREATOR = "#creator"; //$NON-NLS-1$
74 private static final String CREATIONDATE = "#creationDate"; //$NON-NLS-1$
75 private static final String INPUTFILE = "#inputFile"; //$NON-NLS-1$
76 private static final String TIMESCALE = "#timeScale"; //$NON-NLS-1$
77 private static final String ENTITYTYPE = "#entityType"; //$NON-NLS-1$
78 private static final String ENTITYTABLE = "#entityTable"; //$NON-NLS-1$
79 private static final String ENTITYTYPETABLE = "#entityTypeTable"; //$NON-NLS-1$
80
81 // lower-case helpers
82 private static final String lCREATIONDATE = "#creationdate"; //$NON-NLS-1$
83 private static final String lINPUTFILE = "#inputfile"; //$NON-NLS-1$
84 private static final String lTIMESCALE = "#timescale"; //$NON-NLS-1$
85 private static final String lENTITYTYPE = "#entitytype"; //$NON-NLS-1$
86 private static final String lENTITYTABLE = "#entitytable"; //$NON-NLS-1$
87 private static final String lENTITYTYPETABLE = "#entitytypetable"; //$NON-NLS-1$
88
89 private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation(-1L);
90
ff71e543
MK
91 private static final int CACHE_SIZE = 256;
92 private static final int MAX_CONFIDENCE = 100;
93 private static final int MAX_LINES = 100;
94
95 private static int fCheckpointSize = -1;
96
66838307 97 private final @NonNull Map<String, String> fProperties = new HashMap<>();
ff71e543 98
66838307
MAL
99 private final @NonNull Map<Integer, String> fEntityTable = new TreeMap<>();
100 private final @NonNull Map<BtfEventType, String> fEntityTypeTable = new HashMap<>();
101 private final @NonNull Map<Integer, BtfEventType> fEntityTypes = new TreeMap<>();
ff71e543
MK
102
103 private String fVersion;
104 private String fCreator;
105 private String fCreationDate;
106 private String fInputFile;
107 // default unit is ns
5dca27ae 108 private BtfTimestampFormat fTsFormat = BtfTimestampFormat.NS;
ff71e543
MK
109
110 private File fFile;
111 private RandomAccessFile fFileInput;
112 private long fDataOffset;
113 private long fTsOffset = 0;
114
115 /**
116 * Default constructor
117 */
118 public BtfTrace() {
119 super();
120 setCacheSize(CACHE_SIZE);
121 fProperties.put(TIMESCALE, fTsFormat.toString());
122 }
123
124 private void parseHeader(RandomAccessFile input) throws IOException {
125 String line = input.readLine();
126 long pos = 0;
127 while (line != null && line.startsWith("#")) { //$NON-NLS-1$
128 String[] tokens = line.split(" ", 2); //$NON-NLS-1$
129 /*
130 * please note that the examples we were given and the spec are NOT
131 * consistent, so we are ignoring the case to avoid issues
132 */
133 switch (tokens[0].toLowerCase()) {
134 case VERSION:
135 fVersion = tokens[1];
136 fProperties.put(VERSION, fVersion);
137 break;
138 case CREATOR:
139 fCreator = tokens[1];
140 fProperties.put(CREATOR, fCreator);
141 break;
142 case lCREATIONDATE:
143 fCreationDate = tokens[1];
144 fProperties.put(CREATIONDATE, fCreationDate);
145
146 try {
38db0431
MK
147 // DateFormats are inherently unsafe for multithreaded use
148 // so we can't make this a field. Just in case.
eddb2560 149 final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); //$NON-NLS-1$
ff71e543 150 Date dateTime = ISO8601DATEFORMAT.parse(fCreationDate);
73604f55 151 fTsOffset = dateTime.getTime() * MICROSECONDS_IN_A_SECOND;
ff71e543
MK
152 } catch (ParseException e) {
153 Activator.logWarning("Creation date error: " + e.getMessage()); //$NON-NLS-1$
154 }
155 break;
156 case lINPUTFILE:
157 fInputFile = tokens[1];
158 fProperties.put(INPUTFILE, fInputFile);
159 break;
160 case lTIMESCALE:
5dca27ae 161 fTsFormat = BtfTimestampFormat.parse(tokens[1]);
ff71e543
MK
162 fProperties.put(TIMESCALE, fTsFormat.toString());
163 break;
164 case lENTITYTYPE:
165 pos = fFileInput.getFilePointer();
166 line = fFileInput.readLine();
167 while (line.startsWith("#-")) { //$NON-NLS-1$
168 String tempLine = line.substring(1);
169 String[] elements = tempLine.split(" ", 2); //$NON-NLS-1$
170 fEntityTypes.put(Integer.parseInt(elements[0]), BtfEventTypeFactory.parse(elements[1]));
171 pos = fFileInput.getFilePointer();
172 line = fFileInput.readLine();
173 }
174 fFileInput.seek(pos);
175 fProperties.put(ENTITYTYPE, fEntityTypes.toString());
176 break;
177 case lENTITYTABLE:
178 pos = fFileInput.getFilePointer();
179 line = fFileInput.readLine();
180 while (line.startsWith("#-")) { //$NON-NLS-1$
181 String tempLine = line.substring(1);
182 String[] elements = tempLine.split(" ", 2); //$NON-NLS-1$
183 fEntityTable.put(Integer.parseInt(elements[0]), elements[1]);
184 pos = fFileInput.getFilePointer();
185 line = fFileInput.readLine();
186 }
187 fProperties.put(ENTITYTABLE, fEntityTable.toString());
188 fFileInput.seek(pos);
189 break;
190 case lENTITYTYPETABLE:
191 pos = fFileInput.getFilePointer();
192 line = fFileInput.readLine();
193 while (line.startsWith("#-")) { //$NON-NLS-1$
194 String tempLine = line.substring(1);
195 String[] elements = tempLine.split(" ", 2); //$NON-NLS-1$
196 fEntityTypeTable.put(BtfEventTypeFactory.parse(elements[0]), elements[1]);
197 pos = fFileInput.getFilePointer();
198 line = fFileInput.readLine();
199 }
200 fFileInput.seek(pos);
201 fProperties.put(ENTITYTYPETABLE, fEntityTypeTable.toString());
202 break;
203 default:
204 break;
205 }
206 fDataOffset = input.getFilePointer();
207 line = input.readLine();
208 }
209 fTsOffset = (long) (fTsOffset * fTsFormat.getScaleFactor());
210 }
211
212 @Override
213 public void initTrace(IResource resource, String path, Class<? extends ITmfEvent> type) throws TmfTraceException {
214 super.initTrace(resource, path, type);
215 fFile = new File(path);
216 try {
217 fFileInput = new RandomAccessFile(fFile, "r"); //$NON-NLS-1$
218 parseHeader(fFileInput);
219 } catch (IOException e) {
5c9bdcbe 220 throw new TmfTraceException(e.getMessage(), e);
ff71e543
MK
221 }
222
223 }
224
0bc16991
MAL
225 private void initFile() throws TmfTraceException {
226 closeFile();
227 try {
228 fFileInput = new BufferedRandomAccessFile(getPath(), "r"); //$NON-NLS-1$
229 } catch (IOException e) {
230 throw new TmfTraceException(e.getMessage(), e);
231 }
232 }
233
234 private void closeFile() {
235 if (fFileInput != null) {
236 try {
237 fFileInput.close();
238 } catch (IOException e) {
239 } finally {
240 fFileInput = null;
241 }
242 }
243 }
244
ff71e543
MK
245 @Override
246 public IStatus validate(IProject project, String path) {
247 File file = new File(path);
248 if (!file.exists()) {
249 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "File not found: " + path); //$NON-NLS-1$
250 }
251 if (!file.isFile()) {
252 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Not a file. It's a directory: " + path); //$NON-NLS-1$
253 }
254 int confidence = 0;
d26d67f5
BH
255 try {
256 if (!TmfTraceUtils.isText(file)) {
257 return new TraceValidationStatus(confidence, Activator.PLUGIN_ID);
258 }
259 } catch (IOException e) {
260 Activator.logError("Error validating file: " + path, e); //$NON-NLS-1$
261 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "IOException validating file: " + path, e); //$NON-NLS-1$
262 }
ff71e543
MK
263 try (BufferedRandomAccessFile rafile = new BufferedRandomAccessFile(path, "r")) { //$NON-NLS-1$
264 int lineCount = 0;
265 int matches = 0;
266 String line = rafile.getNextLine();
267 while ((line != null) && line.startsWith("#")) { //$NON-NLS-1$
268 line = rafile.getNextLine();
269 }
270 while ((line != null) && (lineCount++ < MAX_LINES)) {
271 try {
272 ITmfEvent event = parseLine(0, line);
273 if (event != null) {
274 matches++;
275 }
276 } catch (RuntimeException e) {
277 confidence = Integer.MIN_VALUE;
278 }
279
280 confidence = MAX_CONFIDENCE * matches / lineCount;
281 line = rafile.getNextLine();
282 }
283 } catch (IOException e) {
284 Activator.logError("Error validating file: " + path, e); //$NON-NLS-1$
285 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "IOException validating file: " + path, e); //$NON-NLS-1$
286 }
287
288 return new TraceValidationStatus(confidence, Activator.PLUGIN_ID);
289 }
290
291 @Override
292 public ITmfLocation getCurrentLocation() {
293 long temp = -1;
294 try {
295 temp = fFileInput.getFilePointer();
296 } catch (IOException e) {
297 }
298 return new TmfLongLocation(temp);
299 }
300
301 @Override
302 public double getLocationRatio(ITmfLocation location) {
303 long size = fFile.length() - fDataOffset;
304 long pos;
305 try {
306 pos = fFileInput.getFilePointer() - fDataOffset;
307 } catch (IOException e) {
308 pos = 0;
309 }
310 return 1.0 / size * pos;
311 }
312
313 @Override
314 public ITmfContext seekEvent(ITmfLocation location) {
315 final TmfContext context = new TmfContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
316 if (NULL_LOCATION.equals(location) || fFile == null) {
317 return context;
318 }
319 try {
320 if (location == null) {
321 fFileInput.seek(fDataOffset);
322 } else if (location.getLocationInfo() instanceof Long) {
323 fFileInput.seek((Long) location.getLocationInfo());
324 }
325 context.setLocation(new TmfLongLocation(fFileInput.getFilePointer()));
326 return context;
327 } catch (final FileNotFoundException e) {
328 Activator.logError("Error seeking event. File not found: " + getPath(), e); //$NON-NLS-1$
329 return context;
330 } catch (final IOException e) {
331 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
332 return context;
333 }
334 }
335
336 @Override
337 public ITmfContext seekEvent(double ratio) {
338 if (fFile == null) {
339 return new TmfContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
340 }
341 try {
342 long pos = Math.round(ratio * fFile.length()) - fDataOffset;
343 while (pos > 0) {
344 fFileInput.seek(pos - 1);
345 if (fFileInput.read() == '\n') {
346 break;
347 }
348 pos--;
349 }
350 final ITmfLocation location = new TmfLongLocation(pos);
351 final ITmfContext context = seekEvent(location);
352 context.setRank(ITmfContext.UNKNOWN_RANK);
353 return context;
354 } catch (final IOException e) {
355 Activator.logError("Error seeking event. File: " + getPath(), e); //$NON-NLS-1$
356 return new CustomTxtTraceContext(NULL_LOCATION, ITmfContext.UNKNOWN_RANK);
357 }
358 }
359
360 @Override
361 public ITmfEvent parseEvent(ITmfContext tmfContext) {
362 if (fFile == null || (!(tmfContext instanceof TmfContext))) {
363 return null;
364 }
365
366 final TmfContext context = (TmfContext) tmfContext;
38db0431
MK
367 ITmfLocation location = context.getLocation();
368 if (location == null
369 || !(location.getLocationInfo() instanceof Long)
370 || NULL_LOCATION.equals(location)) {
ff71e543
MK
371 return null;
372 }
373
374 return parseLine(context);
375
376 }
377
378 /**
379 * Parse a line with a context
380 *
381 * @param context
382 * the context, has a location
383 * @return the event from a given line
384 */
385 private ITmfEvent parseLine(TmfContext context) {
38db0431
MK
386 ITmfLocation location = context.getLocation();
387 if (location != null) {
388 try {
389 if (!location.getLocationInfo().equals(fFileInput.getFilePointer())) {
390 seekEvent(location);
391 }
392 } catch (IOException e1) {
393 seekEvent(location);
ff71e543 394 }
38db0431
MK
395 String line;
396 try {
397 line = fFileInput.readLine();
398 return parseLine(context.getRank(), line);
ff71e543 399
38db0431
MK
400 } catch (IOException e) {
401 Activator.logError(e.getMessage(), e);
402 }
ff71e543 403 }
ff71e543
MK
404 return null;
405 }
406
407 /**
408 * Parse a line of text and make an event using it.
409 *
410 * @param rank
411 * the rank of the event
412 * @param line
413 * the raw string of the event
414 * @return the event
415 */
416 private ITmfEvent parseLine(long rank, String line) {
417 if (line == null) {
418 return null;
419 }
73604f55 420 String[] tokens = line.split(",", MAX_FIELDS); //$NON-NLS-1$
3a723766
PT
421 if (tokens.length < MAX_FIELDS) {
422 return null;
423 }
424 int i = 0;
425 long timestamp = Long.parseLong(tokens[i++]);
426 String source = tokens[i++];
427 long sourceInstance = -1;
428 try {
429 sourceInstance = Long.parseLong(tokens[i++]);
430 } catch (NumberFormatException e) {
431 // this field can be empty
432 }
433 BtfEventType type = BtfEventTypeFactory.parse(tokens[i++]);
434 String target = tokens[i++];
435 long targetInstance = -1;
436 try {
437 targetInstance = Long.parseLong(tokens[i++]);
438 } catch (NumberFormatException e) {
439 // this field can be empty
440 }
441 String event = tokens[i++];
ff71e543
MK
442
443 ITmfEventField content = type.generateContent(event, sourceInstance, targetInstance);
444
445 return new BtfEvent(this, rank,
6b44794a 446 getTimestampTransform().transform(fTsFormat.createTimestamp(timestamp + fTsOffset)),
ff71e543
MK
447 source,
448 type,
449 type.getDescription(),
450 content,
451 target);
452 }
453
454 @Override
455 public int getCheckpointSize() {
eddb2560 456 synchronized (BtfTrace.class) {
ff71e543
MK
457 if (fCheckpointSize == -1) {
458 TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.ZERO, new TmfLongLocation(0L), 0);
459 ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
460 b.clear();
461 c.serialize(b);
462 fCheckpointSize = b.position();
463 }
464 }
465
466 return fCheckpointSize;
467 }
468
469 @Override
470 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
471 return new TmfLongLocation(bufferIn);
472 }
473
474 @Override
475 protected ITmfTraceIndexer createIndexer(int interval) {
476 return new TmfBTreeTraceIndexer(this, interval);
477 }
478
234838b2
GB
479 /**
480 * @since 2.0
481 */
ff71e543 482 @Override
234838b2 483 public Map<String, String> getProperties() {
ff71e543
MK
484 return ImmutableMap.copyOf(fProperties);
485 }
486
b04903a2 487 @Override
ec48d248 488 public Iterable<ITmfEventAspect<?>> getEventAspects() {
b04903a2
AM
489 return BtfEventAspects.getAspects();
490 }
491
ff71e543 492 @Override
d9aa847c
AM
493 public synchronized void dispose() {
494 RandomAccessFile raf = fFileInput;
495 if (raf != null) {
496 try {
497 raf.close();
498 } catch (IOException e) {
499 }
ff71e543 500 }
d9aa847c 501 super.dispose();
ff71e543
MK
502 }
503
0bc16991
MAL
504 @TmfSignalHandler
505 @Override
506 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
507 if (signal.getTrace() == this) {
508 try {
509 synchronized (this) {
38db0431
MK
510 /*
511 * Reset the file handle in case it has reached the end of
512 * the file already. Otherwise, it will not be able to read
513 * new data pass the previous end.
514 */
0bc16991
MAL
515 initFile();
516 }
517 } catch (TmfTraceException e) {
518 Activator.logError(e.getLocalizedMessage(), e);
519 }
520 }
521 super.traceRangeUpdated(signal);
522 }
ff71e543 523}
This page took 0.077021 seconds and 5 git commands to generate.