From 1d7277f317fe1a75f274719fc9a87eaf33fada84 Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Fri, 3 Aug 2012 13:59:15 -0400 Subject: [PATCH] Add time scaling support Useful if your clock is not == 1.0 ghz Change-Id: Ie81bfa6b4379d5cbe5b88abae22618bc5a08dc3f Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/7104 Reviewed-by: Alexandre Montplaisir IP-Clean: Alexandre Montplaisir Tested-by: Alexandre Montplaisir --- .../core/tests/trace/CTFTraceReaderTest.java | 2 +- .../linuxtools/ctf/core/event/CTFClock.java | 70 +++++++++++- .../linuxtools/ctf/core/trace/CTFTrace.java | 108 ++++++++++++++---- .../ctf/core/trace/CTFTraceReader.java | 5 +- .../tmf/core/ctfadaptor/CtfTmfEvent.java | 3 +- 5 files changed, 156 insertions(+), 32 deletions(-) diff --git a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceReaderTest.java b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceReaderTest.java index 247768b5a4..f78bb02701 100644 --- a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceReaderTest.java +++ b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceReaderTest.java @@ -297,7 +297,7 @@ public class CTFTraceReaderTest { */ private long getTimestamp() { if (fixture.getCurrentEventDef() != null) { - return fixture.getCurrentEventDef().getTimestamp()+ this.fixture.getTrace().getOffset(); + return fixture.getTrace().timestampCyclesToNanos(fixture.getCurrentEventDef().getTimestamp()); } return -1; } diff --git a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/event/CTFClock.java b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/event/CTFClock.java index aa288da35a..a68e595908 100644 --- a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/event/CTFClock.java +++ b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/event/CTFClock.java @@ -19,6 +19,14 @@ import java.util.HashMap; */ public class CTFClock { + private static final String NAME = "name"; //$NON-NLS-1$ + private static final String FREQ = "freq"; //$NON-NLS-1$ + private static final String OFFSET = "offset"; //$NON-NLS-1$ + + private long clockOffset = 0; + private double clockScale = 1.0; + private double clockAntiScale = 1.0; + /** * Field properties. */ @@ -27,26 +35,48 @@ public class CTFClock { * Field name. */ private String name; + private boolean isScaled = false; /** * Default constructor */ - public CTFClock() {} + public CTFClock() { + } /** * Method addAttribute. - * @param key String - * @param value Object + * + * @param key + * String + * @param value + * Object */ public void addAttribute(String key, Object value) { this.properties.put(key, value); - if (key.equals("name")) { //$NON-NLS-1$ + if (key.equals(NAME)) { this.name = (String) value; } + if (key.equals(FREQ)) { + /* + * Long is converted to a double. the double is then dividing + * another double that double is saved. this is precise as long as + * the long is under 53 bits long. this is ok as long as we don't + * have a system with a frequency of > 1 600 000 000 GHz with + * 200 ppm precision + */ + isScaled = !((Long) getProperty(FREQ)).equals(1000000000L); + clockScale = 1000000000.0 / ((Long) getProperty(FREQ)).doubleValue(); + clockAntiScale = 1.0 / clockScale; + + } + if (key.equals(OFFSET)) { + clockOffset = (Long) getProperty(OFFSET); + } } /** * Method getName. + * * @return String */ public String getName() { @@ -55,11 +85,41 @@ public class CTFClock { /** * Method getProperty. - * @param key String + * + * @param key + * String * @return Object */ public Object getProperty(String key) { return properties.get(key); } + /** + * @return the clockOffset + */ + public long getClockOffset() { + return clockOffset; + } + + /** + * @return the clockScale + */ + public double getClockScale() { + return clockScale; + } + + /** + * @return the clockAntiScale + */ + public double getClockAntiScale() { + return clockAntiScale; + } + + /** + * @return is the clock in ns or cycles? + */ + public boolean isClockScaled() { + return isScaled; + } + } diff --git a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java index 2404de4cbe..4bbc41e1a5 100644 --- a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java +++ b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java @@ -60,14 +60,6 @@ import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex; */ public class CTFTrace implements IDefinitionScope { - // ------------------------------------------------------------------------ - // Attributes - // ------------------------------------------------------------------------ - - private static final String OFFSET = "offset"; //$NON-NLS-1$ - - - /* * (non-Javadoc) * @@ -116,6 +108,11 @@ public class CTFTrace implements IDefinitionScope { */ private StructDeclaration packetHeaderDecl = null; + /** + * The clock of the trace + */ + private CTFClock singleClock; + /** * Packet header structure definition * @@ -627,7 +624,8 @@ public class CTFTrace implements IDefinitionScope { } /* - * If the stream we try to add has the null key, it must be the onl * one. Thus, if the streams container is not empty, it is not valid. + * If the stream we try to add has the null key, it must be the only + * one. Thus, if the streams container is not empty, it is not valid. */ if ((stream.getId() == null) && (streams.size() != 0)) { throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$ @@ -687,23 +685,18 @@ public class CTFTrace implements IDefinitionScope { return clocks.get(name); } - private CTFClock singleClock; - private long singleOffset; + + /** - * gets the clock if there is only one. (this is 100% of the use cases as of June 2012) + * gets the clock if there is only one. (this is 100% of the use cases as of + * June 2012) + * * @return the clock */ public final CTFClock getClock() { if (clocks.size() == 1) { - if (singleClock == null) { - singleClock = clocks.get(clocks.keySet().toArray()[0]); - if (singleClock.getProperty(OFFSET) != null) { - singleOffset = (Long) getClock().getProperty(OFFSET); - } else { - singleClock.addAttribute(OFFSET, 0); - } - } + singleClock = clocks.get(clocks.keySet().iterator().next()); return singleClock; } return null; @@ -711,13 +704,86 @@ public class CTFTrace implements IDefinitionScope { /** * gets the time offset of a clock with respect to UTC in nanoseconds + * * @return the time offset of a clock with respect to UTC in nanoseconds */ public final long getOffset() { if (getClock() == null) { return 0; } - return singleOffset; + return singleClock.getClockOffset(); + } + + /** + * gets the time offset of a clock with respect to UTC in nanoseconds + * + * @return the time offset of a clock with respect to UTC in nanoseconds + */ + private final double getTimeScale() { + if (getClock() == null) { + return 1.0; + } + return singleClock.getClockScale(); + } + + /** + * Does the trace need to time scale? + * + * @return if the trace is in ns or cycles. + */ + private final boolean clockNeedsScale() { + if (getClock() == null) { + return false; + } + return singleClock.isClockScaled(); + } + + /** + * the inverse clock for returning to a scale. + * + * @return 1.0 / scale + */ + private final double getInverseTimeScale() { + if (getClock() == null) { + return 1.0; + } + return singleClock.getClockAntiScale(); + } + + /** + * @param cycles + * clock cycles since boot + * @return time in nanoseconds UTC offset + */ + public long timestampCyclesToNanos(long cycles) { + long retVal = cycles + getOffset(); + /* + * this fix is since quite often the offset will be > than 53 bits and + * therefore the conversion will be lossy + */ + if (clockNeedsScale()) { + retVal = (long) (retVal * getTimeScale()); + } + return retVal; + } + + /** + * @param nanos + * time in nanoseconds UTC offset + * @return clock cycles since boot. + */ + public long timestampNanoToCycles(long nanos) { + long retVal; + /* + * this fix is since quite often the offset will be > than 53 bits and + * therefore the conversion will be lossy + */ + if (clockNeedsScale()) { + retVal = (long) (nanos * getInverseTimeScale()); + } else { + retVal = nanos; + } + return retVal - getOffset(); } /** diff --git a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTraceReader.java b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTraceReader.java index 8ac8c297ea..f705cac142 100644 --- a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTraceReader.java +++ b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTraceReader.java @@ -25,7 +25,7 @@ import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputReaderTimestamp /** * A CTF trace reader. Reads the events of a trace. - * + * * @version 1.0 * @author Matthew Khouzam * @author Alexandre Montplaisir @@ -244,8 +244,7 @@ public class CTFTraceReader { * Add it back in the queue. */ this.prio.add(top); - final long topEnd = top.getCurrentEvent().getTimestamp() - + this.getTrace().getOffset(); + final long topEnd = this.trace.timestampCyclesToNanos(top.getCurrentEvent().getTimestamp()); this.setEndTime(Math.max(topEnd, this.getEndTime())); this.eventCountPerTraceFile[top.getName()]++; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEvent.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEvent.java index 3090a7d46b..b1d5ec0cf7 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEvent.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEvent.java @@ -85,8 +85,7 @@ public final class CtfTmfEvent implements ITmfEvent, Cloneable { } /* Read the base event info */ - Long offset = originTrace.getCTFTrace().getOffset(); - this.timestamp = eventDef.getTimestamp() + offset; + this.timestamp = this.getTrace().getCTFTrace().timestampCyclesToNanos(eventDef.getTimestamp()); this.sourceCPU = eventDef.getCPU(); this.typeId = eventDef.getDeclaration().getId(); this.eventName = eventDef.getDeclaration().getName(); -- 2.34.1