~ubuntu-branches/ubuntu/trusty/eclipse-linuxtools/trusty

« back to all changes in this revision

Viewing changes to lttng/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/StreamInputPacketReader.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2012-06-29 12:07:30 UTC
  • Revision ID: package-import@ubuntu.com-20120629120730-bfri1xys1i71dpn6
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
 
3
 *
 
4
 * All rights reserved. This program and the accompanying materials are made
 
5
 * 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: Matthew Khouzam - Initial API and implementation
 
10
 * Contributors: Simon Marchi - Initial API and implementation
 
11
 *******************************************************************************/
 
12
package org.eclipse.linuxtools.ctf.core.trace;
 
13
 
 
14
import java.io.IOException;
 
15
import java.nio.MappedByteBuffer;
 
16
import java.nio.channels.FileChannel.MapMode;
 
17
import java.util.Collection;
 
18
import java.util.HashMap;
 
19
 
 
20
import org.eclipse.linuxtools.ctf.core.event.EventDeclaration;
 
21
import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
 
22
import org.eclipse.linuxtools.ctf.core.event.types.Definition;
 
23
import org.eclipse.linuxtools.ctf.core.event.types.EnumDefinition;
 
24
import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
 
25
import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
 
26
import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
 
27
import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
 
28
import org.eclipse.linuxtools.ctf.core.event.types.VariantDefinition;
 
29
import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
 
30
import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
 
31
import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
 
32
 
 
33
/**
 
34
 * CTF trace packet reader. Reads the events of a packet of a trace file.
 
35
 * 
 
36
 * @version 1.0
 
37
 * @author Matthew Khouzam
 
38
 * @author Simon Marchi
 
39
 */
 
