/******************************************************************************* * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others * * 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 * Contributors: Simon Marchi - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.internal.ctf.core.trace; import java.util.AbstractMap; import java.util.Collections; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.tracecompass.common.core.NonNullUtils; import org.eclipse.tracecompass.ctf.core.CTFStrings; import org.eclipse.tracecompass.ctf.core.event.types.EnumDefinition; import org.eclipse.tracecompass.ctf.core.event.types.FloatDefinition; import org.eclipse.tracecompass.ctf.core.event.types.IDefinition; 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.StringDefinition; import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition; import org.eclipse.tracecompass.ctf.core.trace.ICTFPacketDescriptor; import org.eclipse.tracecompass.ctf.core.trace.IPacketReader; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; /** * <b><u>StreamInputPacketIndexEntry</u></b> * <p> * Represents an entry in the index of event packets. */ public class StreamInputPacketIndexEntry implements ICTFPacketDescriptor { private static final Pattern NUMBER_PATTERN = Pattern.compile("\\D*(\\d+)"); //$NON-NLS-1$ // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ /** * Position of the start of the packet header in the file, in bits */ private final long fOffsetBits; /** * Position of the start of the packet header in the file, in bytes */ private final long fOffsetBytes; /** * Packet size, in bits */ private final long fPacketSizeBits; /** * Content size, in bits */ private final long fContentSizeBits; /** * Begin timestamp */ private final long fTimestampBegin; /** * End timestamp */ private final long fTimestampEnd; /** * How many lost events are there? */ private final long fLostEvents; /** * Which target is being traced */ private final String fTarget; private final long fTargetID; /** * Attributes of this index entry */ private final @NonNull Map<String, Object> fAttributes; private final long fEndPacketHeaderBits; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Constructs an index entry. * * @param dataOffsetBits * offset in the file for the start of data in bits * @param fileSizeBytes * number of bytes in a file * * TODO: Remove */ public StreamInputPacketIndexEntry(long dataOffsetBits, long fileSizeBytes) { fAttributes = Collections.EMPTY_MAP; fContentSizeBits = (fileSizeBytes * Byte.SIZE); fPacketSizeBits = (fileSizeBytes * Byte.SIZE); fOffsetBits = dataOffsetBits; fOffsetBytes = dataOffsetBits / Byte.SIZE; fLostEvents = 0; fTarget = ""; //$NON-NLS-1$ fTargetID = 0; fTimestampBegin = 0; fTimestampEnd = Long.MAX_VALUE; fEndPacketHeaderBits = dataOffsetBits; } /** * full Constructor * * @param dataOffsetBits * offset in the file for the start of data in bits * @param streamPacketContextDef * packet context * @param fileSizeBytes * number of bytes in a file * @param lostSoFar * number of lost events so far * * TODO: Remove */ public StreamInputPacketIndexEntry(long dataOffsetBits, StructDefinition streamPacketContextDef, long fileSizeBytes, long lostSoFar) { this(dataOffsetBits, streamPacketContextDef, fileSizeBytes, lostSoFar, dataOffsetBits); } /** * full Constructor * * @param dataOffsetBits * offset in the file for the start of data in bits * @param streamPacketContextDef * packet context * @param fileSizeBytes * number of bytes in a file * @param lostSoFar * number of lost events so far * @param endPacketHeaderBits * end of packet headers */ public StreamInputPacketIndexEntry(long dataOffsetBits, StructDefinition streamPacketContextDef, long fileSizeBytes, long lostSoFar, long endPacketHeaderBits) { fEndPacketHeaderBits = endPacketHeaderBits; fAttributes = computeAttributeMap(streamPacketContextDef); fContentSizeBits = computeContentSize(fileSizeBytes); fPacketSizeBits = computePacketSize(fileSizeBytes); fTimestampBegin = computeTsBegin(); fTimestampEnd = computeTsEnd(); fOffsetBits = dataOffsetBits; fOffsetBytes = dataOffsetBits / Byte.SIZE; // LTTng Specific Target target = lookupTarget(streamPacketContextDef); fTarget = target.string; fTargetID = target.number; fLostEvents = computeLostEvents(lostSoFar); } /** * Copy constructor that updates the timestamp end * * @param entryToAdd * the original {@link StreamInputPacketIndexEntry} * @param newTimestampEnd * the new timestamp end */ public StreamInputPacketIndexEntry(ICTFPacketDescriptor entryToAdd, long newTimestampEnd) { fEndPacketHeaderBits = entryToAdd.getPayloadStartBits(); fAttributes = entryToAdd.getAttributes(); fContentSizeBits = entryToAdd.getContentSizeBits(); fPacketSizeBits = entryToAdd.getPacketSizeBits(); fTimestampBegin = entryToAdd.getTimestampBegin(); fTimestampEnd = newTimestampEnd; fOffsetBits = entryToAdd.getOffsetBits(); fOffsetBytes = entryToAdd.getOffsetBits(); // LTTng Specific fTarget = entryToAdd.getTarget(); fTargetID = entryToAdd.getTargetId(); Target target = new Target(); target.number = fTargetID; target.string = fTarget; fLostEvents = entryToAdd.getLostEvents(); } private static @NonNull Map<String, Object> computeAttributeMap(StructDefinition streamPacketContextDef) { Builder<String, Object> attributeBuilder = ImmutableMap.<String, Object> builder(); for (String field : streamPacketContextDef.getDeclaration().getFieldsList()) { IDefinition id = streamPacketContextDef.lookupDefinition(field); if (id instanceof IntegerDefinition) { attributeBuilder.put(field, ((IntegerDefinition) id).getValue()); } else if (id instanceof FloatDefinition) { attributeBuilder.put(field, ((FloatDefinition) id).getValue()); } else if (id instanceof EnumDefinition) { final EnumDefinition enumDec = (EnumDefinition) id; attributeBuilder.put(field, new AbstractMap.SimpleImmutableEntry<>( NonNullUtils.checkNotNull(enumDec.getStringValue()), NonNullUtils.checkNotNull(enumDec.getIntegerValue()))); } else if (id instanceof StringDefinition) { attributeBuilder.put(field, ((StringDefinition) id).getValue()); } } return attributeBuilder.build(); } private Long getPacketSize() { return (Long) fAttributes.get(CTFStrings.PACKET_SIZE); } private long computeContentSize(long fileSizeBytes) { Long contentSize = (Long) fAttributes.get(CTFStrings.CONTENT_SIZE); /* Read the content size in bits */ if (contentSize != null) { return contentSize.longValue(); } Long packetSize = getPacketSize(); if (packetSize != null) { return packetSize.longValue(); } return fileSizeBytes * Byte.SIZE; } private long computePacketSize(long fileSizeBytes) { Long packetSize = getPacketSize(); /* Read the packet size in bits */ if (packetSize != null) { return packetSize.longValue(); } long contentSizeBits = computeContentSize(fileSizeBytes); if (contentSizeBits != 0) { return contentSizeBits; } return fileSizeBytes * Byte.SIZE; } private long computeTsBegin() { Long tsBegin = (Long) fAttributes.get(CTFStrings.TIMESTAMP_BEGIN); /* Read the begin timestamp */ if (tsBegin != null) { return tsBegin.longValue(); } return 0; } private long computeTsEnd() { Long tsEnd = (Long) fAttributes.get(CTFStrings.TIMESTAMP_END); /* Read the end timestamp */ if (tsEnd != null) { // check if tsEnd == unsigned long max value if (tsEnd == -1) { return Long.MAX_VALUE; } return tsEnd.longValue(); } return Long.MAX_VALUE; } private long computeLostEvents(long lostSoFar) { Long lostEvents = (Long) fAttributes.get(CTFStrings.EVENTS_DISCARDED); if (lostEvents != null) { return lostEvents - lostSoFar; } return 0; } private static class Target { public String string; public long number; public Target() { string = null; number = IPacketReader.UNKNOWN_CPU; } } private Target lookupTarget(StructDefinition streamPacketContextDef) { Target ret = new Target(); boolean hasDevice = fAttributes.containsKey(CTFStrings.DEVICE); if (hasDevice) { IDefinition def = streamPacketContextDef.lookupDefinition(CTFStrings.DEVICE); if (def instanceof SimpleDatatypeDefinition) { SimpleDatatypeDefinition simpleDefinition = (SimpleDatatypeDefinition) def; ret.string = simpleDefinition.getStringValue(); ret.number = simpleDefinition.getIntegerValue(); } else if (def instanceof StringDefinition) { StringDefinition stringDefinition = (StringDefinition) def; ret.string = stringDefinition.getValue(); final Matcher matcher = NUMBER_PATTERN.matcher(ret.string); if (matcher.matches()) { String number = matcher.group(1); ret.number = Integer.parseInt(number); } } } else { Long cpuId = (Long) fAttributes.get(CTFStrings.CPU_ID); if (cpuId != null) { ret.string = ("CPU" + cpuId.toString()); //$NON-NLS-1$ ret.number = cpuId; } } return ret; } // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ @Override public boolean includes(long ts) { return (ts >= fTimestampBegin) && (ts <= fTimestampEnd); } @Override public String toString() { return "StreamInputPacketIndexEntry [offsetBits=" + fOffsetBits //$NON-NLS-1$ + ", timestampBegin=" + fTimestampBegin + ", timestampEnd=" //$NON-NLS-1$ //$NON-NLS-2$ + fTimestampEnd + "]"; //$NON-NLS-1$ } // ------------------------------------------------------------------------ // Getters and Setters // ------------------------------------------------------------------------ @Override public long getOffsetBits() { return fOffsetBits; } @Override public long getPacketSizeBits() { return fPacketSizeBits; } @Override public long getContentSizeBits() { return fContentSizeBits; } @Override public long getTimestampBegin() { return fTimestampBegin; } @Override public long getTimestampEnd() { return fTimestampEnd; } @Override public long getLostEvents() { return fLostEvents; } @Override public Map<String, Object> getAttributes() { return fAttributes; } @Override public String getTarget() { return fTarget; } @Override public long getTargetId() { return fTargetID; } @Override public long getOffsetBytes() { return fOffsetBytes; } @Override public long getPayloadStartBits() { return fEndPacketHeaderBits; } }