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