From 6a5251ebcec5a162f0ad2f5da6262505b1826581 Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Wed, 22 Jan 2014 18:13:06 -0500 Subject: [PATCH] ctf: add support for growing streams This patch adds the notion of the parser being in several states. These states are detailed in the CTFResponse file. The possible states are OK (we can keep reading), WAIT (data will be available but is not yet), FINISH (the trace has no more data), ERROR (something happened that should not). Note: this patch is non-trivial, even though it has been tested, if there are regressions later, this patch is an interesting candidate to check. Change-Id: I2e6bd4bdc9e8e490ebb43910a749bcdca9754214 Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/21057 Tested-by: Hudson CI Reviewed-by: Marc-Andre Laperle IP-Clean: Marc-Andre Laperle Tested-by: Marc-Andre Laperle --- .../ctf/core/tests/headless/ReadTrace.java | 2 +- .../trace/CTFTraceGrowingStreamTest.java | 156 ++++++++++++++++++ .../tests/trace/StreamInputReaderTest.java | 7 +- .../ctf/core/trace/CTFResponse.java | 37 +++++ .../ctf/core/trace/CTFTraceReader.java | 48 +++++- .../ctf/core/trace/StreamInputReader.java | 54 ++++-- 6 files changed, 284 insertions(+), 20 deletions(-) create mode 100644 org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceGrowingStreamTest.java create mode 100644 org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFResponse.java diff --git a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/headless/ReadTrace.java b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/headless/ReadTrace.java index 46a1dce184..3362a042e5 100644 --- a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/headless/ReadTrace.java +++ b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/headless/ReadTrace.java @@ -37,7 +37,7 @@ public class ReadTrace { final int LOOP_COUNT = 1; // Work variables - Long nbEvent = 0L; + long nbEvent = 0L; Vector benchs = new Vector<>(); CTFTrace trace = null; long start, stop; diff --git a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceGrowingStreamTest.java b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceGrowingStreamTest.java new file mode 100644 index 0000000000..e9f81d7aa3 --- /dev/null +++ b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/CTFTraceGrowingStreamTest.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * 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 + *******************************************************************************/ + +package org.eclipse.linuxtools.ctf.core.tests.trace; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.util.UUID; + +import org.eclipse.linuxtools.ctf.core.trace.CTFReaderException; +import org.eclipse.linuxtools.ctf.core.trace.CTFTrace; +import org.eclipse.linuxtools.ctf.core.trace.CTFTraceReader; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests growing streams + * + * @author Matthew Khouzam + * + */ +public class CTFTraceGrowingStreamTest { + + private Path fCtfDirectory; + private File fGrowingStream; + private byte[][] fPackets; + private CTFTrace fFixture; + private UUID fUUID; + + /** + * Run before every test + * + * @throws IOException won't happen + * @throws CTFReaderException won't happen + */ + @Before + public void init() throws IOException, CTFReaderException { + fCtfDirectory = Files.createTempDirectory("temptrace", new FileAttribute[] {}); + File metadata = new File(fCtfDirectory.toString() + "/" + "metadata"); + fGrowingStream = new File(fCtfDirectory.toString() + "/" + "stream"); + fUUID = UUID.randomUUID(); + fPackets = new byte[2][]; + fPackets[0] = new byte[32]; + fPackets[1] = new byte[32]; + try (PrintWriter pw = new PrintWriter(metadata)) { + pw.println("/*CTF 1.8*/"); + pw.println("typealias integer { size = 8; align = 8; signed = false; base = 10; } := uint8_t;"); + pw.println("typealias integer { size = 32; align = 32; signed = false; base = hex; } := uint32_t;"); + + pw.println("trace {"); + pw.println(" major = 0;"); + pw.println(" minor = 1;"); + pw.println(" uuid = \"" + fUUID.toString() + "\";"); + pw.println(" byte_order = le;"); + pw.println(" packet.header := struct {"); + pw.println(" uint32_t magic;"); + pw.println(" uint8_t uuid[16];"); + pw.println(" };"); + pw.println("};"); + pw.println(""); + pw.println("stream {"); + pw.println(" packet.context := struct {"); + pw.println(" uint32_t packet_size;"); + pw.println(" uint32_t content_size;"); + pw.println(" };"); + pw.println("};"); + pw.println(""); + pw.println("event {"); + pw.println(" name = thing;"); + pw.println(" fields := struct { uint32_t f; };"); + pw.println("};"); + pw.println(""); + pw.close(); + } + setupPacket(fPackets[0], 41); + setupPacket(fPackets[1], 0xbab4face); + + try (FileOutputStream fos = new FileOutputStream(fGrowingStream)) { + fos.write(fPackets[0]); + } + fFixture = new CTFTrace(fCtfDirectory.toString()); + } + + private void setupPacket(byte data[], int value) { + ByteBuffer bb = ByteBuffer.wrap(data); + bb.clear(); + bb.order(ByteOrder.LITTLE_ENDIAN); + bb.putInt(0xc1fc1fc1); + bb.order(ByteOrder.BIG_ENDIAN); + bb.putLong(fUUID.getMostSignificantBits()); + bb.putLong(fUUID.getLeastSignificantBits()); + bb.order(ByteOrder.LITTLE_ENDIAN); + bb.putInt(256); + bb.putInt(256); + bb.putInt(value); + } + + /** + * Test a growing stream + * + * @throws CTFReaderException won't happen + * @throws IOException won't happen + * @throws FileNotFoundException won't happen + */ + @Test + public void testGrowingLive() throws CTFReaderException, FileNotFoundException, IOException { + CTFTraceReader reader = new CTFTraceReader(fFixture); + reader.setLive(true); + assertEquals("0x29", reader.getCurrentEventDef().getFields().getDefinitions().get("f").toString()); + reader.advance(); + try (FileOutputStream fos = new FileOutputStream(fGrowingStream, true)) { + fos.write(fPackets[1]); + } + reader.advance(); + assertNotNull(reader.getCurrentEventDef()); + assertEquals("0xbab4face", reader.getCurrentEventDef().getFields().getDefinitions().get("f").toString()); + } + + /** + * Test a growing stream + * + * @throws CTFReaderException won't happen + * @throws IOException won't happen + * @throws FileNotFoundException won't happen + */ + @Test + public void testGrowingNotLive() throws CTFReaderException, FileNotFoundException, IOException { + CTFTraceReader reader = new CTFTraceReader(fFixture); + reader.setLive(false); + assertEquals("0x29", reader.getCurrentEventDef().getFields().getDefinitions().get("f").toString()); + reader.advance(); + try (FileOutputStream fos = new FileOutputStream(fGrowingStream, true)) { + fos.write(fPackets[1]); + } + reader.advance(); + assertNull(reader.getCurrentEventDef()); + } +} diff --git a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/StreamInputReaderTest.java b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/StreamInputReaderTest.java index 99cf6a8855..4ea7f64456 100644 --- a/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/StreamInputReaderTest.java +++ b/org.eclipse.linuxtools.ctf.core.tests/src/org/eclipse/linuxtools/ctf/core/tests/trace/StreamInputReaderTest.java @@ -13,7 +13,6 @@ package org.eclipse.linuxtools.ctf.core.tests.trace; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import java.io.File; @@ -24,6 +23,7 @@ import org.eclipse.linuxtools.ctf.core.event.EventDefinition; import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition; import org.eclipse.linuxtools.ctf.core.tests.shared.CtfTestTrace; import org.eclipse.linuxtools.ctf.core.trace.CTFReaderException; +import org.eclipse.linuxtools.ctf.core.trace.CTFResponse; import org.eclipse.linuxtools.ctf.core.trace.CTFTrace; import org.eclipse.linuxtools.ctf.core.trace.Stream; import org.eclipse.linuxtools.ctf.core.trace.StreamInput; @@ -156,7 +156,7 @@ public class StreamInputReaderTest { @Test public void testGoToLastEvent2() throws CTFReaderException { long timestamp = -1; - while(fixture.readNextEvent()) { + while(fixture.readNextEvent().equals(CTFResponse.OK)) { timestamp = fixture.getCurrentEvent().getTimestamp(); } long endTimestamp = goToEnd(); @@ -174,8 +174,7 @@ public class StreamInputReaderTest { */ @Test public void testReadNextEvent() throws CTFReaderException { - boolean result = fixture.readNextEvent(); - assertTrue(result); + assertEquals(CTFResponse.OK, fixture.readNextEvent()); } /** diff --git a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFResponse.java b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFResponse.java new file mode 100644 index 0000000000..262ff3cd10 --- /dev/null +++ b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFResponse.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson + * + * 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 + *******************************************************************************/ +package org.eclipse.linuxtools.ctf.core.trace; + +/** + * A response to a request + * + * @author Matthew Khouzam + * @since 3.0 + * + */ +public enum CTFResponse { + /** + * The operation was successful + */ + OK, + /** + * The operation cannot be yet completed + */ + WAIT, + /** + * The operation was finished + */ + FINISH, + /** + * The operation failed + */ + ERROR +} 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 44a47baaaf..fcf5b73e64 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 @@ -106,7 +106,8 @@ public class CTFTraceReader { * Copy constructor * * @return The new CTFTraceReader - * @throws CTFReaderException if an error occurs + * @throws CTFReaderException + * if an error occurs */ public CTFTraceReader copyFrom() throws CTFReaderException { CTFTraceReader newReader = null; @@ -233,7 +234,8 @@ public class CTFTraceReader { * to read an event from it. */ reader.setParent(this); - if (reader.readNextEvent()) { + CTFResponse readNextEvent = reader.readNextEvent(); + if (readNextEvent == CTFResponse.OK || readNextEvent == CTFResponse.WAIT) { fPrio.add(reader); fEventCountPerTraceFile[pos] = 0; @@ -279,7 +281,8 @@ public class CTFTraceReader { /* * Read the next event of this reader. */ - if (top.readNextEvent()) { + switch (top.readNextEvent()) { + case OK: { /* * Add it back in the queue. */ @@ -292,6 +295,17 @@ public class CTFTraceReader { fEndTime = Math.max(top.getCurrentEvent().getTimestamp(), fEndTime); } + break; + } + case WAIT: { + fPrio.add(top); + break; + } + case FINISH: + break; + case ERROR: + default: + // something bad happend } /* * If there is no reader in the queue, it means the trace reader reached @@ -322,8 +336,8 @@ public class CTFTraceReader { * * @param timestamp * the timestamp to seek to - * @return true if there are events above or equal the seek timestamp, - * false if seek at the end of the trace (no valid event). + * @return true if there are events above or equal the seek timestamp, false + * if seek at the end of the trace (no valid event). * @throws CTFReaderException * if an error occurs */ @@ -421,6 +435,30 @@ public class CTFTraceReader { return fEndTime; } + /** + * Sets a trace to be live or not + * + * @param live + * whether the trace is live + * @since 3.0 + */ + public void setLive(boolean live) { + for (StreamInputReader s : fPrio) { + s.setLive(live); + } + } + + /** + * Get if the trace is to read live or not + * + * @return whether the trace is live or not + * @since 3.0 + * + */ + public boolean isLive() { + return fPrio.peek().isLive(); + } + @Override public int hashCode() { final int prime = 31; diff --git a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/StreamInputReader.java b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/StreamInputReader.java index 9ea692ff7d..95100feb74 100644 --- a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/StreamInputReader.java +++ b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/StreamInputReader.java @@ -62,6 +62,11 @@ public class StreamInputReader { /** Map of all the event types */ private final Map fEventDefs = new HashMap<>(); + /** + * Live trace reading + */ + private boolean fLive = false; + // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ @@ -198,6 +203,27 @@ public class StreamInputReader { fEventDefs.put(id, def); } + /** + * Set the trace to live mode + * + * @param live + * whether the trace is read live or not + * @since 3.0 + */ + public void setLive(boolean live) { + fLive = live; + } + + /** + * Get if the trace is to read live or not + * + * @return whether the trace is live or not + * @since 3.0 + */ + public boolean isLive() { + return fLive; + } + // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ @@ -207,8 +233,9 @@ public class StreamInputReader { * @return If an event has been successfully read. * @throws CTFReaderException * if an error occurs + * @since 3.0 */ - public boolean readNextEvent() throws CTFReaderException { + public CTFResponse readNextEvent() throws CTFReaderException { /* * Change packet if needed @@ -216,20 +243,21 @@ public class StreamInputReader { if (!fPacketReader.hasMoreEvents()) { final StreamInputPacketIndexEntry prevPacket = fPacketReader .getCurrentPacket(); - if (prevPacket != null) { + if (prevPacket != null || fLive ) { goToNextPacket(); } + } /* * If an event is available, read it. */ if (fPacketReader.hasMoreEvents()) { - this.setCurrentEvent(fPacketReader.readNextEvent()); - return true; + setCurrentEvent(fPacketReader.readNextEvent()); + return CTFResponse.OK; } this.setCurrentEvent(null); - return false; + return fLive ? CTFResponse.WAIT : CTFResponse.FINISH; } /** @@ -240,13 +268,16 @@ public class StreamInputReader { */ private void goToNextPacket() throws CTFReaderException { fPacketIndex++; + // did we already index the packet? if (getPacketSize() >= (fPacketIndex + 1)) { fPacketReader.setCurrentPacket(getPacket()); } else { + // go to the next packet if there is one, index it at the same time if (fStreamInput.addPacketHeaderIndex()) { fPacketIndex = getPacketSize() - 1; fPacketReader.setCurrentPacket(getPacket()); } else { + // out of packets fPacketReader.setCurrentPacket(null); } } @@ -291,11 +322,13 @@ public class StreamInputReader { } /* - * Advance until either of these conditions are met - *
    - *
  • reached the end of the trace file (the given timestamp is after the last event),
  • - *
  • found the first event with a timestamp greater or equal the given timestamp.
  • - *
+ * Advance until either of these conditions are met: + * + * - reached the end of the trace file (the given timestamp is after the + * last event) + * + * - found the first event with a timestamp greater or equal the given + * timestamp. */ readNextEvent(); boolean done = (this.getCurrentEvent() == null); @@ -309,6 +342,7 @@ public class StreamInputReader { /** * @param timestamp + * the time to seek * @throws CTFReaderException * if an error occurs */ -- 2.34.1