40
public class StreamInputPacketReader implements IDefinitionScope {
 
41
 
 
42
    // ------------------------------------------------------------------------
 
43
    // Constants
 
44
    // ------------------------------------------------------------------------
 
45
 
 
46
    /**
 
47
     * Reference to the index entry of the current packet.
 
48
     */
 
49
    private StreamInputPacketIndexEntry currentPacket = null;
 
50
 
 
51
    /**
 
52
     * BitBuffer used to read the trace file.
 
53
     */
 
54
    private final BitBuffer bitBuffer = new BitBuffer();
 
55
 
 
56
    /**
 
57
     * StreamInputReader that uses this StreamInputPacketReader.
 
58
     */
 
59
    private final StreamInputReader streamInputReader;
 
60
 
 
61
    /**
 
62
     * Last timestamp recorded.
 
63
     *
 
64
     * Needed to calculate the complete timestamp values for the events with
 
65
     * compact headers.
 
66
     */
 
67
    private long lastTimestamp = 0;
 
68
 
 
69
    /**
 
70
     * Trace packet header.
 
71
     */
 
72
    private StructDefinition tracePacketHeaderDef = null;
 
73
 
 
74
    /**
 
75
     * Stream packet context definition.
 
76
     */
 
77
    private StructDefinition streamPacketContextDef = null;
 
78
 
 
79
    /**
 
80
     * Stream event header definition.
 
81
     */
 
82
    private StructDefinition streamEventHeaderDef = null;
 
83
 
 
84
    /**
 
85
     * Stream event context definition.
 
86
     */
 
87
    private StructDefinition streamEventContextDef = null;
 
88
 
 
89
    /**
 
90
     * Maps event ID to event definitions.
 
91
     */
 
92
    private final HashMap<Long, EventDefinition> events;
 
93
 
 
94
    /**
 
95
     * CPU id of current packet.
 
96
     */
 
97
    private int currentCpu = 0;
 
98
 
 
99
    /**
 
100
     * number of lost events in this packet
 
101
     */
 
102
    private int lostEvents;
 
103
 
 
104
    private int lostSoFar;
 
105
 
 
106
    // ------------------------------------------------------------------------
 
107
    // Attributes
 
108
    // ------------------------------------------------------------------------
 
109
 
 
110
    /**
 
111
     * Constructs a StreamInputPacketReader.
 
112
     *
 
113
     * @param streamInputReader
 
114
     *            The StreamInputReader to which this packet reader belongs to.
 
115
     */
 
116
    public StreamInputPacketReader(StreamInputReader streamInputReader) {
 
117
        this.streamInputReader = streamInputReader;
 
118
 
 
119
        /*
 
120
         * Set the BitBuffer's byte order.
 
121
         */
 
122
        getBitBuffer().setByteOrder(streamInputReader.getByteOrder());
 
123
 
 
124
        events = streamInputReader.getStreamInput().getStream().getTrace()
 
125
                .getEventDefs(streamInputReader.getStreamInput());
 
126
        /*
 
127
         * Create definitions needed to read the events.
 
128
         */
 
129
        createDefinitions();
 
130
 
 
131
        lostEvents = 0;
 
132
        lostSoFar = 0;
 
133
    }
 
134
 
 
135
    // ------------------------------------------------------------------------
 
136
    // Constructors
 
137
    // ------------------------------------------------------------------------
 
138
 
 
139
    // ------------------------------------------------------------------------
 
140
    // Getters/Setters/Predicates
 
141
    // ------------------------------------------------------------------------
 
142
 
 
143
    /**
 
144
     * Gets the current packet
 
145
     *
 
146
     * @return the current packet
 
147
     */
 
148
    public StreamInputPacketIndexEntry getCurrentPacket() {
 
149
        return this.currentPacket;
 
150
    }
 
151
 
 
152
    /**
 
153
     * Gets the steamPacketContext Definition
 
154
     *
 
155
     * @return steamPacketContext Definition
 
156
     */
 
157
    public StructDefinition getStreamPacketContextDef() {
 
158
        return this.streamPacketContextDef;
 
159
    }
 
160
 
 
161
    /**
 
162
     * Gets the CPU (core) number
 
163
     *
 
164
     * @return the CPU (core) number
 
165
     */
 
166
    public int getCPU() {
 
167
        return this.currentCpu;
 
168
    }
 
169
 
 
170
    @Override
 
171
    public String getPath() {
 
172
        return ""; //$NON-NLS-1$
 
173
    }
 
174
 
 
175
    // ------------------------------------------------------------------------
 
176
    // Operations
 
177
    // ------------------------------------------------------------------------
 
178
 
 
179
    /**
 
180
     * Creates definitions needed to read events (stream-defined and
 
181
     * event-defined).
 
182
     */
 
183
    private void createDefinitions() {
 
184
        /*
 
185
         * Create trace packet header definition.
 
186
         */
 
187
        final Stream currentStream = getStreamInputReader().getStreamInput()
 
188
                .getStream();
 
189
        StructDeclaration tracePacketHeaderDecl = currentStream.getTrace()
 
190
                .getPacketHeader();
 
191
        if (tracePacketHeaderDecl != null) {
 
192
            setTracePacketHeaderDef(tracePacketHeaderDecl.createDefinition(
 
193
                    this, "trace.packet.header")); //$NON-NLS-1$
 
194
        }
 
195
 
 
196
        /*
 
197
         * Create stream packet context definition.
 
198
         */
 
199
        StructDeclaration streamPacketContextDecl = currentStream
 
200
                .getPacketContextDecl();
 
201
        if (streamPacketContextDecl != null) {
 
202
            setStreamPacketContextDef(streamPacketContextDecl.createDefinition(
 
203
                    this, "stream.packet.context")); //$NON-NLS-1$
 
204
        }
 
205
 
 
206
        /*
 
207
         * Create stream event header definition.
 
208
         */
 
209
        StructDeclaration streamEventHeaderDecl = currentStream
 
210
                .getEventHeaderDecl();
 
211
        if (streamEventHeaderDecl != null) {
 
212
            setStreamEventHeaderDef(streamEventHeaderDecl.createDefinition(
 
213
                    this, "stream.event.header")); //$NON-NLS-1$
 
214
        }
 
215
 
 
216
        /*
 
217
         * Create stream event context definition.
 
218
         */
 
219
        StructDeclaration streamEventContextDecl = currentStream
 
220
                .getEventContextDecl();
 
221
        if (streamEventContextDecl != null) {
 
222
            setStreamEventContextDef(streamEventContextDecl.createDefinition(
 
223
                    this, "stream.event.context")); //$NON-NLS-1$
 
224
        }
 
225
 
 
226
        createEventDefinitions();
 
227
    }
 
228
 
 
229
    /**
 
230
     * Creates definitions needed to read the event. (event-defined).
 
231
     */
 
232
    private void createEventDefinitions() {
 
233
        Collection<EventDeclaration> eventDecls = getStreamInputReader()
 
234
                .getStreamInput().getStream().getEvents().values();
 
235
 
 
236
        /*
 
237
         * Create definitions for each event.
 
238
         */
 
239
        for (EventDeclaration event : eventDecls) {
 
240
            if (!events.containsKey(event.getId())) {
 
241
                EventDefinition eventDef = event
 
242
                        .createDefinition(getStreamInputReader());
 
243
                events.put(event.getId(), eventDef);
 
244
            }
 
245
        }
 
246
    }
 
247
 
 
248
    /**
 
249
     * Changes the current packet to the given one.
 
250
     *
 
251
     * @param currentPacket
 
252
     *            The index entry of the packet to switch to.
 
253
     */
 
254
    public void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
 
255
        this.currentPacket = currentPacket;
 
256
 
 
257
        if (this.currentPacket != null) {
 
258
            /*
 
259
             * Change the map of the BitBuffer.
 
260
             */
 
261
            MappedByteBuffer bb = null;
 
262
            try {
 
263
                bb = getStreamInputReader()
 
264
                        .getStreamInput()
 
265
                        .getFileChannel()
 
266
                        .map(MapMode.READ_ONLY,
 
267
                                this.currentPacket.getOffsetBytes(),
 
268
                                (this.currentPacket.getPacketSizeBits() + 7) / 8);
 
269
            } catch (IOException e) {
 
270
                /*
 
271
                 * The streamInputReader object is already allocated, so this
 
272
                 * shouldn't fail bar some very bad kernel or RAM errors...
 
273
                 */
 
274
                e.printStackTrace();
 
275
            }
 
276
 
 
277
            getBitBuffer().setByteBuffer(bb);
 
278
 
 
279
            /*
 
280
             * Read trace packet header.
 
281
             */
 
282
            if (getTracePacketHeaderDef() != null) {
 
283
                getTracePacketHeaderDef().read(getBitBuffer());
 
284
            }
 
285
 
 
286
            /*
 
287
             * Read stream packet context.
 
288
             */
 
289
            if (getStreamPacketContextDef() != null) {
 
290
                getStreamPacketContextDef().read(getBitBuffer());
 
291
                /*
 
292
                 * Read CPU ID
 
293
                 */
 
294
 
 
295
                Definition cpuiddef = getStreamPacketContextDef()
 
296
                        .lookupDefinition("cpu_id"); //$NON-NLS-1$
 
297
                if (cpuiddef instanceof IntegerDefinition) {
 
298
                    currentCpu = (int) ((IntegerDefinition) cpuiddef)
 
299
                            .getValue();
 
300
                }
 
301
                /*
 
302
                 * Read number of lost events
 
303
                 */
 
304
                Definition lostEventsdef = getStreamPacketContextDef()
 
305
                        .lookupDefinition("events_discarded"); //$NON-NLS-1$
 
306
                if (cpuiddef instanceof IntegerDefinition) {
 
307
                    lostEvents = (int) ((IntegerDefinition) lostEventsdef)
 
308
                            .getValue();
 
309
                }
 
310
 
 
311
            }
 
312
 
 
313
            /*
 
314
             * Use the timestamp begin of the packet as the reference for the
 
315
             * timestamp reconstitution.
 
316
             */
 
317
            lastTimestamp = currentPacket.getTimestampBegin();
 
318
        } else {
 
319
            getBitBuffer().setByteBuffer(null);
 
320
 
 
321
            lastTimestamp = 0;
 
322
        }
 
323
    }
 
