| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Ericsson |
| 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: |
| 10 | * Matthew Khouzam - Initial API and implementation |
| 11 | *******************************************************************************/ |
| 12 | |
| 13 | package org.eclipse.tracecompass.internal.ctf.core.trace; |
| 14 | |
| 15 | import java.util.List; |
| 16 | |
| 17 | import org.eclipse.jdt.annotation.NonNullByDefault; |
| 18 | import org.eclipse.jdt.annotation.Nullable; |
| 19 | import org.eclipse.tracecompass.ctf.core.CTFException; |
| 20 | import org.eclipse.tracecompass.ctf.core.CTFStrings; |
| 21 | import org.eclipse.tracecompass.ctf.core.event.EventDefinition; |
| 22 | import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration; |
| 23 | import org.eclipse.tracecompass.ctf.core.event.LostEventDeclaration; |
| 24 | import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer; |
| 25 | import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope; |
| 26 | import org.eclipse.tracecompass.ctf.core.event.scope.ILexicalScope; |
| 27 | import org.eclipse.tracecompass.ctf.core.event.types.ICompositeDefinition; |
| 28 | import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; |
| 29 | import org.eclipse.tracecompass.ctf.core.event.types.IDefinition; |
| 30 | import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration; |
| 31 | import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration; |
| 32 | import org.eclipse.tracecompass.ctf.core.event.types.IntegerDefinition; |
| 33 | import org.eclipse.tracecompass.ctf.core.event.types.SimpleDatatypeDefinition; |
| 34 | import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; |
| 35 | import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition; |
| 36 | import org.eclipse.tracecompass.ctf.core.event.types.VariantDefinition; |
| 37 | import org.eclipse.tracecompass.ctf.core.trace.CTFIOException; |
| 38 | import org.eclipse.tracecompass.ctf.core.trace.ICTFPacketDescriptor; |
| 39 | import org.eclipse.tracecompass.ctf.core.trace.IPacketReader; |
| 40 | import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; |
| 41 | import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderDefinition; |
| 42 | |
| 43 | /** |
| 44 | * Packet reader with a fixed bit buffer, should be the fast and easily |
| 45 | * parallelizable one. |
| 46 | */ |
| 47 | @NonNullByDefault |
| 48 | public final class CTFPacketReader implements IPacketReader, IDefinitionScope { |
| 49 | |
| 50 | private static final IDefinitionScope EVENT_HEADER_SCOPE = new IDefinitionScope() { |
| 51 | |
| 52 | @Override |
| 53 | public @Nullable IDefinition lookupDefinition(@Nullable String lookupPath) { |
| 54 | return null; |
| 55 | } |
| 56 | |
| 57 | @Override |
| 58 | public @Nullable ILexicalScope getScopePath() { |
| 59 | return null; |
| 60 | } |
| 61 | }; |
| 62 | |
| 63 | private final BitBuffer fInput; |
| 64 | private final ICTFPacketDescriptor fPacketContext; |
| 65 | private final List<@Nullable IEventDeclaration> fDeclarations; |
| 66 | private boolean fHasLost; |
| 67 | private long fLastTimestamp; |
| 68 | private @Nullable final IDeclaration fStreamEventHeaderDecl; |
| 69 | |
| 70 | private @Nullable final StructDeclaration fStreamContext; |
| 71 | |
| 72 | private @Nullable final ICompositeDefinition fTracePacketHeader; |
| 73 | |
| 74 | private @Nullable final IDefinitionScope fPacketScope; |
| 75 | |
| 76 | private @Nullable ICompositeDefinition fEventHeader; |
| 77 | |
| 78 | /** |
| 79 | * Constructor |
| 80 | * |
| 81 | * @param input |
| 82 | * input {@link BitBuffer} |
| 83 | * @param packetContext |
| 84 | * packet_context where we get info like lost events and cpu_id |
| 85 | * @param declarations |
| 86 | * event declarations for this packet reader |
| 87 | * @param eventHeaderDeclaration |
| 88 | * event header declaration, what to read before any given event, |
| 89 | * to find it's id |
| 90 | * @param streamContext |
| 91 | * the context declaration |
| 92 | * @param packetHeader |
| 93 | * the header with the magic numbers and such |
| 94 | * @param packetScope |
| 95 | * the scope of the packetHeader |
| 96 | */ |
| 97 | public CTFPacketReader(BitBuffer input, ICTFPacketDescriptor packetContext, List<@Nullable IEventDeclaration> declarations, @Nullable IDeclaration eventHeaderDeclaration, @Nullable StructDeclaration streamContext, @Nullable ICompositeDefinition packetHeader, |
| 98 | IDefinitionScope packetScope) { |
| 99 | fInput = input; |
| 100 | fPacketContext = packetContext; |
| 101 | fDeclarations = declarations; |
| 102 | fPacketScope = packetScope; |
| 103 | fHasLost = fPacketContext.getLostEvents() != 0; |
| 104 | fLastTimestamp = fPacketContext.getTimestampBegin(); |
| 105 | fStreamEventHeaderDecl = eventHeaderDeclaration; |
| 106 | fStreamContext = streamContext; |
| 107 | fTracePacketHeader = packetHeader; |
| 108 | } |
| 109 | |
| 110 | @Override |
| 111 | public int getCPU() { |
| 112 | return (int) fPacketContext.getTargetId(); |
| 113 | } |
| 114 | |
| 115 | @Override |
| 116 | public boolean hasMoreEvents() { |
| 117 | return fHasLost || (fInput.position() < fPacketContext.getContentSizeBits()); |
| 118 | } |
| 119 | |
| 120 | @Override |
| 121 | public EventDefinition readNextEvent() throws CTFException { |
| 122 | int eventID = (int) IEventDeclaration.UNSET_EVENT_ID; |
| 123 | final long posStart = fInput.position(); |
| 124 | /* |
| 125 | * Return the Lost Event after all other events in this packet. We need |
| 126 | * to check if the bytebuffer is at the beginning too. |
| 127 | */ |
| 128 | if (fHasLost && (posStart >= fPacketContext.getContentSizeBits())) { |
| 129 | fHasLost = false; |
| 130 | return createLostEvent(fPacketContext); |
| 131 | } |
| 132 | |
| 133 | fEventHeader = null; |
| 134 | /* Read the stream event header. */ |
| 135 | final IDeclaration streamEventHeaderDecl = fStreamEventHeaderDecl; |
| 136 | if (streamEventHeaderDecl instanceof IEventHeaderDeclaration) { |
| 137 | IEventHeaderDeclaration eventHeaderDeclaration = (IEventHeaderDeclaration) streamEventHeaderDecl; |
| 138 | EventHeaderDefinition ehd = (EventHeaderDefinition) eventHeaderDeclaration.createDefinition(EVENT_HEADER_SCOPE, "", fInput); //$NON-NLS-1$ |
| 139 | fEventHeader = ehd; |
| 140 | eventID = ehd.getId(); |
| 141 | } else if (streamEventHeaderDecl instanceof StructDeclaration) { |
| 142 | StructDefinition structEventHeaderDef = ((StructDeclaration) streamEventHeaderDecl).createDefinition(EVENT_HEADER_SCOPE, ILexicalScope.EVENT_HEADER, fInput); |
| 143 | fEventHeader = structEventHeaderDef; |
| 144 | /* Check for the event id. */ |
| 145 | IDefinition idDef = structEventHeaderDef.lookupDefinition("id"); //$NON-NLS-1$ |
| 146 | SimpleDatatypeDefinition simpleIdDef = null; |
| 147 | if (idDef instanceof SimpleDatatypeDefinition) { |
| 148 | simpleIdDef = ((SimpleDatatypeDefinition) idDef); |
| 149 | } else if (idDef != null) { |
| 150 | throw new CTFIOException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$ |
| 151 | } |
| 152 | /* Check for the variant v. */ |
| 153 | IDefinition variantDef = structEventHeaderDef.lookupDefinition("v"); //$NON-NLS-1$ |
| 154 | if (variantDef instanceof VariantDefinition) { |
| 155 | |
| 156 | /* Get the variant current field */ |
| 157 | StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField(); |
| 158 | |
| 159 | /* |
| 160 | * Try to get the id field in the current field of the variant. |
| 161 | * If it is present, it overrides the previously read event id. |
| 162 | */ |
| 163 | IDefinition vIdDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$ |
| 164 | if (vIdDef instanceof IntegerDefinition) { |
| 165 | simpleIdDef = (SimpleDatatypeDefinition) vIdDef; |
| 166 | } |
| 167 | |
| 168 | } |
| 169 | if (simpleIdDef != null) { |
| 170 | eventID = simpleIdDef.getIntegerValue().intValue(); |
| 171 | } |
| 172 | } |
| 173 | /* Single event type in a trace */ |
| 174 | if (eventID == IEventDeclaration.UNSET_EVENT_ID && fDeclarations.size() == 1) { |
| 175 | eventID = 0; |
| 176 | } |
| 177 | /* Get the right event definition using the event id. */ |
| 178 | IEventDeclaration eventDeclaration = fDeclarations.get(eventID); |
| 179 | if (!(eventDeclaration instanceof EventDeclaration)) { |
| 180 | throw new CTFIOException("Incorrect event id : " + eventID); //$NON-NLS-1$ |
| 181 | } |
| 182 | EventDeclaration declaration = (EventDeclaration) eventDeclaration; |
| 183 | EventDefinition eventDef = declaration.createDefinition(fStreamContext, fPacketContext, fTracePacketHeader, fEventHeader, fInput, fLastTimestamp); |
| 184 | fLastTimestamp = eventDef.getTimestamp(); |
| 185 | /* |
| 186 | * Set the event timestamp using the timestamp calculated by |
| 187 | * updateTimestamp. |
| 188 | */ |
| 189 | |
| 190 | if (posStart == fInput.position()) { |
| 191 | throw new CTFIOException("Empty event not allowed, event: " + eventDef.getDeclaration().getName()); //$NON-NLS-1$ |
| 192 | } |
| 193 | |
| 194 | return eventDef; |
| 195 | } |
| 196 | |
| 197 | private EventDefinition createLostEvent(final ICTFPacketDescriptor currentPacket) { |
| 198 | IEventDeclaration lostEventDeclaration = LostEventDeclaration.INSTANCE; |
| 199 | StructDeclaration lostFields = lostEventDeclaration.getFields(); |
| 200 | // this is a hard coded map, we know it's not null |
| 201 | IntegerDeclaration lostFieldsDecl = (IntegerDeclaration) lostFields.getField(CTFStrings.LOST_EVENTS_FIELD); |
| 202 | if (lostFieldsDecl == null) { |
| 203 | throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$ |
| 204 | } |
| 205 | IntegerDeclaration lostEventsDurationDecl = (IntegerDeclaration) lostFields.getField(CTFStrings.LOST_EVENTS_DURATION); |
| 206 | if (lostEventsDurationDecl == null) { |
| 207 | throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$ |
| 208 | } |
| 209 | long lostEventsTimestamp = fLastTimestamp; |
| 210 | long lostEventsDuration = currentPacket.getTimestampEnd() - lostEventsTimestamp; |
| 211 | IntegerDefinition lostDurationDef = new IntegerDefinition(lostFieldsDecl, null, CTFStrings.LOST_EVENTS_DURATION, lostEventsDuration); |
| 212 | IntegerDefinition lostCountDef = new IntegerDefinition(lostEventsDurationDecl, null, CTFStrings.LOST_EVENTS_FIELD, fPacketContext.getLostEvents()); |
| 213 | IntegerDefinition[] fields = new IntegerDefinition[] { lostCountDef, lostDurationDef }; |
| 214 | int cpu = (int) fPacketContext.getTargetId(); |
| 215 | return new EventDefinition( |
| 216 | lostEventDeclaration, |
| 217 | cpu, |
| 218 | lostEventsTimestamp, |
| 219 | null, |
| 220 | null, |
| 221 | null, |
| 222 | null, |
| 223 | new StructDefinition( |
| 224 | lostFields, |
| 225 | this, "fields", //$NON-NLS-1$ |
| 226 | fields), |
| 227 | fPacketContext); |
| 228 | } |
| 229 | |
| 230 | @Override |
| 231 | public ILexicalScope getScopePath() { |
| 232 | return ILexicalScope.PACKET; |
| 233 | } |
| 234 | |
| 235 | @Override |
| 236 | public @Nullable IDefinition lookupDefinition(@Nullable String lookupPath) { |
| 237 | if (ILexicalScope.TRACE_PACKET_HEADER.getPath().equals(lookupPath)) { |
| 238 | return fTracePacketHeader; |
| 239 | } else if (ILexicalScope.STREAM_PACKET_CONTEXT.getPath().equals(lookupPath) && fPacketScope != null) { |
| 240 | return fPacketScope.lookupDefinition(lookupPath); |
| 241 | } |
| 242 | return null; |
| 243 | } |
| 244 | |
| 245 | @Override |
| 246 | public ICTFPacketDescriptor getCurrentPacket() { |
| 247 | return fPacketContext; |
| 248 | } |
| 249 | |
| 250 | /** |
| 251 | * TODO: remove when API is reworked a bit. |
| 252 | */ |
| 253 | @Override |
| 254 | public @Nullable ICompositeDefinition getCurrentPacketEventHeader() { |
| 255 | return fEventHeader; |
| 256 | } |
| 257 | |
| 258 | } |