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