324
 
 
325
    /**
 
326
     * Returns whether it is possible to read any more events from this packet.
 
327
     *
 
328
     * @return True if it is possible to read any more events from this packet.
 
329
     */
 
330
    public boolean hasMoreEvents() {
 
331
        if (currentPacket != null) {
 
332
            return getBitBuffer().position() < currentPacket
 
333
                    .getContentSizeBits();
 
334
        }
 
335
        return false;
 
336
    }
 
337
 
 
338
    /**
 
339
     * Reads the next event of the packet into the right event definition.
 
340
     *
 
341
     * @return The event definition containing the event data that was just
 
342
     *         read.
 
343
     * @throws CTFReaderException
 
344
     *             If there was a problem reading the trace
 
345
     */
 
346
    public EventDefinition readNextEvent() throws CTFReaderException {
 
347
        /* WARNING: This is very LTTng-specific. */
 
348
        Long eventID = null;
 
349
        long timestamp = 0;
 
350
 
 
351
        if (lostEvents > lostSoFar) {
 
352
            EventDefinition eventDef = EventDeclaration
 
353
                    .getLostEventDeclaration().createDefinition(
 
354
                            streamInputReader);
 
355
            eventDef.setTimestamp(this.lastTimestamp);
 
356
            ++lostSoFar;
 
357
            return eventDef;
 
358
        }
 
359
        StructDefinition sehd = getStreamEventHeaderDef(); // acronym for a long
 
360
                                                           // variable name
 
361
        BitBuffer currentBitBuffer = getBitBuffer();
 
362
        /*
 
363
         * Read the stream event header.
 
364
         */
 
365
 
 
366
        if (sehd != null) {
 
367
            sehd.read(currentBitBuffer);
 
368
 
 
369
            /*
 
370
             * Check for an event id.
 
371
             */
 
372
            EnumDefinition idEnumDef = (EnumDefinition) sehd
 
373
                    .lookupDefinition("id"); //$NON-NLS-1$
 
374
            assert (idEnumDef != null);
 
375
 
 
376
            eventID = idEnumDef.getIntegerValue();
 
377
 
 
378
            /*
 
379
             * Check for the variant v.
 
380
             */
 
381
            VariantDefinition variantDef = (VariantDefinition) sehd
 
382
                    .lookupDefinition("v"); //$NON-NLS-1$
 
383
            assert (variantDef != null);
 
384
 
 
385
            /*
 
386
             * Get the variant current field
 
387
             */
 
388
            StructDefinition variantCurrentField = (StructDefinition) variantDef
 
389
                    .getCurrentField();
 
390
            assert (variantCurrentField != null);
 
391
 
 
392
            /*
 
393
             * Try to get the id field in the current field of the variant. If
 
394
             * it is present, it overrides the previously read event id.
 
395
             */
 
396
            IntegerDefinition idIntegerDef = (IntegerDefinition) variantCurrentField
 
397
                    .lookupDefinition("id"); //$NON-NLS-1$
 
398
            if (idIntegerDef != null) {
 
399
                eventID = idIntegerDef.getValue();
 
400
            }
 
401
 
 
402
            /*
 
403
             * Get the timestamp.
 
404
             */
 
405
            IntegerDefinition timestampDef = (IntegerDefinition) variantCurrentField
 
406
                    .lookupDefinition("timestamp"); //$NON-NLS-1$
 
407
            assert (timestampDef != null);
 
408
 
 
409
            /*
 
410
             * Calculate the event timestamp.
 
411
             */
 
412
            timestamp = calculateTimestamp(timestampDef);
 
413
        }
 
414
 
 
415
        /*
 
416
         * Read the stream event context.
 
417
         */
 
418
        if (getStreamEventContextDef() != null) {
 
419
            getStreamEventContextDef().read(currentBitBuffer);
 
420
        }
 
421
 
 
422
        /*
 
423
         * Get the right event definition using the event id.
 
424
         */
 
425
        EventDefinition eventDef = events.get(eventID);
 
426
        if (eventDef == null) {
 
427
            throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
 
428
        }
 
429
 
 
430
        /*
 
431
         * Read the event context.
 
432
         */
 
433
        if (eventDef.getContext() != null) {
 
434
            eventDef.getContext().read(currentBitBuffer);
 
435
        }
 
436
 
 
437
        /*
 
438
         * Read the event fields.
 
439
         */
 
440
        if (eventDef.getFields() != null) {
 
441
            eventDef.getFields().read(currentBitBuffer);
 
442
        }
 
443
 
 
444
        /*
 
445
         * Set the event timestamp using the timestamp calculated by
 
446
         * updateTimestamp.
 
447
         */
 
448
        eventDef.setTimestamp(timestamp);
 
449
 
 
450
        return eventDef;
 
451
    }
 
