From f9a76cacf7d7cb5e0f6edfcc6d786635864caae5 Mon Sep 17 00:00:00 2001 From: Alexandre Montplaisir Date: Mon, 14 Jan 2013 15:37:55 -0500 Subject: [PATCH 1/1] tmf: Add a new package for state history backends Added two new simple backends: - Null backend, which discards all intervals it receives. - In-memory backend, which is like a full history but keeps everything in RAM. For use with small state systems only! Also renamed the existing *.historytree package to *.backends.historytree. Change-Id: Ia32285ce2162d5315616dd2546fa18549b38da22 Signed-off-by: Alexandre Montplaisir Reviewed-on: https://git.eclipse.org/r/9594 Tested-by: Hudson CI Reviewed-by: Matthew Khouzam IP-Clean: Matthew Khouzam Tested-by: Matthew Khouzam --- .../lttng2/kernel/core/tests/AllTests.java | 6 +- .../StateSystemFullHistoryTest.java | 322 ++---------------- .../StateSystemInMemoryTest.java | 39 +++ .../tests/stateprovider/StateSystemTest.java | 285 ++++++++++++++++ .../core/tests/stateprovider/TestAll.java | 23 +- .../statesystem/StateSystemPushPopTest.java | 4 +- .../tests/statesystem/VerifyHistoryFile.java | 4 +- .../META-INF/MANIFEST.MF | 3 +- .../tmf/core/statesystem/HistoryBuilder.java | 11 +- .../tmf/core/statesystem/StateSystem.java | 16 +- .../tmf/core/statesystem/TransientState.java | 1 + .../{ => backends}/IStateHistoryBackend.java | 2 +- .../statesystem/backends/InMemoryBackend.java | 203 +++++++++++ .../statesystem/backends/NullBackend.java | 123 +++++++ .../{ => backends}/historytree/CoreNode.java | 2 +- .../{ => backends}/historytree/HTConfig.java | 2 +- .../historytree/HTInterval.java | 2 +- .../{ => backends}/historytree/HTNode.java | 2 +- .../{ => backends}/historytree/HT_IO.java | 2 +- .../historytree/HistoryTree.java | 2 +- .../historytree/HistoryTreeBackend.java | 4 +- .../ThreadedHistoryTreeBackend.java | 2 +- .../interval/TmfIntervalEndComparator.java | 29 ++ .../core/statesystem/StateSystemManager.java | 51 ++- 24 files changed, 804 insertions(+), 336 deletions(-) create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemInMemoryTest.java create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemTest.java rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/IStateHistoryBackend.java (99%) create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/InMemoryBackend.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/NullBackend.java rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/CoreNode.java (98%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/HTConfig.java (94%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/HTInterval.java (99%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/HTNode.java (99%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/HT_IO.java (98%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/HistoryTree.java (99%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/HistoryTreeBackend.java (98%) rename org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/{ => backends}/historytree/ThreadedHistoryTreeBackend.java (98%) create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/interval/TmfIntervalEndComparator.java diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/AllTests.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/AllTests.java index cf6c55cf03..93d97234ff 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/AllTests.java +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/AllTests.java @@ -20,8 +20,8 @@ import org.junit.runners.Suite; *

