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