452
 
 
453
    /**
 
454
     * Calculates the timestamp value of the event, possibly using the timestamp
 
455
     * from the last event.
 
456
     *
 
457
     * @param timestampDef
 
458
     *            Integer definition of the timestamp.
 
459
     * @return The calculated timestamp value.
 
460
     */
 
461
    private long calculateTimestamp(IntegerDefinition timestampDef) {
 
462
        long newval;
 
463
        long majorasbitmask;
 
464
        int len = timestampDef.getDeclaration().getLength();
 
465
 
 
466
        /*
 
467
         * If the timestamp length is 64 bits, it is a full timestamp.
 
468
         */
 
469
        if (timestampDef.getDeclaration().getLength() == 64) {
 
470
            lastTimestamp = timestampDef.getValue();
 
471
            return lastTimestamp;
 
472
        }
 
473
 
 
474
        /*
 
475
         * Bit mask to keep / remove all old / new bits.
 
476
         */
 
477
        majorasbitmask = (1L << len) - 1;
 
478
 
 
479
        /*
 
480
         * If the new value is smaller than the corresponding bits of the last
 
481
         * timestamp, we assume an overflow of the compact representation.
 
482
         */
 
483
        newval = timestampDef.getValue();
 
484
        if (newval < (lastTimestamp & majorasbitmask)) {
 
485
            newval = newval + (1L << len);
 
486
        }
 
487
 
 
488
        /* Keep only the high bits of the old value */
 
489
        lastTimestamp = lastTimestamp & ~majorasbitmask;
 
490
 
 
491
        /* Then add the low bits of the new value */
 
492
        lastTimestamp = lastTimestamp + newval;
 
493
 
 
494
        return lastTimestamp;
 
495
    }
 