*/ @RunWith(Suite.class) -@Suite.SuiteClasses({ ActivatorTest.class, - org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider.CtfKernelStateInputTest.class, - org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider.StateSystemFullHistoryTest.class +@Suite.SuiteClasses({ + ActivatorTest.class, + org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider.TestAll.class }) public class AllTests { } diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemFullHistoryTest.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemFullHistoryTest.java index c4e884dc4f..f0f51a164c 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemFullHistoryTest.java +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemFullHistoryTest.java @@ -1,32 +1,24 @@ /******************************************************************************* * Copyright (c) 2012 Ericsson - * Copyright (c) 2010, 2011 École Polytechnique de Montréal - * Copyright (c) 2010, 2011 Alexandre Montplaisir * * 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: + * Alexandre Montplaisir - Initial API and implementation + ******************************************************************************/ package org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import java.io.File; -import java.util.List; -import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes; import org.eclipse.linuxtools.internal.lttng2.kernel.core.stateprovider.CtfKernelStateInput; -import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; -import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; -import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; -import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; -import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput; import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; import org.eclipse.linuxtools.tmf.core.statesystem.StateSystemManager; @@ -35,33 +27,25 @@ import org.junit.BeforeClass; import org.junit.Test; /** - * Unit tests for the StateHistorySystem, which uses a full (non-partial) - * history and the non-threaded CTF kernel handler. - * - * @author alexmont + * State system tests using a full history back-end and the LTTng kernel state + * input. * + * @author Alexandre Montplaisir */ -@SuppressWarnings({"nls", "javadoc"}) -public class StateSystemFullHistoryTest { - - static File stateFile; - static File stateFileBenchmark; - - static IStateChangeInput input; - static ITmfStateSystem ssq; - - /* Offset in the trace + start time of the trace */ - private final static long interestingTimestamp1 = 18670067372290L + 1331649577946812237L; +public class StateSystemFullHistoryTest extends StateSystemTest { - protected static String getTestFileName() { - return "/tmp/statefile.ht"; //$NON-NLS-1$ - } + private static File stateFile; + private static File stateFileBenchmark; + /** + * Initialize the test cases (build the history file once for all tests). + */ @BeforeClass public static void initialize() { - stateFile = new File(getTestFileName()); - stateFileBenchmark = new File(getTestFileName() + ".benchmark"); //$NON-NLS-1$ try { + stateFile = File.createTempFile("test", ".ht"); //$NON-NLS-1$ //$NON-NLS-2$ + stateFileBenchmark = File.createTempFile("test", ".ht.benchmark"); //$NON-NLS-1$ //$NON-NLS-2$ + input = new CtfKernelStateInput(CtfTestFiles.getTestTrace()); ssq = StateSystemManager.loadStateHistory(stateFile, input, true); } catch (Exception e) { @@ -69,6 +53,9 @@ public class StateSystemFullHistoryTest { } } + /** + * Delete the temp files after we're done + */ @AfterClass public static void cleanup() { boolean ret1, ret2; @@ -76,16 +63,20 @@ public class StateSystemFullHistoryTest { ret2 = stateFileBenchmark.delete(); if ( !(ret1 && ret2) ) { System.err.println("Error cleaning up during unit testing, " + //$NON-NLS-1$ - "you might have leftovers state history files in /tmp"); //$NON-NLS-1$ + "you might have leftovers state history files in /tmp"); //$NON-NLS-1$ } } + // ------------------------------------------------------------------------ + // Tests specific to a full-history + // ------------------------------------------------------------------------ + /** * Rebuild independently so we can benchmark it. Too bad JUnit doesn't allow * us to @Test the @BeforeClass... * - * @throws IOException * @throws TmfTraceException + * Fails the test */ @Test public void testBuild() throws TmfTraceException { @@ -99,6 +90,12 @@ public class StateSystemFullHistoryTest { assertEquals(CtfTestFiles.endTime, ssb2.getCurrentEndTime()); } + /** + * Test re-opening the existing file. + * + * @throws TmfTraceException + * Fails the test + */ @Test public void testOpenExistingStateFile() throws TmfTraceException { ITmfStateSystem ssb2; @@ -111,263 +108,4 @@ public class StateSystemFullHistoryTest { assertEquals(CtfTestFiles.endTime, ssb2.getCurrentEndTime()); } - @Test - public void testFullQuery1() throws StateValueTypeException, - AttributeNotFoundException, TimeRangeException, - StateSystemDisposedException { - - List list; - ITmfStateInterval interval; - int quark, valueInt; - String valueStr; - - list = ssq.queryFullState(interestingTimestamp1); - - quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - interval = list.get(quark); - valueInt = interval.getStateValue().unboxInt(); - assertEquals(1397, valueInt); - - quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); - interval = list.get(quark); - valueStr = interval.getStateValue().unboxStr(); - assertEquals("gdbus", valueStr); - - quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.SYSTEM_CALL); - interval = list.get(quark); - valueStr = interval.getStateValue().unboxStr(); - assertTrue(valueStr.equals("sys_poll")); - } - - @Test - public void testFullQuery2() { - // - } - - @Test - public void testFullQuery3() { - // - } - - @Test - public void testSingleQuery1() throws AttributeNotFoundException, - TimeRangeException, StateValueTypeException, - StateSystemDisposedException { - - long timestamp = interestingTimestamp1; - int quark; - ITmfStateInterval interval; - String valueStr; - - quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); - interval = ssq.querySingleState(timestamp, quark); - valueStr = interval.getStateValue().unboxStr(); - assertEquals("gdbus", valueStr); - } - - @Test - public void testSingleQuery2() { - // - } - - @Test - public void testSingleQuery3() { - // - } - - /** - * Test a range query (with no resolution parameter, so all intervals) - */ - @Test - public void testRangeQuery1() throws AttributeNotFoundException, - TimeRangeException, StateValueTypeException, - StateSystemDisposedException { - - long time1 = interestingTimestamp1; - long time2 = time1 + 1L * CtfTestFiles.NANOSECS_PER_SEC; - int quark; - List intervals; - - quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - intervals = ssq.queryHistoryRange(quark, time1, time2); - assertEquals(487, intervals.size()); /* Number of context switches! */ - assertEquals(1685, intervals.get(100).getStateValue().unboxInt()); - assertEquals(1331668248427681372L, intervals.get(205).getEndTime()); - } - - /** - * Range query, but with a t2 far off the end of the trace. - * The result should still be valid. - */ - @Test - public void testRangeQuery2() throws TimeRangeException, - AttributeNotFoundException, StateSystemDisposedException { - - List intervals; - - int quark = ssq.getQuarkAbsolute(Attributes.RESOURCES, Attributes.IRQS, "1"); - long ts1 = ssq.getStartTime(); /* start of the trace */ - long ts2 = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid, but ignored */ - - intervals = ssq.queryHistoryRange(quark, ts1, ts2); - - /* Activity of IRQ 1 over the whole trace */ - assertEquals(65, intervals.size()); - } - - /** - * Test a range query with a resolution - */ - @Test - public void testRangeQuery3() throws AttributeNotFoundException, - TimeRangeException, StateValueTypeException, - StateSystemDisposedException { - - long time1 = interestingTimestamp1; - long time2 = time1 + 1L * CtfTestFiles.NANOSECS_PER_SEC; - long resolution = 1000000; /* One query every millisecond */ - int quark; - List intervals; - - quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - intervals = ssq.queryHistoryRange(quark, time1, time2, resolution, null); - assertEquals(126, intervals.size()); /* Number of context switches! */ - assertEquals(1452, intervals.get(50).getStateValue().unboxInt()); - assertEquals(1331668248815698779L, intervals.get(100).getEndTime()); - } - - /** - * Ask for a time range outside of the trace's range - */ - @Test(expected = TimeRangeException.class) - public void testFullQueryInvalidTime1() throws TimeRangeException, - StateSystemDisposedException { - long ts = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; - ssq.queryFullState(ts); - } - - @Test(expected = TimeRangeException.class) - public void testFullQueryInvalidTime2() throws TimeRangeException, - StateSystemDisposedException { - long ts = CtfTestFiles.startTime - 20L * CtfTestFiles.NANOSECS_PER_SEC; - ssq.queryFullState(ts); - } - - @Test(expected = TimeRangeException.class) - public void testSingleQueryInvalidTime1() - throws AttributeNotFoundException, TimeRangeException, - StateSystemDisposedException { - - int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - long ts = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; - ssq.querySingleState(ts, quark); - } - - @Test(expected = TimeRangeException.class) - public void testSingleQueryInvalidTime2() - throws AttributeNotFoundException, TimeRangeException, - StateSystemDisposedException { - - int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - long ts = CtfTestFiles.startTime - 20L * CtfTestFiles.NANOSECS_PER_SEC; - ssq.querySingleState(ts, quark); - } - - @Test(expected = TimeRangeException.class) - public void testRangeQueryInvalidTime1() throws AttributeNotFoundException, - TimeRangeException, StateSystemDisposedException { - - int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - long ts1 = CtfTestFiles.startTime - 20L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid */ - long ts2 = CtfTestFiles.startTime + 1L * CtfTestFiles.NANOSECS_PER_SEC; /* valid */ - - ssq.queryHistoryRange(quark, ts1, ts2); - } - - @Test(expected = TimeRangeException.class) - public void testRangeQueryInvalidTime2() throws TimeRangeException, - AttributeNotFoundException, StateSystemDisposedException { - - int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - long ts1 = CtfTestFiles.startTime - 1L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid */ - long ts2 = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid */ - - ssq.queryHistoryRange(quark, ts1, ts2); - } - - /** - * Ask for a non-existing attribute - * - * @throws AttributeNotFoundException - */ - @Test(expected = AttributeNotFoundException.class) - public void testQueryInvalidAttribute() throws AttributeNotFoundException { - - ssq.getQuarkAbsolute("There", "is", "no", "cow", "level"); - } - - /** - * Query but with the wrong State Value type - */ - @Test(expected = StateValueTypeException.class) - public void testQueryInvalidValuetype1() throws StateValueTypeException, - AttributeNotFoundException, TimeRangeException, - StateSystemDisposedException { - List list; - ITmfStateInterval interval; - int quark; - - list = ssq.queryFullState(interestingTimestamp1); - quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - interval = list.get(quark); - - /* This is supposed to be an int value */ - interval.getStateValue().unboxStr(); - } - - @Test(expected = StateValueTypeException.class) - public void testQueryInvalidValuetype2() throws StateValueTypeException, - AttributeNotFoundException, TimeRangeException, - StateSystemDisposedException { - List list; - ITmfStateInterval interval; - int quark; - - list = ssq.queryFullState(interestingTimestamp1); - quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); - interval = list.get(quark); - - /* This is supposed to be a String value */ - interval.getStateValue().unboxInt(); - } - - @Test - public void testFullAttributeName() throws AttributeNotFoundException { - int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); - String name = ssq.getFullAttributePath(quark); - assertEquals(name, "CPUs/0/Current_thread"); - } - - @Test - public void testGetQuarks_begin() { - List list = ssq.getQuarks("*", "1577", Attributes.EXEC_NAME); - - assertEquals(1, list.size()); - } - - @Test - public void testGetQuarks_middle() { - List list = ssq.getQuarks(Attributes.THREADS, "*", Attributes.EXEC_NAME); - - /* Number of different kernel threads in the trace */ - assertEquals(168, list.size()); - } - - @Test - public void testGetQuarks_end() { - List list = ssq.getQuarks(Attributes.THREADS, "1577", "*"); - - /* There should be 4 sub-attributes for each Thread node */ - assertEquals(4, list.size()); - } } diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemInMemoryTest.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemInMemoryTest.java new file mode 100644 index 0000000000..94e09b3572 --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemInMemoryTest.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2013 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: + * Alexandre Montplaisir - Initial API and implementation + ******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider; + +import org.eclipse.linuxtools.internal.lttng2.kernel.core.stateprovider.CtfKernelStateInput; +import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; +import org.eclipse.linuxtools.tmf.core.statesystem.StateSystemManager; +import org.junit.BeforeClass; + +/** + * State system tests using the in-memory back-end. + * + * @author Alexandre Montplaisir + */ +public class StateSystemInMemoryTest extends StateSystemTest { + + /** + * Initialization + */ + @BeforeClass + public static void initialize() { + try { + input = new CtfKernelStateInput(CtfTestFiles.getTestTrace()); + ssq = StateSystemManager.newInMemHistory(input, true); + } catch (TmfTraceException e) { + e.printStackTrace(); + } + } +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemTest.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemTest.java new file mode 100644 index 0000000000..3f88770a8c --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/StateSystemTest.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2012 Ericsson + * Copyright (c) 2010, 2011 École Polytechnique de Montréal + * Copyright (c) 2010, 2011 Alexandre Montplaisir + * + * 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 + * + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.eclipse.linuxtools.internal.lttng2.kernel.core.Attributes; +import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; +import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; +import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; +import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; +import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; +import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput; +import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; +import org.junit.Test; + +/** + * Base unit tests for the StateHistorySystem. Extension can be made to test + * different state back-end types or configurations. + * + * @author Alexandre Montplaisir + * + */ +@SuppressWarnings({"nls", "javadoc"}) +public abstract class StateSystemTest { + + protected static IStateChangeInput input; + protected static ITmfStateSystem ssq; + + /* Offset in the trace + start time of the trace */ + private static final long interestingTimestamp1 = 18670067372290L + 1331649577946812237L; + + @Test + public void testFullQuery1() throws StateValueTypeException, + AttributeNotFoundException, TimeRangeException, + StateSystemDisposedException { + + List list; + ITmfStateInterval interval; + int quark, valueInt; + String valueStr; + + list = ssq.queryFullState(interestingTimestamp1); + + quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + interval = list.get(quark); + valueInt = interval.getStateValue().unboxInt(); + assertEquals(1397, valueInt); + + quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); + interval = list.get(quark); + valueStr = interval.getStateValue().unboxStr(); + assertEquals("gdbus", valueStr); + + quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.SYSTEM_CALL); + interval = list.get(quark); + valueStr = interval.getStateValue().unboxStr(); + assertTrue(valueStr.equals("sys_poll")); + } + + @Test + public void testSingleQuery1() throws AttributeNotFoundException, + TimeRangeException, StateValueTypeException, + StateSystemDisposedException { + + long timestamp = interestingTimestamp1; + int quark; + ITmfStateInterval interval; + String valueStr; + + quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); + interval = ssq.querySingleState(timestamp, quark); + valueStr = interval.getStateValue().unboxStr(); + assertEquals("gdbus", valueStr); + } + + /** + * Test a range query (with no resolution parameter, so all intervals) + */ + @Test + public void testRangeQuery1() throws AttributeNotFoundException, + TimeRangeException, StateValueTypeException, + StateSystemDisposedException { + + long time1 = interestingTimestamp1; + long time2 = time1 + 1L * CtfTestFiles.NANOSECS_PER_SEC; + int quark; + List intervals; + + quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + intervals = ssq.queryHistoryRange(quark, time1, time2); + assertEquals(487, intervals.size()); /* Number of context switches! */ + assertEquals(1685, intervals.get(100).getStateValue().unboxInt()); + assertEquals(1331668248427681372L, intervals.get(205).getEndTime()); + } + + /** + * Range query, but with a t2 far off the end of the trace. + * The result should still be valid. + */ + @Test + public void testRangeQuery2() throws TimeRangeException, + AttributeNotFoundException, StateSystemDisposedException { + + List intervals; + + int quark = ssq.getQuarkAbsolute(Attributes.RESOURCES, Attributes.IRQS, "1"); + long ts1 = ssq.getStartTime(); /* start of the trace */ + long ts2 = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid, but ignored */ + + intervals = ssq.queryHistoryRange(quark, ts1, ts2); + + /* Activity of IRQ 1 over the whole trace */ + assertEquals(65, intervals.size()); + } + + /** + * Test a range query with a resolution + */ + @Test + public void testRangeQuery3() throws AttributeNotFoundException, + TimeRangeException, StateValueTypeException, + StateSystemDisposedException { + + long time1 = interestingTimestamp1; + long time2 = time1 + 1L * CtfTestFiles.NANOSECS_PER_SEC; + long resolution = 1000000; /* One query every millisecond */ + int quark; + List intervals; + + quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + intervals = ssq.queryHistoryRange(quark, time1, time2, resolution, null); + assertEquals(126, intervals.size()); /* Number of context switches! */ + assertEquals(1452, intervals.get(50).getStateValue().unboxInt()); + assertEquals(1331668248815698779L, intervals.get(100).getEndTime()); + } + + /** + * Ask for a time range outside of the trace's range + */ + @Test(expected = TimeRangeException.class) + public void testFullQueryInvalidTime1() throws TimeRangeException, + StateSystemDisposedException { + long ts = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; + ssq.queryFullState(ts); + } + + @Test(expected = TimeRangeException.class) + public void testFullQueryInvalidTime2() throws TimeRangeException, + StateSystemDisposedException { + long ts = CtfTestFiles.startTime - 20L * CtfTestFiles.NANOSECS_PER_SEC; + ssq.queryFullState(ts); + } + + @Test(expected = TimeRangeException.class) + public void testSingleQueryInvalidTime1() + throws AttributeNotFoundException, TimeRangeException, + StateSystemDisposedException { + + int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + long ts = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; + ssq.querySingleState(ts, quark); + } + + @Test(expected = TimeRangeException.class) + public void testSingleQueryInvalidTime2() + throws AttributeNotFoundException, TimeRangeException, + StateSystemDisposedException { + + int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + long ts = CtfTestFiles.startTime - 20L * CtfTestFiles.NANOSECS_PER_SEC; + ssq.querySingleState(ts, quark); + } + + @Test(expected = TimeRangeException.class) + public void testRangeQueryInvalidTime1() throws AttributeNotFoundException, + TimeRangeException, StateSystemDisposedException { + + int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + long ts1 = CtfTestFiles.startTime - 20L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid */ + long ts2 = CtfTestFiles.startTime + 1L * CtfTestFiles.NANOSECS_PER_SEC; /* valid */ + + ssq.queryHistoryRange(quark, ts1, ts2); + } + + @Test(expected = TimeRangeException.class) + public void testRangeQueryInvalidTime2() throws TimeRangeException, + AttributeNotFoundException, StateSystemDisposedException { + + int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + long ts1 = CtfTestFiles.startTime - 1L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid */ + long ts2 = CtfTestFiles.startTime + 20L * CtfTestFiles.NANOSECS_PER_SEC; /* invalid */ + + ssq.queryHistoryRange(quark, ts1, ts2); + } + + /** + * Ask for a non-existing attribute + * + * @throws AttributeNotFoundException + */ + @Test(expected = AttributeNotFoundException.class) + public void testQueryInvalidAttribute() throws AttributeNotFoundException { + + ssq.getQuarkAbsolute("There", "is", "no", "cow", "level"); + } + + /** + * Query but with the wrong State Value type + */ + @Test(expected = StateValueTypeException.class) + public void testQueryInvalidValuetype1() throws StateValueTypeException, + AttributeNotFoundException, TimeRangeException, + StateSystemDisposedException { + List list; + ITmfStateInterval interval; + int quark; + + list = ssq.queryFullState(interestingTimestamp1); + quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + interval = list.get(quark); + + /* This is supposed to be an int value */ + interval.getStateValue().unboxStr(); + } + + @Test(expected = StateValueTypeException.class) + public void testQueryInvalidValuetype2() throws StateValueTypeException, + AttributeNotFoundException, TimeRangeException, + StateSystemDisposedException { + List list; + ITmfStateInterval interval; + int quark; + + list = ssq.queryFullState(interestingTimestamp1); + quark = ssq.getQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); + interval = list.get(quark); + + /* This is supposed to be a String value */ + interval.getStateValue().unboxInt(); + } + + @Test + public void testFullAttributeName() throws AttributeNotFoundException { + int quark = ssq.getQuarkAbsolute(Attributes.CPUS, "0", Attributes.CURRENT_THREAD); + String name = ssq.getFullAttributePath(quark); + assertEquals(name, "CPUs/0/Current_thread"); + } + + @Test + public void testGetQuarks_begin() { + List list = ssq.getQuarks("*", "1577", Attributes.EXEC_NAME); + + assertEquals(1, list.size()); + } + + @Test + public void testGetQuarks_middle() { + List list = ssq.getQuarks(Attributes.THREADS, "*", Attributes.EXEC_NAME); + + /* Number of different kernel threads in the trace */ + assertEquals(168, list.size()); + } + + @Test + public void testGetQuarks_end() { + List list = ssq.getQuarks(Attributes.THREADS, "1577", "*"); + + /* There should be 4 sub-attributes for each Thread node */ + assertEquals(4, list.size()); + } +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/TestAll.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/TestAll.java index fa9d695484..a0f6817f4b 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/TestAll.java +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/stateprovider/TestAll.java @@ -1,18 +1,17 @@ /******************************************************************************* * Copyright (c) 2012 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: * Alexandre Montplaisir - Initial implementation ******************************************************************************/ package org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider; -import org.junit.runner.JUnitCore; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -20,22 +19,16 @@ import org.junit.runners.Suite; * The class TestAll builds a suite that can be used to run all of * the tests within its package as well as within any subpackages of its * package. - * + * * @author ematkho * @version $Revision: 1.0 $ */ @RunWith(Suite.class) -@Suite.SuiteClasses({ CtfKernelStateInputTest.class, - StateSystemFullHistoryTest.class}) +@Suite.SuiteClasses({ + CtfKernelStateInputTest.class, + StateSystemFullHistoryTest.class, + StateSystemInMemoryTest.class +}) public class TestAll { - /** - * Launch the test. - * - * @param args - * the command line arguments - */ - public static void main(String[] args) { - JUnitCore.runClasses(new Class[] { TestAll.class }); - } } diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/StateSystemPushPopTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/StateSystemPushPopTest.java index 281ac85195..6f8154acca 100644 --- a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/StateSystemPushPopTest.java +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/StateSystemPushPopTest.java @@ -18,9 +18,9 @@ import java.util.List; import junit.framework.TestCase; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.IStateHistoryBackend; import org.eclipse.linuxtools.internal.tmf.core.statesystem.StateSystem; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree.HistoryTreeBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree.HistoryTreeBackend; import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/VerifyHistoryFile.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/VerifyHistoryFile.java index d775dc39a8..aba79a9e41 100644 --- a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/VerifyHistoryFile.java +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/VerifyHistoryFile.java @@ -17,8 +17,8 @@ import java.io.IOException; import java.util.List; import org.eclipse.linuxtools.internal.tmf.core.statesystem.HistoryBuilder; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.IStateHistoryBackend; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree.HistoryTreeBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree.HistoryTreeBackend; import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; diff --git a/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF index b45e159217..af21aa7293 100644 --- a/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF @@ -16,7 +16,8 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.core;x-friends:="org.eclipse org.eclipse.linuxtools.internal.tmf.core.component;x-friends:="org.eclipse.linuxtools.tmf.core.tests", org.eclipse.linuxtools.internal.tmf.core.request;x-friends:="org.eclipse.linuxtools.tmf.core.tests", org.eclipse.linuxtools.internal.tmf.core.statesystem;x-friends:="org.eclipse.linuxtools.tmf.core.tests", - org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree;x-friends:="org.eclipse.linuxtools.tmf.core.tests", + org.eclipse.linuxtools.internal.tmf.core.statesystem.backends;x-friends:="org.eclipse.linuxtools.tmf.core.tests", + org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;x-friends:="org.eclipse.linuxtools.tmf.core.tests", org.eclipse.linuxtools.internal.tmf.core.trace;x-friends:="org.eclipse.linuxtools.tmf.core.tests", org.eclipse.linuxtools.tmf.core, org.eclipse.linuxtools.tmf.core.component, diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/HistoryBuilder.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/HistoryBuilder.java index de62ee1da3..edd2aac2eb 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/HistoryBuilder.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/HistoryBuilder.java @@ -14,6 +14,7 @@ package org.eclipse.linuxtools.internal.tmf.core.statesystem; import java.io.IOException; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; import org.eclipse.linuxtools.tmf.core.component.TmfComponent; import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange; @@ -54,26 +55,22 @@ public class HistoryBuilder extends TmfComponent { * @param stateChangeInput * The input plugin to use. This is required. * @param backend - * The backend storage to use. + * The back-end storage to use. * @param buildManually * Should we build this history in-band or not. True means we * will start the building ourselves and block the caller until * construction is done. False (out-of-band) means we will start * listening for the signal and return immediately. Another * signal will be sent when finished. - * @throws IOException - * Is thrown if anything went wrong (usually with the storage - * backend) */ public HistoryBuilder(IStateChangeInput stateChangeInput, - IStateHistoryBackend backend, boolean buildManually) - throws IOException { + IStateHistoryBackend backend, boolean buildManually) { if (stateChangeInput == null || backend == null) { throw new IllegalArgumentException(); } sci = stateChangeInput; hb = backend; - ss = new StateSystem(hb, true); + ss = new StateSystem(hb); sci.assignTargetStateSystem(ss); diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/StateSystem.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/StateSystem.java index a77c8557ab..c2891b51aa 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/StateSystem.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/StateSystem.java @@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.linuxtools.internal.tmf.core.Activator; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; @@ -59,11 +60,24 @@ public class StateSystem implements ITmfStateSystemBuilder { private boolean buildCancelled = false; private boolean isDisposed = false; + /** + * New-file constructor. For when you build a state system with a new file, + * or if the back-end does not require a file on disk. + * + * @param backend + * Back-end plugin to use + */ + public StateSystem(IStateHistoryBackend backend) { + this.backend = backend; + this.transState = new TransientState(backend); + this.attributeTree = new AttributeTree(this); + } + /** * General constructor * * @param backend - * The "state history storage" backend to use. + * The "state history storage" back-end to use. * @param newFile * Put true if this is a new history started from scratch. It is * used to tell the state system where to get its attribute tree. diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/TransientState.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/TransientState.java index 26f163cc90..0b9f66a310 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/TransientState.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/TransientState.java @@ -16,6 +16,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException; import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/IStateHistoryBackend.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/IStateHistoryBackend.java similarity index 99% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/IStateHistoryBackend.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/IStateHistoryBackend.java index 4a44e154b7..8877018241 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/IStateHistoryBackend.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/IStateHistoryBackend.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends; import java.io.File; import java.io.FileInputStream; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/InMemoryBackend.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/InMemoryBackend.java new file mode 100644 index 0000000000..3ff4038f35 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/InMemoryBackend.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2013 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: + * Alexandre Montplaisir - Initial API and implementation + ******************************************************************************/ + +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends; + +import java.io.File; +import java.io.FileInputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException; +import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; +import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; +import org.eclipse.linuxtools.tmf.core.interval.TmfIntervalEndComparator; +import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval; +import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue; + +/** + * State history back-end that stores its intervals in RAM only. It cannot be + * saved to disk, which means we need to rebuild it every time we re-open a + * trace. But it's relatively quick to build, so this shouldn't be a problem in + * most cases. + * + * This should only be used with very small state histories (and/or, very small + * traces). Since it's stored in standard Collections, it's limited to 2^31 + * intervals. + * + * @author Alexandre Montplaisir + */ +public class InMemoryBackend implements IStateHistoryBackend { + + private final static Comparator endComparator = + new TmfIntervalEndComparator(); + + private final List intervals; + private final long startTime; + private long latestTime; + + /** + * Constructor + * + * @param startTime + * The start time of this interval store + */ + public InMemoryBackend(long startTime) { + this.startTime = startTime; + this.latestTime = startTime; + this.intervals = new ArrayList(); + } + + @Override + public long getStartTime() { + return startTime; + } + + @Override + public long getEndTime() { + return latestTime; + } + + @Override + public void insertPastState(long stateStartTime, long stateEndTime, + int quark, ITmfStateValue value) throws TimeRangeException { + /* Make sure the passed start/end times make sense */ + if (stateStartTime > stateEndTime || stateStartTime < startTime) { + throw new TimeRangeException(); + } + + ITmfStateInterval interval = new TmfStateInterval(stateStartTime, stateEndTime, quark, value); + + /* Update the "latest seen time" */ + if (stateEndTime > latestTime) { + latestTime = stateEndTime; + } + + /* Add the interval into the-array */ + intervals.add(interval); + } + + + @Override + public void doQuery(List currentStateInfo, long t) + throws TimeRangeException { + if (!checkValidTime(t)) { + throw new TimeRangeException(); + } + + /* + * The intervals are sorted by end time, so we can binary search to get + * the first possible interval, then only compare their start times. + */ + ITmfStateInterval entry; + for (int i = binarySearchEndTime(intervals, t); i < intervals.size(); i++) { + entry = intervals.get(i); + if (entry.getStartTime() <= t) { + /* Add this interval to the returned values */ + currentStateInfo.set(entry.getAttribute(), entry); + } + } + } + + @Override + public ITmfStateInterval doSingularQuery(long t, int attributeQuark) + throws TimeRangeException, AttributeNotFoundException { + if (!checkValidTime(t)) { + throw new TimeRangeException(); + } + + /* + * The intervals are sorted by end time, so we can binary search to get + * the first possible interval, then only compare their start times. + */ + ITmfStateInterval entry; + for (int i = binarySearchEndTime(intervals, t); i < intervals.size(); i++) { + entry = intervals.get(i); + if (entry.getStartTime() <= t && entry.getAttribute() == attributeQuark) { + /* This is the droid we are looking for */ + return entry; + } + } + throw new AttributeNotFoundException(); + } + + @Override + public boolean checkValidTime(long t) { + if (t >= startTime && t <= latestTime) { + return true; + } + return false; + } + + @Override + public void finishedBuilding(long endTime) throws TimeRangeException { + /* Nothing to do */ + } + + @Override + public FileInputStream supplyAttributeTreeReader() { + /* Saving to disk not supported */ + return null; + } + + @Override + public File supplyAttributeTreeWriterFile() { + /* Saving to disk not supported */ + return null; + } + + @Override + public long supplyAttributeTreeWriterFilePosition() { + /* Saving to disk not supported */ + return -1; + } + + @Override + public void removeFiles() { + /* Nothing to do */ + } + + @Override + public void dispose() { + /* Nothing to do */ + } + + @Override + public void debugPrint(PrintWriter writer) { + writer.println(intervals.toString()); + } + + private static int binarySearchEndTime(List list, long time) { + ITmfStateInterval dummyInterval = new TmfStateInterval(-1, time, -1, null); + int mid = Collections.binarySearch(list, dummyInterval, endComparator); + + /* The returned value is < 0 if the exact key was not found. */ + if (mid < 0) { + mid = -mid; + } + + /* + * Collections.binarySearch doesn't guarantee which element is returned + * if it falls on one of many equal ones. So make sure we are at the + * first one provided. + */ + while ((mid > 0) && + (list.get(mid).getEndTime() == list.get(mid-1).getEndTime())) { + mid--; + } + return mid; + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/NullBackend.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/NullBackend.java new file mode 100644 index 0000000000..88c3cc9701 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/NullBackend.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2013 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: + * Alexandre Montplaisir - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends; + +import java.io.File; +import java.io.FileInputStream; +import java.io.PrintWriter; +import java.util.List; + +import org.eclipse.linuxtools.internal.tmf.core.statesystem.StateSystem; +import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; +import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue; + +/** + * An implement of a state history back-end to simply discards *all* the + * intervals it receives. Obviously, no queries can be done on it. It is useful + * for using with a {@link StateSystem} on which you will only want to do + * "ongoing" requests. + * + * @author Alexandre Montplaisir + */ +public class NullBackend implements IStateHistoryBackend { + + /** + * Constructor + */ + public NullBackend() {} + + @Override + public long getStartTime() { + return 0; + } + + @Override + public long getEndTime() { + return 0; + } + + /** + * The interval will be discarded when using a null backend. + */ + @Override + public void insertPastState(long stateStartTime, long stateEndTime, + int quark, ITmfStateValue value) { + /* The interval is always discarded. */ + } + + @Override + public void finishedBuilding(long endTime) { + /* Nothing to do */ + } + + @Override + public FileInputStream supplyAttributeTreeReader() { + return null; + } + + @Override + public File supplyAttributeTreeWriterFile() { + return null; + } + + @Override + public long supplyAttributeTreeWriterFilePosition() { + return -1; + } + + @Override + public void removeFiles() { + /* Nothing to do */ + } + + @Override + public void dispose() { + /* Nothing to do */ + } + + /** + * Null back-ends cannot run queries. Nothing will be put in + * currentStateInfo. + */ + @Override + public void doQuery(List currentStateInfo, long t) { + /* Cannot do past queries */ + } + + /** + * Null back-ends cannot run queries. 'null' will be returned. + * + * @return Always returns null. + */ + @Override + public ITmfStateInterval doSingularQuery(long t, int attributeQuark) { + /* Cannot do past queries */ + return null; + } + + /** + * Null back-ends cannot run queries. + * + * @return Always returns false. + */ + @Override + public boolean checkValidTime(long t) { + /* Cannot do past queries */ + return false; + } + + @Override + public void debugPrint(PrintWriter writer) { + writer.println("Null history backend"); //$NON-NLS-1$ + } +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/CoreNode.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/CoreNode.java similarity index 98% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/CoreNode.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/CoreNode.java index 21866f377a..f2e2cf0f20 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/CoreNode.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/CoreNode.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.nio.ByteBuffer; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTConfig.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTConfig.java similarity index 94% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTConfig.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTConfig.java index 126750b322..9bdbfb3366 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTConfig.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTConfig.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.File; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTInterval.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTInterval.java similarity index 99% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTInterval.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTInterval.java index 0432f4e2de..5312c62812 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTInterval.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTInterval.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.IOException; import java.nio.ByteBuffer; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTNode.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTNode.java similarity index 99% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTNode.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTNode.java index 12b10724c0..465b252475 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HTNode.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTNode.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.IOException; import java.io.PrintWriter; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HT_IO.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HT_IO.java similarity index 98% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HT_IO.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HT_IO.java index 7495eb1b2f..b9994825e0 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HT_IO.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HT_IO.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.File; import java.io.FileInputStream; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HistoryTree.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTree.java similarity index 99% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HistoryTree.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTree.java index 576b0490b7..ac04265bbe 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HistoryTree.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTree.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.File; import java.io.FileInputStream; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HistoryTreeBackend.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTreeBackend.java similarity index 98% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HistoryTreeBackend.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTreeBackend.java index d794831301..ef13e62d3b 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/HistoryTreeBackend.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTreeBackend.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.File; import java.io.FileInputStream; @@ -19,7 +19,7 @@ import java.io.PrintWriter; import java.nio.channels.ClosedChannelException; import java.util.List; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.IStateHistoryBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException; import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException; import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/ThreadedHistoryTreeBackend.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/ThreadedHistoryTreeBackend.java similarity index 98% rename from org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/ThreadedHistoryTreeBackend.java rename to org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/ThreadedHistoryTreeBackend.java index 820a44a933..5bc09c7855 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/historytree/ThreadedHistoryTreeBackend.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/ThreadedHistoryTreeBackend.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree; +package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree; import java.io.File; import java.io.IOException; diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/interval/TmfIntervalEndComparator.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/interval/TmfIntervalEndComparator.java new file mode 100644 index 0000000000..a9076b2928 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/interval/TmfIntervalEndComparator.java @@ -0,0 +1,29 @@ +package org.eclipse.linuxtools.tmf.core.interval; + +import java.util.Comparator; + +/** + * Comparator for ITmfStateInterval, using their *end times*. Making intervals + * Comparable wouldn't be clear if it's using their start or end times (or maybe + * even values), so separate comparators are provided. + * + * @author Alexandre Montplaisir + * @since 2.0 + */ +public class TmfIntervalEndComparator implements Comparator { + + @Override + public int compare(ITmfStateInterval o1, ITmfStateInterval o2) { + long e1 = o1.getEndTime(); + long e2 = o2.getEndTime(); + + if (e1 < e2) { + return -1; + } else if (e1 > e2) { + return 1; + } else { + return 0; + } + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statesystem/StateSystemManager.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statesystem/StateSystemManager.java index b73714ee3e..205bdfa1ce 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statesystem/StateSystemManager.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statesystem/StateSystemManager.java @@ -16,9 +16,11 @@ import java.io.File; import java.io.IOException; import org.eclipse.linuxtools.internal.tmf.core.statesystem.HistoryBuilder; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.IStateHistoryBackend; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree.HistoryTreeBackend; -import org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree.ThreadedHistoryTreeBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.InMemoryBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.NullBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree.HistoryTreeBackend; +import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree.ThreadedHistoryTreeBackend; import org.eclipse.linuxtools.tmf.core.component.TmfComponent; import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; @@ -102,4 +104,47 @@ public abstract class StateSystemManager extends TmfComponent { } return builder.getStateSystemQuerier(); } + + /** + * Create a new state system using a null history back-end. This means that + * no history intervals will be saved anywhere, and as such only + * {@link ITmfStateSystem#queryOngoingState} will be available. + * + * This has to be built "manually" (which means you should call + * input.processEvent() to update the ongoing state of the state system). + * + * @param input + * The input plugin to build the history + * @return Reference to the history-less state system that got built + * @since 2.0 + */ + public static ITmfStateSystem newNullHistory(IStateChangeInput input) { + IStateHistoryBackend backend = new NullBackend(); + HistoryBuilder builder = new HistoryBuilder(input, backend, true); + ITmfStateSystem ss = builder.getStateSystemQuerier(); + return ss; + } + + /** + * Create a new state system using in-memory interval storage. This should + * only be done for very small state system, and will be naturally limited + * to 2^31 intervals. + * + * This will block the caller while the construction is ongoing. + * + * @param input + * The state change input to use + * @param buildManually + * Set to true to block the caller and build without using TMF + * signals (for test programs most of the time). Use false if you + * are using the TMF facilities (experiments, etc.) + * @return Reference to the state system that just got built + * @since 2.0 + */ + public static ITmfStateSystem newInMemHistory(IStateChangeInput input, + boolean buildManually) { + IStateHistoryBackend backend = new InMemoryBackend(input.getStartTime()); + HistoryBuilder builder = new HistoryBuilder(input, backend, buildManually); + return builder.getStateSystemQuerier(); + } } -- 2.34.1