Merge master in TmfTraceModel
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / internal / ctf / core / trace / StreamInput.java
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
13 package org.eclipse.linuxtools.internal.ctf.core.trace;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.nio.MappedByteBuffer;
18 import java.nio.channels.FileChannel;
19 import java.nio.channels.FileChannel.MapMode;
20 import java.util.UUID;
21
22 import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition;
23 import org.eclipse.linuxtools.ctf.core.event.types.Definition;
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.StructDefinition;
27 import org.eclipse.linuxtools.ctf.core.trace.CTFReaderException;
28 import org.eclipse.linuxtools.ctf.core.trace.Utils;
29 import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
30
31 /**
32 * <b><u>StreamInput</u></b>
33 * <p>
34 * Represents a trace file that belongs to a certain stream.
35 */
36 public class StreamInput implements IDefinitionScope {
37
38 // ------------------------------------------------------------------------
39 // Attributes
40 // ------------------------------------------------------------------------
41
42 /**
43 * The associated Stream
44 */
45 private final Stream stream;
46
47 /**
48 * FileChannel to the trace file
49 */
50 private final FileChannel fileChannel;
51
52 /**
53 * Information on the file (used for debugging)
54 */
55 public final File file;
56
57 /**
58 * The packet index of this input
59 */
60 private final StreamInputPacketIndex index = new StreamInputPacketIndex();
61
62 private long timestampEnd;
63
64 // ------------------------------------------------------------------------
65 // Constructors
66 // ------------------------------------------------------------------------
67
68 /**
69 * Constructs a StreamInput.
70 *
71 * @param stream
72 * The stream to which this StreamInput belongs to.
73 * @param fileChannel
74 * The FileChannel to the trace file.
75 * @param file
76 * Information about the trace file (for debugging purposes).
77 */
78 public StreamInput(Stream stream, FileChannel fileChannel, File file) {
79 this.stream = stream;
80 this.fileChannel = fileChannel;
81 this.file = file;
82 }
83
84 // ------------------------------------------------------------------------
85 // Getters/Setters/Predicates
86 // ------------------------------------------------------------------------
87
88 public Stream getStream() {
89 return stream;
90 }
91
92 public StreamInputPacketIndex getIndex() {
93 return index;
94 }
95
96 public FileChannel getFileChannel() {
97 return fileChannel;
98 }
99
100 public String getFilename() {
101 return file.getName();
102 }
103
104 public long getTimestampEnd() {
105 return timestampEnd;
106 }
107
108 public void setTimestampEnd(long timestampEnd) {
109 this.timestampEnd = timestampEnd;
110 }
111
112 @Override
113 public String getPath() {
114 return ""; //$NON-NLS-1$
115 }
116
117 // ------------------------------------------------------------------------
118 // Operations
119 // ------------------------------------------------------------------------
120
121 @SuppressWarnings("unused")
122 @Override
123 public Definition lookupDefinition(String lookupPath) {
124 /* TODO: lookup in different dynamic scopes is not supported yet. */
125 return null;
126 }
127
128 /**
129 * Create the index for this trace file.
130 *
131 * @throws CTFReaderException
132 */
133 public void createIndex() throws CTFReaderException {
134 /*
135 * The size of the file in bytes
136 */
137 long fileSizeBytes = 0;
138 try {
139 fileSizeBytes = fileChannel.size();
140 } catch (IOException e) {
141 throw new CTFReaderException(e);
142 }
143
144 /*
145 * Offset of the current packet in bytes
146 */
147 long packetOffsetBytes = 0;
148
149 /*
150 * Initial size, it should map at least the packet header + context
151 * size.
152 *
153 * TODO: use a less arbitrary size.
154 */
155 long mapSize = 4096;
156
157 /*
158 * Definition of trace packet header
159 */
160 StructDefinition tracePacketHeaderDef = null;
161
162 /*
163 * Definition of trace stream packet context
164 */
165 StructDefinition streamPacketContextDef = null;
166
167 /*
168 * The BitBuffer to extract data from the StreamInput
169 */
170 BitBuffer bitBuffer = new BitBuffer();
171 bitBuffer.order(this.getStream().getTrace().getByteOrder());
172
173 /*
174 * Create the definitions we need to read the packet headers + contexts
175 */
176 if (getStream().getTrace().getPacketHeader() != null) {
177 tracePacketHeaderDef = getStream().getTrace().getPacketHeader()
178 .createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
179 }
180
181 if (getStream().getPacketContextDecl() != null) {
182 streamPacketContextDef = getStream().getPacketContextDecl()
183 .createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
184 }
185
186 /*
187 * Scan through the packets of the file.
188 */
189 while (packetOffsetBytes < fileSizeBytes) {
190 /*
191 * If there is less data remaining than what we want to map, reduce
192 * the map size.
193 */
194 if ((fileSizeBytes - packetOffsetBytes) < mapSize) {
195 mapSize = fileSizeBytes - packetOffsetBytes;
196 }
197
198 /*
199 * Map the packet.
200 */
201 MappedByteBuffer bb;
202 try {
203 bb = fileChannel.map(MapMode.READ_ONLY, packetOffsetBytes,
204 mapSize);
205 } catch (IOException e) {
206 throw new CTFReaderException(e);
207 }
208 bitBuffer.setByteBuffer(bb);
209
210 /*
211 * Create the index entry
212 */
213 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
214 packetOffsetBytes);
215
216 /*
217 * Read the trace packet header if it exists.
218 */
219 if (tracePacketHeaderDef != null) {
220 tracePacketHeaderDef.read(bitBuffer);
221
222 /*
223 * Check the CTF magic number
224 */
225 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
226 .lookupDefinition("magic"); //$NON-NLS-1$
227 if (magicDef != null) {
228 int magic = (int) magicDef.getValue();
229 if (magic != Utils.CTF_MAGIC) {
230 throw new CTFReaderException(
231 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
232 }
233
234 }
235
236 /*
237 * Check the trace UUID
238 */
239 ArrayDefinition uuidDef = (ArrayDefinition) tracePacketHeaderDef
240 .lookupDefinition("uuid"); //$NON-NLS-1$
241 if (uuidDef != null) {
242 byte[] uuidArray = new byte[16];
243
244 for (int i = 0; i < 16; i++) {
245 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef
246 .getElem(i);
247 uuidArray[i] = (byte) uuidByteDef.getValue();
248 }
249
250 UUID uuid = Utils.makeUUID(uuidArray);
251
252 if (!getStream().getTrace().getUUID().equals(uuid)) {
253 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
254 }
255 }
256
257 /*
258 * Check that the stream id did not change
259 */
260 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
261 .lookupDefinition("stream_id"); //$NON-NLS-1$
262 if (streamIDDef != null) {
263 long streamID = streamIDDef.getValue();
264
265 if (streamID != getStream().getId()) {
266 throw new CTFReaderException(
267 "Stream ID changing within a StreamInput"); //$NON-NLS-1$
268 }
269 }
270 }
271
272 /*
273 * Read the stream packet context if it exists.
274 */
275 if (streamPacketContextDef != null) {
276 streamPacketContextDef.read(bitBuffer);
277
278 /*
279 * Read the content size in bits
280 */
281 IntegerDefinition contentSizeDef = (IntegerDefinition) streamPacketContextDef
282 .lookupDefinition("content_size"); //$NON-NLS-1$
283 if (contentSizeDef != null) {
284 packetIndex.setContentSizeBits((int) contentSizeDef
285 .getValue());
286 } else {
287 packetIndex.setContentSizeBits((int) (fileSizeBytes * 8));
288 }
289
290 /*
291 * Read the packet size in bits
292 */
293 IntegerDefinition packetSizeDef = (IntegerDefinition) streamPacketContextDef
294 .lookupDefinition("packet_size"); //$NON-NLS-1$
295 if (packetSizeDef != null) {
296 packetIndex.setPacketSizeBits((int) packetSizeDef
297 .getValue());
298 } else {
299 if (packetIndex.getContentSizeBits() != 0) {
300 packetIndex.setPacketSizeBits(packetIndex
301 .getContentSizeBits());
302 } else {
303 packetIndex
304 .setPacketSizeBits((int) (fileSizeBytes * 8));
305 }
306 }
307
308 /*
309 * Read the begin timestamp
310 */
311 IntegerDefinition timestampBeginDef = (IntegerDefinition) streamPacketContextDef
312 .lookupDefinition("timestamp_begin"); //$NON-NLS-1$
313 if (timestampBeginDef != null) {
314 packetIndex.setTimestampBegin( timestampBeginDef.getValue());
315 }
316
317 /*
318 * Read the end timestamp
319 */
320 IntegerDefinition timestampEndDef = (IntegerDefinition) streamPacketContextDef
321 .lookupDefinition("timestamp_end"); //$NON-NLS-1$
322 if (timestampEndDef != null) {
323 packetIndex.setTimestampEnd(timestampEndDef
324 .getValue());
325 setTimestampEnd(packetIndex.getTimestampEnd());
326 }
327 } else {
328 /*
329 * If there is no packet context, infer the content and packet
330 * size from the file size (assume that there is only one packet
331 * and no padding)
332 */
333 packetIndex.setContentSizeBits( (int) (fileSizeBytes * 8));
334 packetIndex.setPacketSizeBits( (int) (fileSizeBytes * 8));
335 }
336
337 /* Basic validation */
338 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
339 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
340 }
341
342 if (packetIndex.getPacketSizeBits() > ((fileSizeBytes - packetIndex.getOffsetBytes()) * 8)) {
343 throw new CTFReaderException(
344 "Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
345 }
346
347 /*
348 * Offset in the file, in bits
349 */
350 packetIndex.setDataOffsetBits( bitBuffer.position());
351
352 /*
353 * Add the packet index entry to the index
354 */
355 index.addEntry(packetIndex);
356
357 /*
358 * Update the counting packet offset
359 */
360 packetOffsetBytes += (packetIndex.getPacketSizeBits() + 7) / 8;
361
362 }
363 index.getEntries().get(0).setIndexBegin(0L);
364 }
365
366 }
This page took 0.038628 seconds and 5 git commands to generate.