496
 
 
497
    @Override
 
498
    public Definition lookupDefinition(String lookupPath) {
 
499
        // TODO Auto-generated method stub
 
500
        return null;
 
501
    }
 
502
 
 
503
    /**
 
504
     * Gets the stream event context definition (see CTF specs)
 
505
     *
 
506
     * @return the definition of the stream event context (the form not the
 
507
     *         content)
 
508
     */
 
509
    public StructDefinition getStreamEventContextDef() {
 
510
        return this.streamEventContextDef;
 
511
    }
 
512
 
 
513
    /**
 
514
     * Sets the stream event context definition
 
515
     *
 
516
     * @param streamEventContextDef
 
517
     *            The stream event context definition
 
518
     */
 
519
    public void setStreamEventContextDef(StructDefinition streamEventContextDef) {
 
520
        this.streamEventContextDef = streamEventContextDef;
 
521
    }
 
522
 
 
523
    /**
 
524
     * Gets the stream event header definition
 
525
     *
 
526
     * @return the stream event header definition
 
527
     */
 
528
    public StructDefinition getStreamEventHeaderDef() {
 
529
        return this.streamEventHeaderDef;
 
530
    }
 
531
 
 
532
    /**
 
533
     * Sets the stream event header definition
 
534
     *
 
535
     * @param streamEventHeaderDef
 
536
     *            the stream event header definition
 
537
     */
 
538
    public void setStreamEventHeaderDef(StructDefinition streamEventHeaderDef) {
 
539
        this.streamEventHeaderDef = streamEventHeaderDef;
 
540
    }
 
541
 
 
542
    /**
 
543
     * Sets the stream packet context definition
 
544
     *
 
545
     * @param streamPacketContextDef
 
546
     *            the stream packet context definition
 
547
     */
 
548
    public void setStreamPacketContextDef(
 
549
            StructDefinition streamPacketContextDef) {
 
550
        this.streamPacketContextDef = streamPacketContextDef;
 
551
    }
 
552
 
 
553
    /**
 
554
     * Gets the trace packet header definition
 
555
     *
 
556
     * @return the trace packet header definition
 
557
     */
 
558
    public StructDefinition getTracePacketHeaderDef() {
 
559
        return this.tracePacketHeaderDef;
 
560
    }
 
561
 
 
562
    /**
 
563
     * Sets the trace packet header definition
 
564
     *
 
565
     * @param tracePacketHeaderDef
 
566
     *            the trace packet header definition
 
567
     */
 
568
    public void setTracePacketHeaderDef(StructDefinition tracePacketHeaderDef) {
 
569
        this.tracePacketHeaderDef = tracePacketHeaderDef;
 
570
    }
 
571
 
 
572
    /**
 
573
     * @return the parent stream input reader
 
574
     */
 
575
    public StreamInputReader getStreamInputReader() {
 
576
        return this.streamInputReader;
 
577
    }
 
578
 
 
579
    /**
 
580
     *
 
581
     * @return THe bit buffer that reads the file.
 
582
     */
 
583
    public BitBuffer getBitBuffer() {
 
584
        return bitBuffer;
 
585
    }
 
586
}