blob: 1db15ffda31370bf8f80f20aa952d92b0a962c76 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}