/******************************************************************************* * Copyright (c) 2015 Ericsson * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Matthew Khouzam - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.internal.ctf.core.trace; import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.ctf.core.CTFException; import org.eclipse.tracecompass.ctf.core.CTFStrings; import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration; import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer; import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope; import org.eclipse.tracecompass.ctf.core.event.scope.ILexicalScope; import org.eclipse.tracecompass.ctf.core.event.types.ICompositeDefinition; import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.IDefinition; import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.IntegerDefinition; import org.eclipse.tracecompass.ctf.core.event.types.SimpleDatatypeDefinition; import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition; import org.eclipse.tracecompass.ctf.core.event.types.VariantDefinition; import org.eclipse.tracecompass.ctf.core.trace.CTFIOException; import org.eclipse.tracecompass.ctf.core.trace.ICTFPacketDescriptor; import org.eclipse.tracecompass.ctf.core.trace.IPacketReader; import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; import org.eclipse.tracecompass.internal.ctf.core.event.EventDefinition; import org.eclipse.tracecompass.internal.ctf.core.event.LostEventDeclaration; import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderDefinition; /** * Packet reader with a fixed bit buffer, should be the fast and easily * parallelizable one. */ @NonNullByDefault public final class CTFPacketReader implements IPacketReader, IDefinitionScope { private static final IDefinitionScope EVENT_HEADER_SCOPE = new IDefinitionScope() { @Override public @Nullable IDefinition lookupDefinition(@Nullable String lookupPath) { return null; } @Override public @Nullable ILexicalScope getScopePath() { return null; } }; private final BitBuffer fInput; private final ICTFPacketDescriptor fPacketContext; private final List<@Nullable IEventDeclaration> fDeclarations; private boolean fHasLost; private long fLastTimestamp; private @Nullable final IDeclaration fStreamEventHeaderDecl; private @Nullable final StructDeclaration fStreamContext; private @Nullable final ICompositeDefinition fTracePacketHeader; private @Nullable final IDefinitionScope fPacketScope; private @Nullable ICompositeDefinition fEventHeader; /** * Constructor * * @param input * input {@link BitBuffer} * @param packetContext * packet_context where we get info like lost events and cpu_id * @param declarations * event declarations for this packet reader * @param eventHeaderDeclaration * event header declaration, what to read before any given event, * to find it's id * @param streamContext * the context declaration * @param packetHeader * the header with the magic numbers and such * @param packetScope * the scope of the packetHeader */ public CTFPacketReader(BitBuffer input, ICTFPacketDescriptor packetContext, List<@Nullable IEventDeclaration> declarations, @Nullable IDeclaration eventHeaderDeclaration, @Nullable StructDeclaration streamContext, @Nullable ICompositeDefinition packetHeader, IDefinitionScope packetScope) { fInput = input; fPacketContext = packetContext; fDeclarations = declarations; fPacketScope = packetScope; fHasLost = fPacketContext.getLostEvents() != 0; fLastTimestamp = fPacketContext.getTimestampBegin(); fStreamEventHeaderDecl = eventHeaderDeclaration; fStreamContext = streamContext; fTracePacketHeader = packetHeader; } @Override public int getCPU() { return (int) fPacketContext.getTargetId(); } @Override public boolean hasMoreEvents() { return fHasLost || (fInput.position() < fPacketContext.getContentSizeBits()); } @Override public EventDefinition readNextEvent() throws CTFException { int eventID = (int) IEventDeclaration.UNSET_EVENT_ID; final long posStart = fInput.position(); /* * Return the Lost Event after all other events in this packet. We need * to check if the bytebuffer is at the beginning too. */ if (fHasLost && (posStart >= fPacketContext.getContentSizeBits())) { fHasLost = false; return createLostEvent(fPacketContext); } fEventHeader = null; /* Read the stream event header. */ final IDeclaration streamEventHeaderDecl = fStreamEventHeaderDecl; if (streamEventHeaderDecl instanceof IEventHeaderDeclaration) { IEventHeaderDeclaration eventHeaderDeclaration = (IEventHeaderDeclaration) streamEventHeaderDecl; EventHeaderDefinition ehd = (EventHeaderDefinition) eventHeaderDeclaration.createDefinition(EVENT_HEADER_SCOPE, "", fInput); //$NON-NLS-1$ fEventHeader = ehd; eventID = ehd.getId(); } else if (streamEventHeaderDecl instanceof StructDeclaration) { StructDefinition structEventHeaderDef = ((StructDeclaration) streamEventHeaderDecl).createDefinition(EVENT_HEADER_SCOPE, ILexicalScope.EVENT_HEADER, fInput); fEventHeader = structEventHeaderDef; /* Check for the event id. */ IDefinition idDef = structEventHeaderDef.lookupDefinition("id"); //$NON-NLS-1$ SimpleDatatypeDefinition simpleIdDef = null; if (idDef instanceof SimpleDatatypeDefinition) { simpleIdDef = ((SimpleDatatypeDefinition) idDef); } else if (idDef != null) { throw new CTFIOException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$ } /* Check for the variant v. */ IDefinition variantDef = structEventHeaderDef.lookupDefinition("v"); //$NON-NLS-1$ if (variantDef instanceof VariantDefinition) { /* Get the variant current field */ StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField(); /* * Try to get the id field in the current field of the variant. * If it is present, it overrides the previously read event id. */ IDefinition vIdDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$ if (vIdDef instanceof IntegerDefinition) { simpleIdDef = (SimpleDatatypeDefinition) vIdDef; } } if (simpleIdDef != null) { eventID = simpleIdDef.getIntegerValue().intValue(); } } /* Single event type in a trace */ if (eventID == IEventDeclaration.UNSET_EVENT_ID && fDeclarations.size() == 1) { eventID = 0; } /* Get the right event definition using the event id. */ IEventDeclaration eventDeclaration = fDeclarations.get(eventID); if (!(eventDeclaration instanceof EventDeclaration)) { throw new CTFIOException("Incorrect event id : " + eventID); //$NON-NLS-1$ } EventDeclaration declaration = (EventDeclaration) eventDeclaration; EventDefinition eventDef = declaration.createDefinition(fStreamContext, fPacketContext, fTracePacketHeader, fEventHeader, fInput, fLastTimestamp); fLastTimestamp = eventDef.getTimestamp(); /* * Set the event timestamp using the timestamp calculated by * updateTimestamp. */ if (posStart == fInput.position()) { throw new CTFIOException("Empty event not allowed, event: " + eventDef.getDeclaration().getName()); //$NON-NLS-1$ } return eventDef; } private EventDefinition createLostEvent(final ICTFPacketDescriptor currentPacket) { IEventDeclaration lostEventDeclaration = LostEventDeclaration.INSTANCE; StructDeclaration lostFields = lostEventDeclaration.getFields(); // this is a hard coded map, we know it's not null IntegerDeclaration lostFieldsDecl = (IntegerDeclaration) lostFields.getField(CTFStrings.LOST_EVENTS_FIELD); if (lostFieldsDecl == null) { throw new IllegalStateException("Lost events count not declared!"); //$NON-NLS-1$ } IntegerDeclaration lostEventsDurationDecl = (IntegerDeclaration) lostFields.getField(CTFStrings.LOST_EVENTS_DURATION); if (lostEventsDurationDecl == null) { throw new IllegalStateException("Lost events duration not declared!"); //$NON-NLS-1$ } long lostEventsTimestamp = fLastTimestamp; long lostEventsDuration = currentPacket.getTimestampEnd() - lostEventsTimestamp; IntegerDefinition lostDurationDef = new IntegerDefinition(lostFieldsDecl, null, CTFStrings.LOST_EVENTS_DURATION, lostEventsDuration); IntegerDefinition lostCountDef = new IntegerDefinition(lostEventsDurationDecl, null, CTFStrings.LOST_EVENTS_FIELD, fPacketContext.getLostEvents()); IntegerDefinition[] fields = new IntegerDefinition[] { lostCountDef, lostDurationDef }; int cpu = (int) fPacketContext.getTargetId(); return new EventDefinition( lostEventDeclaration, cpu, lostEventsTimestamp, null, null, null, null, new StructDefinition( lostFields, this, "fields", //$NON-NLS-1$ fields), fPacketContext); } @Override public ILexicalScope getScopePath() { return ILexicalScope.PACKET; } @Override public @Nullable IDefinition lookupDefinition(@Nullable String lookupPath) { if (ILexicalScope.TRACE_PACKET_HEADER.getPath().equals(lookupPath)) { return fTracePacketHeader; } else if (ILexicalScope.STREAM_PACKET_CONTEXT.getPath().equals(lookupPath) && fPacketScope != null) { return fPacketScope.lookupDefinition(lookupPath); } return null; } @Override public ICTFPacketDescriptor getCurrentPacket() { return fPacketContext; } /** * TODO: remove when API is reworked a bit. */ @Override public @Nullable ICompositeDefinition getCurrentPacketEventHeader() { return fEventHeader; } }