| /******************************************************************************* |
| * 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 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * 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; |
| |
| private final StructDefinition fStreamPacketContextDef; |
| |
| // ------------------------------------------------------------------------ |
| // 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.emptyMap(); |
| fContentSizeBits = (fileSizeBytes * Byte.SIZE); |
| fPacketSizeBits = (fileSizeBytes * Byte.SIZE); |
| fOffsetBits = dataOffsetBits; |
| fOffsetBytes = bitsToBytes(dataOffsetBits); |
| fLostEvents = 0; |
| fTarget = ""; //$NON-NLS-1$ |
| fTargetID = 0; |
| fTimestampBegin = 0; |
| fTimestampEnd = Long.MAX_VALUE; |
| fEndPacketHeaderBits = dataOffsetBits; |
| fStreamPacketContextDef = null; |
| } |
| |
| private static long bitsToBytes(long value) { |
| return (long) Math.ceil(value / (double) Byte.SIZE); |
| } |
| |
| /** |
| * 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) { |
| fStreamPacketContextDef = streamPacketContextDef; |
| fEndPacketHeaderBits = endPacketHeaderBits; |
| fAttributes = computeAttributeMap(streamPacketContextDef); |
| fContentSizeBits = computeContentSize(fileSizeBytes); |
| fPacketSizeBits = computePacketSize(fileSizeBytes); |
| fTimestampBegin = computeTsBegin(); |
| fTimestampEnd = computeTsEnd(); |
| fOffsetBits = dataOffsetBits; |
| fOffsetBytes = bitsToBytes(dataOffsetBits); |
| |
| // LTTng Specific |
| Target target = lookupTarget(streamPacketContextDef); |
| fTarget = target.getLabel(); |
| fTargetID = target.getNumber(); |
| 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) { |
| if (entryToAdd instanceof StreamInputPacketIndexEntry) { |
| fStreamPacketContextDef = ((StreamInputPacketIndexEntry) entryToAdd).getStreamPacketContextDef(); |
| } else { |
| fStreamPacketContextDef = null; |
| } |
| |
| 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(); |
| 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 { |
| private String fLabel; |
| private long fNumber; |
| |
| public Target(String target, long targetID) { |
| fLabel = target; |
| fNumber = targetID; |
| } |
| |
| public String getLabel() { |
| return fLabel; |
| } |
| |
| public long getNumber() { |
| return fNumber; |
| } |
| } |
| |
| private Target lookupTarget(StructDefinition streamPacketContextDef) { |
| Target ret = new Target(null, IPacketReader.UNKNOWN_CPU); |
| boolean hasDevice = fAttributes.containsKey(CTFStrings.DEVICE); |
| if (hasDevice) { |
| IDefinition def = streamPacketContextDef.lookupDefinition(CTFStrings.DEVICE); |
| if (def instanceof SimpleDatatypeDefinition) { |
| SimpleDatatypeDefinition simpleDefinition = (SimpleDatatypeDefinition) def; |
| ret = new Target(simpleDefinition.getStringValue(), simpleDefinition.getIntegerValue()); |
| } else if (def instanceof StringDefinition) { |
| StringDefinition stringDefinition = (StringDefinition) def; |
| ret = new Target(stringDefinition.getValue(), IPacketReader.UNKNOWN_CPU); |
| final Matcher matcher = NUMBER_PATTERN.matcher(ret.getLabel()); |
| if (matcher.matches()) { |
| String number = matcher.group(1); |
| ret = new Target(ret.getLabel(), Integer.parseInt(number)); |
| } |
| } |
| } else { |
| Long cpuId = (Long) fAttributes.get(CTFStrings.CPU_ID); |
| if (cpuId != null) { |
| ret = new Target("CPU" + cpuId.toString(), cpuId); //$NON-NLS-1$ |
| } |
| } |
| 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; |
| } |
| |
| /** |
| * Get the backing stream packet context |
| * |
| * @return the backing context definition |
| */ |
| public StructDefinition getStreamPacketContextDef() { |
| return fStreamPacketContextDef; |
| } |
| } |