From 5b341dc83b9480d2cbbdf63ecb401b194ae8c5c9 Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Thu, 9 Jul 2015 09:10:43 -0400 Subject: [PATCH] ctf: allow traces to read timestamps in fields [bug 470845] This adds declaration looking up their sub-fields. Change-Id: Ie2b40d418014893aa28bb9efb3c745de35411e69 Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/51654 Reviewed-by: Hudson CI Reviewed-by: Bernd Hufmann Tested-by: Bernd Hufmann --- .../tracecompass/ctf/core/CTFStrings.java | 6 ++ .../core/event/types/StructDeclaration.java | 19 +++- .../core/event/types/StructDefinition.java | 58 +++++++++---- .../core/event/types/VariantDefinition.java | 13 ++- .../trace/CTFStreamInputPacketReader.java | 72 +--------------- .../ctf/core/event/EventDeclaration.java | 86 +++++++++++++++++-- .../core/tests/context/CtfTmfContextTest.java | 19 ++-- 7 files changed, 174 insertions(+), 99 deletions(-) diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/CTFStrings.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/CTFStrings.java index 37deed9d92..46ad5e8531 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/CTFStrings.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/CTFStrings.java @@ -117,4 +117,10 @@ public interface CTFStrings { * @since 1.1 */ String PACKET = "packet"; + /** + * Timestamp + * + * @since 1.1 + */ + String TIMESTAMP = "timestamp"; } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java index f45323d8af..d612dd77aa 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java @@ -243,7 +243,7 @@ public class StructDeclaration extends Declaration { private static final Pattern EVENT_HEADER = Pattern.compile(ILexicalScope.EVENT_HEADER.getPath().replaceAll("\\.", "\\\\.") + "\\."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - private class InternalDef implements IDefinitionScope { + static class InternalDef implements IDefinitionScope { private final ICompositeDefinition fEventHeaderDef; private final IDefinitionScope fTraceDef; @@ -280,6 +280,23 @@ public class StructDeclaration extends Declaration { return lookupDefinition; } + public IDefinition lookupDefinitionBreakLoop(String lookupPath) { + IDefinition lookupDefinition = null; + if (fTraceDef != null) { + lookupDefinition = fTraceDef.lookupDefinition(lookupPath); + } + if (lookupDefinition == null) { + if (fEventHeaderDef != null) { + String[] paths = EVENT_HEADER.split(lookupPath); + if (paths.length > 1) { + String[] childLookup = paths[1].split("\\."); //$NON-NLS-1$ + return getRecursiveDef(fEventHeaderDef.getDefinition(childLookup[0]), childLookup, 1); + } + } + } + return lookupDefinition; + } + private IDefinition getRecursiveDef(Definition definition, String[] childLookup, int i) { if (i == childLookup.length) { return definition; diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java index c70eb47477..c6ec4053a1 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java @@ -20,6 +20,7 @@ import java.util.Map; import org.eclipse.jdt.annotation.NonNull; 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.StructDeclaration.InternalDef; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; @@ -142,21 +143,7 @@ public final class StructDefinition extends ScopedDefinition implements IComposi @Override public Definition lookupDefinition(String lookupPath) { - /* - * The fields are created in order of appearance, so if a variant or - * sequence refers to a field that is after it, the field's definition - * will not be there yet in the hashmap. - */ - int val = fFieldNames.indexOf(lookupPath); - if (val != -1) { - return fDefinitions[val]; - } - String lookupUnderscored = "_" + lookupPath; //$NON-NLS-1$ - val = fFieldNames.indexOf(lookupUnderscored); - if (val != -1) { - return fDefinitions[val]; - } - return (Definition) getDefinitionScope().lookupDefinition(lookupPath); + return lookupDefinition(lookupPath, null); } @Override @@ -180,4 +167,45 @@ public final class StructDefinition extends ScopedDefinition implements IComposi return builder.toString(); } + /** + * Lookup definition while exclusing the caller + * + * @param lookupPath + * the path to lookup + * @param defintionToExclude + * the definition to exclude, can be null + * @return the definition or null + * @since 1.1 + */ + public Definition lookupDefinition(String lookupPath, ScopedDefinition defintionToExclude) { + /* + * The fields are created in order of appearance, so if a variant or + * sequence refers to a field that is after it, the field's definition + * will not be there yet in the hashmap. + */ + int val = fFieldNames.indexOf(lookupPath); + if (val != -1) { + return fDefinitions[val]; + } + String lookupUnderscored = "_" + lookupPath; //$NON-NLS-1$ + val = fFieldNames.indexOf(lookupUnderscored); + if (val != -1) { + return fDefinitions[val]; + } + for (IDefinition child : fDefinitions) { + if (child instanceof ScopedDefinition) { + if (!child.equals(defintionToExclude)) { + IDefinition def = ((ScopedDefinition) child).lookupDefinition(lookupPath); + if (def instanceof Definition) { + return (Definition) def; + } + } + } + } + if (getDefinitionScope() instanceof InternalDef) { + return (Definition) ((InternalDef) getDefinitionScope()).lookupDefinitionBreakLoop(lookupPath); + } + return (Definition) getDefinitionScope().lookupDefinition(lookupPath); + } + } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java index abcfdddbee..22a1fd27b2 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java @@ -106,7 +106,18 @@ public final class VariantDefinition extends ScopedDefinition { if (lookupPath.equals(fFieldName)) { return fDefinition; } - return getDefinitionScope().lookupDefinition(lookupPath); + if (fDefinition instanceof ScopedDefinition) { + IDefinition def = ((ScopedDefinition) fDefinition).lookupDefinition(lookupPath); + if (def != null) { + return def; + } + } + final IDefinitionScope definitionScope = getDefinitionScope(); + if (definitionScope instanceof StructDefinition) { + StructDefinition structDefinition = (StructDefinition) definitionScope; + return structDefinition.lookupDefinition(lookupPath, this); + } + return definitionScope.lookupDefinition(lookupPath); } @Override diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFStreamInputPacketReader.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFStreamInputPacketReader.java index d073d90ce3..4f82c1e7af 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFStreamInputPacketReader.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFStreamInputPacketReader.java @@ -278,7 +278,7 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab * Use the timestamp begin of the packet as the reference for the * timestamp reconstitution. */ - fLastTimestamp = currentPacket.getTimestampBegin(); + fLastTimestamp = Math.max(currentPacket.getTimestampBegin(), 0); } else { fBitBuffer = null; fLastTimestamp = 0; @@ -311,7 +311,6 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab /* Default values for those fields */ // compromise since we cannot have 64 bit addressing of arrays yet. int eventID = (int) IEventDeclaration.UNSET_EVENT_ID; - long timestamp = 0; final BitBuffer currentBitBuffer = fBitBuffer; final ICTFPacketDescriptor currentPacket = fCurrentPacket; if (currentBitBuffer == null || currentPacket == null) { @@ -361,7 +360,6 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab fCurrentStreamEventHeaderDef = (ICompositeDefinition) fStreamEventHeaderDecl.createDefinition(EVENT_HEADER_SCOPE, "", currentBitBuffer); //$NON-NLS-1$ EventHeaderDefinition ehd = (EventHeaderDefinition) fCurrentStreamEventHeaderDef; eventID = ehd.getId(); - timestamp = calculateTimestamp(ehd.getTimestamp(), ehd.getTimestampLength()); } else { fCurrentStreamEventHeaderDef = ((StructDeclaration) fStreamEventHeaderDecl).createDefinition(EVENT_HEADER_SCOPE, ILexicalScope.EVENT_HEADER, currentBitBuffer); StructDefinition StructEventHeaderDef = (StructDefinition) fCurrentStreamEventHeaderDef; @@ -373,13 +371,6 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab } else if (idDef != null) { throw new CTFIOException("Id defintion not an integer, enum or float definiton in event header."); //$NON-NLS-1$ } - - /* - * Get the timestamp from the event header (may be overridden - * later on) - */ - IntegerDefinition timestampDef = StructEventHeaderDef.lookupInteger("timestamp"); //$NON-NLS-1$ - /* Check for the variant v. */ IDefinition variantDef = StructEventHeaderDef.lookupDefinition("v"); //$NON-NLS-1$ if (variantDef instanceof VariantDefinition) { @@ -397,18 +388,10 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab simpleIdDef = (SimpleDatatypeDefinition) vIdDef; } - /* - * Get the timestamp. This would overwrite any previous - * timestamp definition - */ - timestampDef = variantCurrentField.lookupInteger("timestamp"); //$NON-NLS-1$ } if (simpleIdDef != null) { eventID = simpleIdDef.getIntegerValue().intValue(); } - if (timestampDef != null) { - timestamp = calculateTimestamp(timestampDef); - } // else timestamp remains 0 } } /* Get the right event definition using the event id. */ @@ -416,8 +399,8 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab if (eventDeclaration == null) { throw new CTFIOException("Incorrect event id : " + eventID); //$NON-NLS-1$ } - EventDefinition eventDef = eventDeclaration.createDefinition(fStreamInputReader, fCurrentStreamEventHeaderDef, currentBitBuffer, timestamp); - + EventDefinition eventDef = eventDeclaration.createDefinition(fStreamInputReader, fCurrentStreamEventHeaderDef, currentBitBuffer, fLastTimestamp); + fLastTimestamp = eventDef.getTimestamp(); /* * Set the event timestamp using the timestamp calculated by * updateTimestamp. @@ -430,55 +413,6 @@ public class CTFStreamInputPacketReader implements IDefinitionScope, AutoCloseab return eventDef; } - /** - * Calculates the timestamp value of the event, possibly using the timestamp - * from the last event. - * - * @param timestampDef - * Integer definition of the timestamp. - * @return The calculated timestamp value. - */ - private long calculateTimestamp(IntegerDefinition timestampDef) { - int len = timestampDef.getDeclaration().getLength(); - final long value = timestampDef.getValue(); - - return calculateTimestamp(value, len); - } - - private long calculateTimestamp(final long value, int len) { - long newval; - long majorasbitmask; - /* - * If the timestamp length is 64 bits, it is a full timestamp. - */ - if (len == Long.SIZE) { - fLastTimestamp = value; - return fLastTimestamp; - } - - /* - * Bit mask to keep / remove all old / new bits. - */ - majorasbitmask = (1L << len) - 1; - - /* - * If the new value is smaller than the corresponding bits of the last - * timestamp, we assume an overflow of the compact representation. - */ - newval = value; - if (newval < (fLastTimestamp & majorasbitmask)) { - newval = newval + (1L << len); - } - - /* Keep only the high bits of the old value */ - fLastTimestamp = fLastTimestamp & ~majorasbitmask; - - /* Then add the low bits of the new value */ - fLastTimestamp = fLastTimestamp + newval; - - return fLastTimestamp; - } - @Override public Definition lookupDefinition(String lookupPath) { if (lookupPath.equals(ILexicalScope.STREAM_PACKET_CONTEXT.getPath())) { diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java index 9acb2b7d95..5bc6ba5ccf 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java @@ -17,16 +17,22 @@ import java.util.Map; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; +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.EventDefinition; 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.ILexicalScope; +import org.eclipse.tracecompass.ctf.core.event.types.Definition; import org.eclipse.tracecompass.ctf.core.event.types.ICompositeDefinition; +import org.eclipse.tracecompass.ctf.core.event.types.IntegerDefinition; import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition; +import org.eclipse.tracecompass.ctf.core.trace.CTFIOException; import org.eclipse.tracecompass.ctf.core.trace.CTFStream; import org.eclipse.tracecompass.ctf.core.trace.CTFStreamInputReader; +import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderDefinition; /** * Representation of one type of event. A bit like "int" or "long" but for trace @@ -88,23 +94,21 @@ public class EventDeclaration implements IEventDeclaration { * The event header definition * @param input * the bitbuffer input source - * @param timestamp + * @param prevTimestamp * The timestamp when the event was taken * @return A new EventDefinition. * @throws CTFException * As a bitbuffer is used to read, it could have wrapped * IOExceptions. */ - public EventDefinition createDefinition(CTFStreamInputReader streamInputReader, ICompositeDefinition eventHeaderDef, @NonNull BitBuffer input, long timestamp) throws CTFException { + public EventDefinition createDefinition(CTFStreamInputReader streamInputReader, ICompositeDefinition eventHeaderDef, @NonNull BitBuffer input, long prevTimestamp) throws CTFException { StructDeclaration streamEventContextDecl = streamInputReader.getStreamEventContextDecl(); StructDefinition streamEventContext = streamEventContextDecl != null ? streamEventContextDecl.createDefinition(fStream.getTrace(), ILexicalScope.STREAM_EVENT_CONTEXT, input) : null; ICompositeDefinition packetContext = streamInputReader.getPacketReader().getCurrentPacketEventHeader(); StructDefinition eventContext = fContext != null ? fContext.createFieldDefinition(eventHeaderDef, fStream.getTrace(), ILexicalScope.CONTEXT, input) : null; StructDefinition eventPayload = fFields != null ? fFields.createFieldDefinition(eventHeaderDef, fStream.getTrace(), ILexicalScope.FIELDS, input) : null; + long timestamp = calculateTimestamp(eventHeaderDef, prevTimestamp, eventPayload); - // a bit lttng specific - // CTF doesn't require a timestamp, - // but it's passed to us return new EventDefinition( this, streamInputReader, @@ -116,6 +120,28 @@ public class EventDeclaration implements IEventDeclaration { eventPayload); } + private static long calculateTimestamp(@Nullable ICompositeDefinition eventHeaderDef, long prevTimestamp, StructDefinition eventPayload) throws CTFIOException { + long timestamp = 0; + Definition def = null; + if (eventHeaderDef instanceof EventHeaderDefinition) { + EventHeaderDefinition eventHeaderDefinition = (EventHeaderDefinition) eventHeaderDef; + timestamp = calculateTimestamp(eventHeaderDefinition.getTimestamp(), eventHeaderDefinition.getTimestampLength(), prevTimestamp); + } else if (eventHeaderDef instanceof StructDefinition) { + StructDefinition structDefinition = (StructDefinition) eventHeaderDef; + def = structDefinition.lookupDefinition(CTFStrings.TIMESTAMP); + } else if (eventHeaderDef != null) { + throw new CTFIOException("Event header def is not a Struct or an Event Header"); //$NON-NLS-1$ + } + if (def == null && eventPayload != null) { + def = eventPayload.lookupDefinition(CTFStrings.TIMESTAMP); + } + if (def instanceof IntegerDefinition) { + IntegerDefinition timestampDef = (IntegerDefinition) def; + timestamp = calculateTimestamp(timestampDef, prevTimestamp); + } + return timestamp; + } + @Override public EventDefinition createDefinition(CTFStreamInputReader streamInputReader, @NonNull BitBuffer input, long timestamp) throws CTFException { StructDeclaration streamEventContextDecl = streamInputReader.getStreamEventContextDecl(); @@ -310,6 +336,56 @@ public class EventDeclaration implements IEventDeclaration { fCustomAttributes.put(key, value); } + /** + * Calculates the timestamp value of the event, possibly using the timestamp + * from the last event. + * + * @param timestampDef + * Integer definition of the timestamp. + * @return The calculated timestamp value. + */ + private static long calculateTimestamp(IntegerDefinition timestampDef, long lastTimestamp) { + int len = timestampDef.getDeclaration().getLength(); + final long value = timestampDef.getValue(); + + return calculateTimestamp(value, len, lastTimestamp); + } + + private static long calculateTimestamp(final long value, int len, long prevTimestamp) { + long newval; + long majorasbitmask; + long lastTimestamp = prevTimestamp; + /* + * If the timestamp length is 64 bits, it is a full timestamp. + */ + if (len == Long.SIZE) { + lastTimestamp = value; + return lastTimestamp; + } + + /* + * Bit mask to keep / remove all old / new bits. + */ + majorasbitmask = (1L << len) - 1; + + /* + * If the new value is smaller than the corresponding bits of the last + * timestamp, we assume an overflow of the compact representation. + */ + newval = value; + if (newval < (lastTimestamp & majorasbitmask)) { + newval = newval + (1L << len); + } + + /* Keep only the high bits of the old value */ + lastTimestamp = lastTimestamp & ~majorasbitmask; + + /* Then add the low bits of the new value */ + lastTimestamp = lastTimestamp + newval; + + return lastTimestamp; + } + // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ diff --git a/ctf/org.eclipse.tracecompass.tmf.ctf.core.tests/src/org/eclipse/tracecompass/tmf/ctf/core/tests/context/CtfTmfContextTest.java b/ctf/org.eclipse.tracecompass.tmf.ctf.core.tests/src/org/eclipse/tracecompass/tmf/ctf/core/tests/context/CtfTmfContextTest.java index 28e992314e..1e1bba68e1 100644 --- a/ctf/org.eclipse.tracecompass.tmf.ctf.core.tests/src/org/eclipse/tracecompass/tmf/ctf/core/tests/context/CtfTmfContextTest.java +++ b/ctf/org.eclipse.tracecompass.tmf.ctf.core.tests/src/org/eclipse/tracecompass/tmf/ctf/core/tests/context/CtfTmfContextTest.java @@ -14,6 +14,7 @@ package org.eclipse.tracecompass.tmf.ctf.core.tests.context; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -37,7 +38,9 @@ import org.junit.Test; public class CtfTmfContextTest { private static final CtfTmfTestTrace testTrace = CtfTmfTestTrace.KERNEL; - private static final long begin = 1332170682440133097L; /* Trace start time */ + private static final long begin = 1332170682440133097L; /* + * Trace start time + */ private static final long end = 1332170692664579801L; /* Trace end time */ private CtfTmfTrace trace; @@ -101,7 +104,7 @@ public class CtfTmfContextTest { CtfTmfContext lwc = new CtfTmfContext(trace); lwc.seek(val); trace.getNext(lwc); - synchronized(trace){ + synchronized (trace) { if (lwc.getCurrentEvent() != null) { vals.add(lwc.getCurrentEvent().getTimestamp().getValue()); } @@ -109,18 +112,18 @@ public class CtfTmfContextTest { } } }; - thread.setVal((long)i); + thread.setVal((long) i); threads.add(thread); thread.start(); } - for (Thread t: threads){ + for (Thread t : threads) { t.join(); } - - for (long val : vals){ - assertTrue(val >= begin); - assertTrue(val <= end); + assertEquals("seeks done ", lwcCount + 1, vals.size()); + for (long val : vals) { + assertTrue("val >= begin, " + val + " " + begin, val >= begin); + assertTrue("val >= end, " + val + " " + end, val <= end); } } } -- 2.34.1