From e73a4ba51dcd98bfe18f94b0f58748a14761f540 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Genevi=C3=A8ve=20Bastien?= Date: Thu, 17 Jan 2013 11:52:32 -0500 Subject: [PATCH] Tmf: Trace synchronization using network events MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * Event matching infrastructure allow to create dependencies between 2 events. * Network events (TCP packets) are matched for LTTng 2.0 traces, using one of two techniques: fgiraldeau's dynamic probe addon module, or an experimental branch with additional data on net_* tracepoints of lttng-modules. * Traces in an experiment are synchronized using the Fully Incremental Convex Hull algorithm. * A trace's timestamps can be modified using Timestamp Transforms classes. TmfTimestampTransformLinear takes a slope and/or an offset. * Once synchronized, the trace is copied, without its supplementary files so the state system is regenerated with synchronized time. * A new synchronization view shows statistics about the synchronization. * The synchronization information is kept at the experiment level to be able to view synchronization's statistics after first sync. * Synchronization formula for a trace is saved in supplementary files. * Unit tests for trace synchronization. Change-Id: I1971fcd856254fc5654c609d6146904cd3dfd25c Signed-off-by: Geneviève Bastien Reviewed-on: https://git.eclipse.org/r/14056 Tested-by: Hudson CI Reviewed-by: Bernd Hufmann IP-Clean: Bernd Hufmann Tested-by: Bernd Hufmann --- .../ctf/core/tests/shared/CtfTestTraces.java | 4 +- .../traces/.gitignore | 1 + .../traces/get-traces.sh | 4 + .../traces/get-traces.xml | 4 + .../META-INF/MANIFEST.MF | 10 +- .../lttng2/kernel/core/tests/AllTests.java | 3 +- .../tests/event/matchandsync/AllTests.java | 28 + .../matchandsync/ExperimentSyncTest.java | 100 +++ .../event/matchandsync/MatchAndSyncTest.java | 63 ++ .../META-INF/MANIFEST.MF | 3 +- .../lttng2/kernel/core/Activator.java | 5 + .../lttng2/kernel/core/TcpEventStrings.java | 60 ++ .../core/event/matching/TcpEventMatching.java | 87 +++ .../event/matching/TcpLttngEventMatching.java | 116 ++++ .../core/tests/shared/CtfTmfTestTraces.java | 2 +- .../tmf/core/tests/AllTmfCoreTests.java | 1 + .../core/tests/synchronization/AllTests.java | 26 + .../core/tests/synchronization/SyncTest.java | 240 ++++++++ .../synchronization/TsTransformTest.java | 144 +++++ .../tmf/core/tests/trace/TmfTraceTest.java | 8 +- .../tests/stubs/event/TmfSyncEventStub.java | 45 ++ .../META-INF/MANIFEST.MF | 2 + .../tmf/core/ctfadaptor/CtfTmfEvent.java | 1 + .../core/ctfadaptor/CtfTmfEventFactory.java | 3 +- .../tmf/core/ctfadaptor/CtfTmfTrace.java | 15 +- .../event/matching/IMatchProcessingUnit.java | 56 ++ .../event/matching/ITmfEventMatching.java | 31 + .../matching/ITmfMatchEventDefinition.java | 56 ++ .../event/matching/TmfEventDependency.java | 60 ++ .../core/event/matching/TmfEventMatches.java | 82 +++ .../core/event/matching/TmfEventMatching.java | 275 +++++++++ .../matching/TmfNetworkEventMatching.java | 226 +++++++ .../matching/TmfNetworkMatchDefinition.java | 37 ++ .../signal/TmfTraceSynchronizedSignal.java | 53 ++ .../ITmfTimestampTransform.java | 55 ++ .../tmf/core/synchronization/Messages.java | 53 ++ .../SyncAlgorithmFullyIncremental.java | 572 ++++++++++++++++++ .../SynchronizationAlgorithm.java | 135 +++++ .../SynchronizationBackend.java | 219 +++++++ .../SynchronizationManager.java | 133 ++++ .../TmfTimestampTransform.java | 79 +++ .../TmfTimestampTransformLinear.java | 148 +++++ .../core/synchronization/messages.properties | 21 + .../tmf/core/timestamp/TmfTimestamp.java | 21 +- .../linuxtools/tmf/core/trace/ITmfTrace.java | 104 +++- .../tmf/core/trace/TmfExperiment.java | 117 +++- .../linuxtools/tmf/core/trace/TmfTrace.java | 114 +++- .../META-INF/MANIFEST.MF | 1 + .../icons/eview16/synced.gif | Bin 0 -> 160 bytes .../plugin.properties | 6 + org.eclipse.linuxtools.tmf.ui/plugin.xml | 56 ++ .../tmf/ui/project/handlers/Messages.java | 11 +- .../handlers/OpenExperimentHandler.java | 3 +- .../handlers/SynchronizeTracesHandler.java | 250 ++++++++ .../ui/project/handlers/messages.properties | 10 + .../project/model/TmfWithFolderElement.java | 4 +- .../ui/views/synchronization/Messages.java | 33 + .../TmfSynchronizationView.java | 127 ++++ .../views/synchronization/messages.properties | 2 + 59 files changed, 4060 insertions(+), 65 deletions(-) create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/AllTests.java create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/ExperimentSyncTest.java create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/MatchAndSyncTest.java create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/TcpEventStrings.java create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpEventMatching.java create mode 100644 org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpLttngEventMatching.java create mode 100644 org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/AllTests.java create mode 100644 org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/SyncTest.java create mode 100644 org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/TsTransformTest.java create mode 100644 org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/event/TmfSyncEventStub.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/IMatchProcessingUnit.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfEventMatching.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfMatchEventDefinition.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventDependency.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatches.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatching.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkEventMatching.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkMatchDefinition.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceSynchronizedSignal.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/ITmfTimestampTransform.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/Messages.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationAlgorithm.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationBackend.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationManager.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransform.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransformLinear.java create mode 100644 org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/messages.properties create mode 100644 org.eclipse.linuxtools.tmf.ui/icons/eview16/synced.gif create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/Messages.java create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/TmfSynchronizationView.java create mode 100644 org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/messages.properties diff --git a/org.eclipse.linuxtools.ctf.core.tests/shared/org/eclipse/linuxtools/ctf/core/tests/shared/CtfTestTraces.java b/org.eclipse.linuxtools.ctf.core.tests/shared/org/eclipse/linuxtools/ctf/core/tests/shared/CtfTestTraces.java index 1f8f14f99d..9128c73cef 100644 --- a/org.eclipse.linuxtools.ctf.core.tests/shared/org/eclipse/linuxtools/ctf/core/tests/shared/CtfTestTraces.java +++ b/org.eclipse.linuxtools.ctf.core.tests/shared/org/eclipse/linuxtools/ctf/core/tests/shared/CtfTestTraces.java @@ -30,7 +30,9 @@ public abstract class CtfTestTraces { private static final String[] testTracePaths = { "../org.eclipse.linuxtools.ctf.core.tests/traces/kernel", "../org.eclipse.linuxtools.ctf.core.tests/traces/trace2", - "../org.eclipse.linuxtools.ctf.core.tests/traces/kernel_vm" + "../org.eclipse.linuxtools.ctf.core.tests/traces/kernel_vm", + "../org.eclipse.linuxtools.ctf.core.tests/traces/synctraces/scp_src", + "../org.eclipse.linuxtools.ctf.core.tests/traces/synctraces/scp_dest" }; private static CTFTrace[] testTraces = new CTFTrace[testTracePaths.length]; diff --git a/org.eclipse.linuxtools.ctf.core.tests/traces/.gitignore b/org.eclipse.linuxtools.ctf.core.tests/traces/.gitignore index 0d74bee223..4194ab3cbe 100644 --- a/org.eclipse.linuxtools.ctf.core.tests/traces/.gitignore +++ b/org.eclipse.linuxtools.ctf.core.tests/traces/.gitignore @@ -3,6 +3,7 @@ /ctf-testsuite /kernel /kernel_vm +/synctraces /trace2 *.ht diff --git a/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.sh b/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.sh index 4abdb9512b..71ef35378d 100755 --- a/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.sh +++ b/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.sh @@ -24,3 +24,7 @@ wget http://www.dorsal.polymtl.ca/~alexmont/data/kernel_vm.tar.bz2 -O- | tar xvj # CTF test suite, used for testing CTF parser compliance git clone https://github.com/efficios/ctf-testsuite.git + +# Trace used by the lttng2 kernel to match packets and synchronize +wget http://www.dorsal.polymtl.ca/~gbastien/traces/synctraces.tar.gz -O- | tar xvzf - && + diff --git a/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.xml b/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.xml index 09d04104c6..b860ebaa84 100644 --- a/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.xml +++ b/org.eclipse.linuxtools.ctf.core.tests/traces/get-traces.xml @@ -14,6 +14,7 @@ + @@ -29,6 +30,7 @@ + @@ -44,9 +46,11 @@ + + diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.lttng2.kernel.core.tests/META-INF/MANIFEST.MF index be9524cbe9..83dd1378d5 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.core.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/META-INF/MANIFEST.MF @@ -11,7 +11,9 @@ Require-Bundle: org.junit;bundle-version="4.0.0", org.eclipse.core.runtime, org.eclipse.linuxtools.tmf.core;bundle-version="3.0.0", org.eclipse.linuxtools.tmf.core.tests;bundle-version="3.0.0", - org.eclipse.linuxtools.lttng2.kernel.core;bundle-version="3.0.0" -Export-Package: org.eclipse.linuxtools.lttng2.kernel.core.tests;x-friends:="org.eclipse.linuxtools.lttng.alltests", - org.eclipse.linuxtools.lttng2.kernel.core.tests.headless;x-internal:=true, - org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider;x-internal:=true + org.eclipse.linuxtools.lttng2.kernel.core;bundle-version="3.0.0", + org.eclipse.core.resources +Export-Package: org.eclipse.linuxtools.lttng2.kernel.core.tests, + org.eclipse.linuxtools.lttng2.kernel.core.tests.event.matchandsync, + org.eclipse.linuxtools.lttng2.kernel.core.tests.headless, + org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider 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 682e4000bc..e6f3cb60bd 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 @@ -21,6 +21,7 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ ActivatorTest.class, - org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider.TestAll.class + org.eclipse.linuxtools.lttng2.kernel.core.tests.stateprovider.TestAll.class, + org.eclipse.linuxtools.lttng2.kernel.core.tests.event.matchandsync.AllTests.class }) public class AllTests { } diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/AllTests.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/AllTests.java new file mode 100644 index 0000000000..9a37836eb6 --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/AllTests.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.tests.event.matchandsync; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Test suite for org.eclipse.linuxtools.lttng2.kernel.core.tests.event.matching + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + MatchAndSyncTest.class, + ExperimentSyncTest.class +}) +public class AllTests { + +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/ExperimentSyncTest.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/ExperimentSyncTest.java new file mode 100644 index 0000000000..6267b03c1c --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/ExperimentSyncTest.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.tests.event.matchandsync; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpEventMatching; +import org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpLttngEventMatching; +import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTrace; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching; +import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; +import org.eclipse.linuxtools.tmf.core.synchronization.ITmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm; +import org.eclipse.linuxtools.tmf.core.synchronization.TmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.tests.shared.CtfTmfTestTraces; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; +import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for experiment syncing + * + * @author Geneviève Bastien + */ +@SuppressWarnings("nls") +public class ExperimentSyncTest { + + private static final String EXPERIMENT = "MyExperiment"; + private static int BLOCK_SIZE = 1000; + + private static ITmfTrace[] fTraces; + private static TmfExperiment fExperiment; + + /** + * Setup the traces and experiment + */ + @Before + public void setUp() { + CtfTmfTrace trace1 = CtfTmfTestTraces.getTestTrace(3); + CtfTmfTrace trace2 = CtfTmfTestTraces.getTestTrace(4); + + fTraces = new CtfTmfTrace[2]; + fTraces[0] = trace1; + fTraces[1] = trace2; + + fExperiment = new TmfExperiment(trace1.getEventType(), EXPERIMENT, fTraces, BLOCK_SIZE); + + TmfEventMatching.registerMatchObject(new TcpEventMatching()); + TmfEventMatching.registerMatchObject(new TcpLttngEventMatching()); + } + + /** + * Reset the timestamp transforms on the traces + */ + @After + public void cleanUp() { + fTraces[0].setTimestampTransform(TmfTimestampTransform.IDENTITY); + fTraces[1].setTimestampTransform(TmfTimestampTransform.IDENTITY); + } + + /** + * Testing experiment synchronization + */ + @Test + public void testExperimentSync() { + try { + SynchronizationAlgorithm syncAlgo = fExperiment.synchronizeTraces(true); + + ITmfTimestampTransform tt1, tt2; + + tt1 = syncAlgo.getTimestampTransform(fTraces[0]); + tt2 = syncAlgo.getTimestampTransform(fTraces[1]); + + fTraces[0].setTimestampTransform(tt1); + fTraces[1].setTimestampTransform(tt2); + + assertEquals("TmfTimestampTransform [ IDENTITY ]", tt2.toString()); + assertEquals("TmfTimestampLinear [ alpha = 0.9999413783703139011056845831168394, beta = 79796507913179.33347660124688298171 ]", tt1.toString()); + + assertEquals(syncAlgo.getTimestampTransform(fTraces[0].getName()),fTraces[0].getTimestampTransform()); + assertEquals(syncAlgo.getTimestampTransform(fTraces[1].getName()),fTraces[1].getTimestampTransform()); + + } catch (TmfTraceException e) { + fail("Exception thrown in experiment synchronization " + e.getMessage()); + } + } +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/MatchAndSyncTest.java b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/MatchAndSyncTest.java new file mode 100644 index 0000000000..b036336b65 --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core.tests/src/org/eclipse/linuxtools/lttng2/kernel/core/tests/event/matchandsync/MatchAndSyncTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.tests.event.matchandsync; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpEventMatching; +import org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpLttngEventMatching; +import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTrace; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkEventMatching; +import org.eclipse.linuxtools.tmf.core.tests.shared.CtfTmfTestTraces; +import org.junit.Test; + +/** + * Tests for {@link TcpEventMatching} + * + * @author Geneviève Bastien + */ +@SuppressWarnings("nls") +public class MatchAndSyncTest { + + /** + * Testing the packet matching + */ + @Test + public void testMatching() { + final String cr = System.getProperty("line.separator"); + CtfTmfTrace trace1 = CtfTmfTestTraces.getTestTrace(3); + CtfTmfTrace trace2 = CtfTmfTestTraces.getTestTrace(4); + + CtfTmfTrace[] tracearr = new CtfTmfTrace[2]; + tracearr[0] = trace1; + tracearr[1] = trace2; + + TmfEventMatching.registerMatchObject(new TcpEventMatching()); + TmfEventMatching.registerMatchObject(new TcpLttngEventMatching()); + + TmfNetworkEventMatching twoTraceMatch = new TmfNetworkEventMatching(tracearr); + assertTrue(twoTraceMatch.matchEvents()); + + String stats = twoTraceMatch.toString(); + assertEquals("TmfEventMatches [ Number of matches found: 46 ]" + + "Trace 0:" + cr + + " 3 unmatched incoming events" + cr + + " 2 unmatched outgoing events" + cr + + "Trace 1:" + cr + + " 2 unmatched incoming events" + cr + + " 1 unmatched outgoing events" + cr, stats); + } + +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.lttng2.kernel.core/META-INF/MANIFEST.MF index 7e84ee5353..2ba6f2e26e 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.core/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.lttng2.kernel.core/META-INF/MANIFEST.MF @@ -14,4 +14,5 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.linuxtools.tmf.core;bundle-version="3.0.0" Export-Package: org.eclipse.linuxtools.internal.lttng2.kernel.core;x-friends:="org.eclipse.linuxtools.lttng2.kernel.ui,org.eclipse.linuxtools.lttng2.kernel.core.tests", org.eclipse.linuxtools.internal.lttng2.kernel.core.stateprovider;x-friends:="org.eclipse.linuxtools.lttng2.kernel.core.tests", - org.eclipse.linuxtools.lttng2.kernel.core.trace + org.eclipse.linuxtools.lttng2.kernel.core.trace, + org.eclipse.linuxtools.lttng2.kernel.core.event.matching diff --git a/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/Activator.java b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/Activator.java index d0270fdc24..8629784bc4 100644 --- a/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/Activator.java +++ b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/Activator.java @@ -15,6 +15,9 @@ package org.eclipse.linuxtools.internal.lttng2.kernel.core; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Status; +import org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpEventMatching; +import org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpLttngEventMatching; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching; import org.osgi.framework.BundleContext; /** @@ -69,6 +72,8 @@ public class Activator extends Plugin { public void start(BundleContext context) throws Exception { super.start(context); plugin = this; + TmfEventMatching.registerMatchObject(new TcpEventMatching()); + TmfEventMatching.registerMatchObject(new TcpLttngEventMatching()); } @Override diff --git a/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/TcpEventStrings.java b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/TcpEventStrings.java new file mode 100644 index 0000000000..2891210aa4 --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/TcpEventStrings.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial API and implementation + ******************************************************************************/ + +package org.eclipse.linuxtools.internal.lttng2.kernel.core; + +/** + * This file defines all the known event and field names used to trace socket + * connection for both the addons module method ( + * {@link org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpEventMatching} + * ) and the net_data_experimental branch ( + * {@link org.eclipse.linuxtools.lttng2.kernel.core.event.matching.TcpLttngEventMatching} + * ). + * + * These events should be eventually mainlined and when this happens, this class + * won't be necessary anymore and they should be moved to {@link LttngStrings} + * class + * + * + * @author Geneviève Bastien + */ +@SuppressWarnings({ "javadoc", "nls" }) +public interface TcpEventStrings { + + /* Event names */ + public static final String INET_CONNECT = "inet_connect"; + public static final String INET_SOCK_CREATE = "inet_sock_create"; + public static final String INET_SOCK_LOCAL_OUT = "inet_sock_local_out"; + public static final String INET_SOCK_LOCAL_IN = "inet_sock_local_in"; + public static final String INET_SOCK_CLONE = "inet_sock_clone"; + public static final String INET_ACCEPT = "inet_accept"; + public static final String INET_SOCK_DELETE = "inet_sock_delete"; + public static final String NETIF_RECEIVE_SKB = "netif_receive_skb"; + public static final String NET_DEV_QUEUE = "net_dev_queue"; + + /* Field names */ + public static final String SEQ = "seq"; + public static final String SK = "sk"; + public static final String OSK = "osk"; + public static final String NSK = "nsk"; + public static final String SPORT = "sport"; + public static final String DPORT = "dport"; + public static final String SADDR = "saddr"; + public static final String DADDR = "daddr"; + public static final String ACKSEQ = "ack_seq"; + public static final String CHECK = "check"; + public static final String WINDOW = "window"; + public static final String FLAGS = "flags"; + public static final String TRANSPORT_FIELDS = "transport_fields"; + public static final String TYPE_TCP = "thtype_tcp"; + +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpEventMatching.java b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpEventMatching.java new file mode 100644 index 0000000000..7f9952a52f --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpEventMatching.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.event.matching; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.linuxtools.internal.lttng2.kernel.core.TcpEventStrings; +import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTrace; +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching.MatchingType; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkEventMatching.Direction; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkMatchDefinition; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Class to match tcp type events. This matching class applies to traces + * obtained with the 'addons' lttng module. This module can be obtained with + * lttng-modules to generate traces at + * https://github.com/giraldeau/lttng-modules/tree/addons + * + * Note: this module only allows to generate traces to be read and analyzed by + * TMF, no code from this module is being used here + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TcpEventMatching extends TmfNetworkMatchDefinition { + + @Override + public Direction getDirection(ITmfEvent event) { + String evname = event.getType().getName(); + /* Is the event a tcp socket in or out event */ + if (evname.equals(TcpEventStrings.INET_SOCK_LOCAL_IN)) { + return Direction.IN; + } else if (evname.equals(TcpEventStrings.INET_SOCK_LOCAL_OUT)) { + return Direction.OUT; + } + return null; + } + + /** + * The key to uniquely identify a TCP packet depends on many fields. This + * method computes the key for a given event. + * + * @param event + * The event for which to compute the key + * @return the unique key for this event + */ + @Override + public List getUniqueField(ITmfEvent event) { + List keys = new ArrayList(); + + keys.add(event.getContent().getField(TcpEventStrings.SEQ).getValue()); + keys.add(event.getContent().getField(TcpEventStrings.ACKSEQ).getValue()); + keys.add(event.getContent().getField(TcpEventStrings.FLAGS).getValue()); + + return keys; + } + + @Override + public boolean canMatchTrace(ITmfTrace trace) { + if (!(trace instanceof CtfTmfTrace)) { + return false; + } + CtfTmfTrace ktrace = (CtfTmfTrace) trace; + String[] events = { TcpEventStrings.INET_SOCK_LOCAL_IN, TcpEventStrings.INET_SOCK_LOCAL_OUT }; + return ktrace.hasAtLeastOneOfEvents(events); + } + + @Override + public MatchingType[] getApplicableMatchingTypes() { + MatchingType[] types = { MatchingType.NETWORK }; + return types; + } + +} diff --git a/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpLttngEventMatching.java b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpLttngEventMatching.java new file mode 100644 index 0000000000..ca9d95bb99 --- /dev/null +++ b/org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/lttng2/kernel/core/event/matching/TcpLttngEventMatching.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng2.kernel.core.event.matching; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.linuxtools.internal.lttng2.kernel.core.TcpEventStrings; +import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTrace; +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.event.ITmfEventField; +import org.eclipse.linuxtools.tmf.core.event.TmfEventField; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching.MatchingType; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkEventMatching.Direction; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkMatchDefinition; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Class to match tcp type events. This class applies to traces obtained with + * the full network tracepoint data available from an experimental branch of + * lttng-modules. This branch is often rebased on lttng-modules master and is + * available at + * http://git.dorsal.polymtl.ca/~gbastien?p=lttng-modules.git;a=summary + * net_data_experimental branch. + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TcpLttngEventMatching extends TmfNetworkMatchDefinition { + + private static final String[] key_seq = { TcpEventStrings.TRANSPORT_FIELDS, TcpEventStrings.TYPE_TCP, TcpEventStrings.SEQ }; + private static final String[] key_ackseq = { TcpEventStrings.TRANSPORT_FIELDS, TcpEventStrings.TYPE_TCP, TcpEventStrings.ACKSEQ }; + private static final String[] key_flags = { TcpEventStrings.TRANSPORT_FIELDS, TcpEventStrings.TYPE_TCP, TcpEventStrings.FLAGS }; + + private static boolean canMatchPacket(final ITmfEvent event) { + TmfEventField field = (TmfEventField) event.getContent(); + + String[] tcp_data = { TcpEventStrings.TRANSPORT_FIELDS, TcpEventStrings.TYPE_TCP }; + ITmfEventField data = field.getSubField(tcp_data); + if (data != null) { + return (data.getValue() != null); + } + return false; + } + + /** + * The key to uniquely identify a TCP packet depends on many fields. This + * method computes the key for a given event. + * + * @param event + * The event for which to compute the key + * @return the unique key for this event + */ + @Override + public List getUniqueField(ITmfEvent event) { + List keys = new ArrayList(); + + TmfEventField field = (TmfEventField) event.getContent(); + ITmfEventField data; + + data = field.getSubField(key_seq); + if (data != null) { + keys.add(data.getValue()); + } + data = field.getSubField(key_ackseq); + if (data != null) { + keys.add(data.getValue()); + } + data = field.getSubField(key_flags); + if (data != null) { + keys.add(data.getValue()); + } + + return keys; + } + + @Override + public boolean canMatchTrace(ITmfTrace trace) { + if (!(trace instanceof CtfTmfTrace)) { + return false; + } + CtfTmfTrace ktrace = (CtfTmfTrace) trace; + String[] events = { TcpEventStrings.NET_DEV_QUEUE, TcpEventStrings.NETIF_RECEIVE_SKB }; + return (ktrace.hasAtLeastOneOfEvents(events)); + } + + @Override + public Direction getDirection(ITmfEvent event) { + String evname = event.getType().getName(); + + /* Is the event a tcp socket in or out event */ + if (evname.equals(TcpEventStrings.NETIF_RECEIVE_SKB) && canMatchPacket(event)) { + return Direction.IN; + } else if (evname.equals(TcpEventStrings.NET_DEV_QUEUE) && canMatchPacket(event)) { + return Direction.OUT; + } + return null; + } + + @Override + public MatchingType[] getApplicableMatchingTypes() { + MatchingType[] types = { MatchingType.NETWORK }; + return types; + } + +} diff --git a/org.eclipse.linuxtools.tmf.core.tests/shared/org/eclipse/linuxtools/tmf/core/tests/shared/CtfTmfTestTraces.java b/org.eclipse.linuxtools.tmf.core.tests/shared/org/eclipse/linuxtools/tmf/core/tests/shared/CtfTmfTestTraces.java index 9f4146d9f2..11de9adc4e 100644 --- a/org.eclipse.linuxtools.tmf.core.tests/shared/org/eclipse/linuxtools/tmf/core/tests/shared/CtfTmfTestTraces.java +++ b/org.eclipse.linuxtools.tmf.core.tests/shared/org/eclipse/linuxtools/tmf/core/tests/shared/CtfTmfTestTraces.java @@ -34,7 +34,7 @@ public final class CtfTmfTestTraces { private static final File emptyFile = new File(""); private static CtfTmfTrace emptyTrace = new CtfTmfTrace(); - private static CtfTmfTrace[] testTraces = new CtfTmfTrace[3]; + private static CtfTmfTrace[] testTraces = new CtfTmfTrace[5]; /** * Get an empty File (new File("");) diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java index 56ea7f2826..35dac22ebb 100644 --- a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java @@ -29,6 +29,7 @@ import org.junit.runners.Suite; org.eclipse.linuxtools.tmf.core.tests.signal.AllTests.class, org.eclipse.linuxtools.tmf.core.tests.statesystem.AllTests.class, org.eclipse.linuxtools.tmf.core.tests.statistics.AllTests.class, + org.eclipse.linuxtools.tmf.core.tests.synchronization.AllTests.class, org.eclipse.linuxtools.tmf.core.tests.trace.AllTests.class, org.eclipse.linuxtools.tmf.core.tests.trace.indexer.checkpoint.AllTests.class, org.eclipse.linuxtools.tmf.core.tests.trace.location.AllTests.class, diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/AllTests.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/AllTests.java new file mode 100644 index 0000000000..6a264ab741 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/AllTests.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.tests.synchronization; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Test suite for org.eclipse.linuxtools.tmf.core.synchronization + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ TsTransformTest.class, + SyncTest.class }) +public class AllTests { + +} diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/SyncTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/SyncTest.java new file mode 100644 index 0000000000..46742f4de6 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/SyncTest.java @@ -0,0 +1,240 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.tests.synchronization; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventDependency; +import org.eclipse.linuxtools.tmf.core.synchronization.ITmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.synchronization.SyncAlgorithmFullyIncremental; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm.SyncQuality; +import org.eclipse.linuxtools.tmf.core.synchronization.TmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; +import org.eclipse.linuxtools.tmf.tests.stubs.event.TmfSyncEventStub; +import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for {@link SynchronizationAlgorithm} and its descendants + * + * @author Geneviève Bastien + */ +@SuppressWarnings("nls") +public class SyncTest { + + private TmfTraceStub t1, t2; + private TmfTraceStub[] fTraces; + + /** + * Initializing the traces + */ + @Before + public void init() { + t1 = new TmfTraceStub(); + t1.init("t1"); + t2 = new TmfTraceStub(); + t2.init("t2"); + TmfTraceStub[] traces = { t1, t2 }; + fTraces = traces; + } + + /** + * Testing fully incremental algorithm with communication between the two + * traces + */ + @Test + public void testFullyIncremental() { + + SynchronizationAlgorithm syncAlgo = new SyncAlgorithmFullyIncremental(); + + syncAlgo.init(fTraces); + + assertEquals(SyncQuality.ABSENT, syncAlgo.getSynchronizationQuality(t1, t2)); + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(1)), + new TmfSyncEventStub(t1, new TmfTimestamp(1)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1 beta 0 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(1)), + new TmfSyncEventStub(t2, new TmfTimestamp(3)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1 beta 0 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(2)), + new TmfSyncEventStub(t1, new TmfTimestamp(3)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1 beta 0.5 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.APPROXIMATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(3)), + new TmfSyncEventStub(t2, new TmfTimestamp(5)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 0.75 beta 1.25 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.ACCURATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(4)), + new TmfSyncEventStub(t2, new TmfTimestamp(8)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 0.75 beta 1.25 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.ACCURATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(4)), + new TmfSyncEventStub(t1, new TmfTimestamp(5)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1.125 beta 0.875 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.ACCURATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(4)), + new TmfSyncEventStub(t1, new TmfTimestamp(6)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1.125 beta 0.875 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.ACCURATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(6)), + new TmfSyncEventStub(t2, new TmfTimestamp(7)) + )); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 0.725 beta 1.275 ]]", syncAlgo.toString()); + assertEquals(SyncQuality.ACCURATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + ITmfTimestampTransform tt2 = syncAlgo.getTimestampTransform(t2); + ITmfTimestampTransform tt1 = syncAlgo.getTimestampTransform(t1); + + assertEquals(syncAlgo.getTimestampTransform("t1"), tt1); + assertEquals(TmfTimestampTransform.IDENTITY, tt1); + assertEquals(syncAlgo.getTimestampTransform("t2"), tt2); + + /* Make the two hulls intersect */ + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(7)), + new TmfSyncEventStub(t2, new TmfTimestamp(4)) + )); + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(7)), + new TmfSyncEventStub(t1, new TmfTimestamp(3)) + )); + assertEquals(SyncQuality.FAIL, syncAlgo.getSynchronizationQuality(t1, t2)); + } + + /** + * Testing the fully incremental synchronization algorithm when + * communication goes in only one direction + */ + @Test + public void testOneHull() { + + SynchronizationAlgorithm syncAlgo = new SyncAlgorithmFullyIncremental(); + + syncAlgo.init(fTraces); + + assertEquals(SyncQuality.ABSENT, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(1)), + new TmfSyncEventStub(t2, new TmfTimestamp(3))) + ); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(2)), + new TmfSyncEventStub(t2, new TmfTimestamp(5))) + ); + + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(3)), + new TmfSyncEventStub(t2, new TmfTimestamp(5))) + ); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(4)), + new TmfSyncEventStub(t2, new TmfTimestamp(7))) + ); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1 beta 0 ]]", syncAlgo.toString()); + + } + + /** + * Testing the fully incremental synchronization algorithm when all + * communication from trace1 to trace2 happens before all communication from + * trace2 to trace1 + */ + @Test + public void testDisjoint() { + + SynchronizationAlgorithm syncAlgo = new SyncAlgorithmFullyIncremental(); + + syncAlgo.init(fTraces); + + assertEquals(SyncQuality.ABSENT, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(1)), + new TmfSyncEventStub(t2, new TmfTimestamp(3))) + ); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(2)), + new TmfSyncEventStub(t2, new TmfTimestamp(5))) + ); + + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(3)), + new TmfSyncEventStub(t2, new TmfTimestamp(5))) + ); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t1, new TmfTimestamp(4)), + new TmfSyncEventStub(t2, new TmfTimestamp(7))) + ); + assertEquals(SyncQuality.INCOMPLETE, syncAlgo.getSynchronizationQuality(t1, t2)); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1 beta 0 ]]", syncAlgo.toString()); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(7)), + new TmfSyncEventStub(t1, new TmfTimestamp(6))) + ); + assertEquals(SyncQuality.APPROXIMATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(8)), + new TmfSyncEventStub(t1, new TmfTimestamp(6))) + ); + assertEquals(SyncQuality.APPROXIMATE, syncAlgo.getSynchronizationQuality(t1, t2)); + + syncAlgo.addMatch( + new TmfEventDependency(new TmfSyncEventStub(t2, new TmfTimestamp(10)), + new TmfSyncEventStub(t1, new TmfTimestamp(8))) + ); + assertEquals(SyncQuality.APPROXIMATE, syncAlgo.getSynchronizationQuality(t1, t2)); + assertEquals("SyncAlgorithmFullyIncremental [Between t1 and t2 [ alpha 1 beta 2.5 ]]", syncAlgo.toString()); + } +} diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/TsTransformTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/TsTransformTest.java new file mode 100644 index 0000000000..4e91a4ae97 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/synchronization/TsTransformTest.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.tests.synchronization; + +import static org.junit.Assert.*; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.linuxtools.tmf.core.synchronization.ITmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.synchronization.TmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.synchronization.TmfTimestampTransformLinear; +import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; +import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; +import org.junit.Test; + +/** + * Tests for {@link TmfTimestampTransform} and its descendants + * + * @author Geneviève Bastien + */ +@SuppressWarnings("nls") +public class TsTransformTest { + + private long ts = 1361657893526374091L; + private ITmfTimestamp oTs = new TmfTimestamp(ts); + + /** + * Test the linear transform + */ + @Test + public void testLinearTransform() { + /* Default constructor */ + TmfTimestampTransformLinear ttl = new TmfTimestampTransformLinear(); + assertEquals(1361657893526374091L, ttl.transform(ts)); + assertEquals(1361657893526374091L, ttl.transform(oTs).getValue()); + + /* Just an offset */ + ttl = new TmfTimestampTransformLinear(BigDecimal.valueOf(1.0), BigDecimal.valueOf(3)); + assertEquals(1361657893526374094L, ttl.transform(ts)); + assertEquals(1361657893526374094L, ttl.transform(oTs).getValue()); + + /* Just a slope */ + ttl = new TmfTimestampTransformLinear(BigDecimal.valueOf(2.0), BigDecimal.valueOf(0)); + assertEquals(2723315787052748182L, ttl.transform(ts)); + assertEquals(2723315787052748182L, ttl.transform(oTs).getValue()); + + /* Offset and slope */ + ttl = new TmfTimestampTransformLinear(BigDecimal.valueOf(2.0), BigDecimal.valueOf(3)); + assertEquals(2723315787052748185L, ttl.transform(ts)); + assertEquals(2723315787052748185L, ttl.transform(oTs).getValue()); + + /* Offset and slope */ + ttl = new TmfTimestampTransformLinear(BigDecimal.valueOf(0.5), BigDecimal.valueOf(0)); + assertEquals(680828946763187045L, ttl.transform(ts)); + assertEquals(680828946763187045L, ttl.transform(oTs).getValue()); + } + + /** + * Test for the identity transform + */ + @Test + public void testIdentityTransform() { + ITmfTimestampTransform tt = TmfTimestampTransform.IDENTITY; + assertEquals(ts, tt.transform(ts)); + assertEquals(oTs, tt.transform(oTs)); + } + + /** + * Test hash and equals function + */ + @Test + public void testEquality() { + Map map = new HashMap(); + ITmfTimestampTransform ttl = new TmfTimestampTransformLinear(BigDecimal.valueOf(2.0), BigDecimal.valueOf(3)); + ITmfTimestampTransform ttl2 = new TmfTimestampTransformLinear(BigDecimal.valueOf(2.0), BigDecimal.valueOf(3)); + ITmfTimestampTransform ttl3 = new TmfTimestampTransformLinear(BigDecimal.valueOf(3), BigDecimal.valueOf(3)); + assertEquals(ttl, ttl2); + assertFalse(ttl.equals(ttl3)); + assertFalse(ttl2.equals(ttl3)); + + map.put(ttl, "a"); + assertTrue(map.containsKey(ttl2)); + assertEquals("a", map.get(ttl)); + + ITmfTimestampTransform ti = TmfTimestampTransform.IDENTITY; + assertEquals(TmfTimestampTransform.IDENTITY, ti); + assertFalse(TmfTimestampTransform.IDENTITY.equals(ttl)); + + map.put(ti, "b"); + assertTrue(map.containsKey(TmfTimestampTransform.IDENTITY)); + assertEquals("b", map.get(ti)); + + assertFalse(ti.equals(ttl)); + assertFalse(ttl.equals(ti)); + + } + + /** + * Test the transform composition function + */ + @Test + public void testComposition() { + long t = 100; + ITmfTimestampTransform ti = TmfTimestampTransform.IDENTITY; + ITmfTimestampTransform ttl = new TmfTimestampTransformLinear(BigDecimal.valueOf(2.0), BigDecimal.valueOf(3)); + ITmfTimestampTransform ttl2 = new TmfTimestampTransformLinear(BigDecimal.valueOf(1.5), BigDecimal.valueOf(8)); + + ITmfTimestampTransform tc1 = ti.composeWith(ttl); + /* Should be ttl */ + assertEquals(ttl, tc1); + assertEquals(203, tc1.transform(t)); + + tc1 = ttl.composeWith(ti); + /* Should be ttl also */ + assertEquals(ttl, tc1); + assertEquals(203, tc1.transform(t)); + + tc1 = ti.composeWith(ti); + /* Should be identity */ + assertEquals(tc1, TmfTimestampTransform.IDENTITY); + assertEquals(100, tc1.transform(t)); + + tc1 = ttl.composeWith(ttl2); + assertEquals(ttl.transform(ttl2.transform(t)), tc1.transform(t)); + assertEquals(319, tc1.transform(t)); + + tc1 = ttl2.composeWith(ttl); + assertEquals(ttl2.transform(ttl.transform(t)), tc1.transform(t)); + assertEquals(312, tc1.transform(t)); + + } +} diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceTest.java index c105b473c6..7c05832505 100644 --- a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceTest.java +++ b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceTest.java @@ -1364,15 +1364,15 @@ public class TmfTraceTest { assertEquals("getInitialRangeOffset", defaultInitRange, trace.getInitialRangeOffset()); trace.setInitialRangeOffset(new TmfTimestamp(5, ITmfTimestamp.MILLISECOND_SCALE)); trace.indexTrace(true); + + TmfTimestamp initRange = new TmfTimestamp(5, ITmfTimestamp.MILLISECOND_SCALE); + assertEquals("getInitialRangeOffset", initRange, trace.getInitialRangeOffset()); + } catch (final URISyntaxException e) { fail("URISyntaxException"); } catch (final IOException e) { fail("IOException"); } - assertFalse ("Open trace", trace == null); - - TmfTimestamp initRange = new TmfTimestamp(5, ITmfTimestamp.MILLISECOND_SCALE); - assertEquals("getInitialRangeOffset", initRange, trace.getInitialRangeOffset()); } /** diff --git a/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/event/TmfSyncEventStub.java b/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/event/TmfSyncEventStub.java new file mode 100644 index 0000000000..b8a0166ba1 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/event/TmfSyncEventStub.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.tests.stubs.event; + +import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; +import org.eclipse.linuxtools.tmf.core.event.TmfEvent; +import org.eclipse.linuxtools.tmf.core.event.TmfEventField; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Event stub used by the synchronization tests + * + * @author Geneviève Bastien + */ +public class TmfSyncEventStub extends TmfEvent { + + private static final String stub = "stub"; //$NON-NLS-1$ + + /** + * Constructor + * + * @param trace + * The trace of this event + * @param timestamp + * The timestamp + */ + public TmfSyncEventStub(final ITmfTrace trace, final ITmfTimestamp timestamp) { + super(trace, + timestamp, + stub, + new TmfEventTypeStub(), + new TmfEventField(stub, stub, null), + stub); + } +} diff --git a/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF index 4364e38caa..518e117d5a 100644 --- a/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF @@ -25,6 +25,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.core;x-friends:="org.eclipse org.eclipse.linuxtools.tmf.core.ctfadaptor, org.eclipse.linuxtools.tmf.core.event, org.eclipse.linuxtools.tmf.core.event.lookup, + org.eclipse.linuxtools.tmf.core.event.matching, org.eclipse.linuxtools.tmf.core.exceptions, org.eclipse.linuxtools.tmf.core.filter, org.eclipse.linuxtools.tmf.core.filter.model, @@ -36,6 +37,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.core;x-friends:="org.eclipse org.eclipse.linuxtools.tmf.core.statesystem, org.eclipse.linuxtools.tmf.core.statevalue, org.eclipse.linuxtools.tmf.core.statistics, + org.eclipse.linuxtools.tmf.core.synchronization, org.eclipse.linuxtools.tmf.core.timestamp, org.eclipse.linuxtools.tmf.core.trace, org.eclipse.linuxtools.tmf.core.trace.indexer, 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 ae002a0cc9..fbefc03c1b 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 @@ -77,6 +77,7 @@ public final class CtfTmfEvent extends TmfEvent sourceCPU = cpu; typeId = declaration.getId(); eventName = declaration.getName(); + } /** diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEventFactory.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEventFactory.java index ead5231283..6e3dbb463a 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEventFactory.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfEventFactory.java @@ -55,8 +55,7 @@ public final class CtfTmfEventFactory { /* Prepare what to pass to CtfTmfEvent's constructor */ long ts = eventDef.getTimestamp(); - CtfTmfTimestamp timestamp = new CtfTmfTimestamp( - originTrace.getCTFTrace().timestampCyclesToNanos(ts)); + CtfTmfTimestamp timestamp = originTrace.createTimestamp(originTrace.getCTFTrace().timestampCyclesToNanos(ts)); int sourceCPU = eventDef.getCPU(); diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java index 2ed90726da..5edb8cda8f 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 Ericsson + * Copyright (c) 2012, 2013 Ericsson, École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which @@ -9,6 +9,7 @@ * Contributors: * Matthew Khouzam - Initial API and implementation * Patrick Tasse - Updated for removal of context clone + * Geneviève Bastien - Added the createTimestamp function *******************************************************************************/ package org.eclipse.linuxtools.tmf.core.ctfadaptor; @@ -434,4 +435,16 @@ public class CtfTmfTrace extends TmfTrace public CtfIterator createIterator() { return new CtfIterator(this); } + + // ------------------------------------------------------------------------ + // Timestamp transformation functions + // ------------------------------------------------------------------------ + + /** + * @since 3.0 + */ + @Override + public CtfTmfTimestamp createTimestamp(long ts) { + return new CtfTmfTimestamp(getTimestampTransform().transform(ts)); + } } diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/IMatchProcessingUnit.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/IMatchProcessingUnit.java new file mode 100644 index 0000000000..063f15cefc --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/IMatchProcessingUnit.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * This class represent an action to be done when event matches are found. This + * interface needs to be implemented by all classes that want to be warned when + * new event matches are found. They need to register to an instance of + * TmfEventMatches class in order to be informed of matches. + * + * @author Geneviève Bastien + * @since 3.0 + */ +public interface IMatchProcessingUnit { + + /** + * Once the traces are known, hook function to initialize some things + * + * @param fTraces the set of traces that will be synchronized + */ + void init(ITmfTrace[] fTraces); + + /** + * Function called when a match is found + * + * @param match + * The event match + */ + void addMatch(TmfEventDependency match); + + /** + * Function called after all matching has been done, to do any post-match + * treatment + */ + void matchingEnded(); + + /** + * Counts the matches + * + * @return the number of matches + */ + int countMatches(); + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfEventMatching.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfEventMatching.java new file mode 100644 index 0000000000..1714ca8510 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfEventMatching.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + + +/** + * Interface for matching trace events + * + * @author Geneviève Bastien + * @since 3.0 + */ +public interface ITmfEventMatching { + + /** + * Method that start the process of matching events + * + * @return Whether the match was completed correctly or not + */ + boolean matchEvents(); + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfMatchEventDefinition.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfMatchEventDefinition.java new file mode 100644 index 0000000000..caba63508e --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/ITmfMatchEventDefinition.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import java.util.List; + +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching.MatchingType; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * This interface describe a concrete method to match events. Typically it + * manages for a given matching type what events/fields are used to match events + * + * @author Geneviève Bastien + * @since 3.0 + */ +public interface ITmfMatchEventDefinition { + + /** + * Returns a list of values for an event that uniquely identifies this event + * + * @param event + * The event for which to compute the key + * @return the unique key for this event + */ + List getUniqueField(ITmfEvent event); + + /** + * Verifies whether a trace has all required events to match using this + * class + * + * @param trace + * The trace + * @return Whether the trace has all required information + */ + boolean canMatchTrace(ITmfTrace trace); + + /** + * Return all matching types this definition covers + * + * @return an array of matching types + */ + MatchingType[] getApplicableMatchingTypes(); + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventDependency.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventDependency.java new file mode 100644 index 0000000000..13502507b5 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventDependency.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; + +/** + * Represents a dependency (match) between two events, where source event leads + * to destination event + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfEventDependency { + + private final ITmfEvent fSourceEvent; + private final ITmfEvent fDestEvent; + + /** + * Constructor + * + * @param source + * The source event of this dependency + * @param destination + * The destination event of this dependency + */ + public TmfEventDependency(final ITmfEvent source, final ITmfEvent destination) { + fSourceEvent = source; + fDestEvent = destination; + } + + /** + * Getter for fSourceEvent + * + * @return The source event + */ + public ITmfEvent getSourceEvent() { + return fSourceEvent; + } + + /** + * Getter for fDestEvent + * + * @return the Destination event + */ + public ITmfEvent getDestinationEvent() { + return fDestEvent; + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatches.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatches.java new file mode 100644 index 0000000000..8cf3e5ec24 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatches.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Class that does something with a match. + * + * This default implementation of the class just adds it to a list of matches + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfEventMatches implements IMatchProcessingUnit { + + /** + * The list of matches found + */ + private final List fMatches; + + /** + * Constructor + */ + public TmfEventMatches() { + fMatches = new ArrayList(); + } + + /** + * IMatchProcessingUnit overrides + */ + + @Override + public void init(ITmfTrace[] fTraces) { + + } + + @Override + public void addMatch(TmfEventDependency match) { + fMatches.add(match); + } + + @Override + public void matchingEnded() { + + } + + @Override + public int countMatches() { + return fMatches.size(); + } + + /** + * Returns the match at the specified index + * + * @param index + * The index of the match to get + * @return The match at index or null or not present + */ + public TmfEventDependency getMatch(int index) { + return fMatches.get(index); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [ Number of matches found: " + fMatches.size() + " ]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatching.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatching.java new file mode 100644 index 0000000000..fe694f628f --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfEventMatching.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.linuxtools.internal.tmf.core.Activator; +import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEvent; +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest; +import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest; +import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest; +import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Abstract class to extend to match certain type of events in a trace + * + * @author Geneviève Bastien + * @since 3.0 + */ +public abstract class TmfEventMatching implements ITmfEventMatching { + + /** + * The matching type + * + * FIXME Not the best place to put this. Have an array of match types as a + * parameter of each trace? + */ + public enum MatchingType { + /** + * NETWORK, match network events + */ + NETWORK + } + + /** + * The array of traces to match + */ + private final ITmfTrace[] fTraces; + + /** + * The class to call once a match is found + */ + private final IMatchProcessingUnit fMatches; + + private static final Map> fMatchDefinitions = new HashMap>(); + + private final Map fMatchMap = new HashMap(); + + /** + * Constructor with multiple traces and a match processing object + * + * @param traces + * The set of traces for which to match events + * @param tmfEventMatches + * The match processing class + */ + public TmfEventMatching(ITmfTrace[] traces, IMatchProcessingUnit tmfEventMatches) { + if (tmfEventMatches == null) { + throw new IllegalArgumentException(); + } + fTraces = traces; + fMatches = tmfEventMatches; + } + + /** + * Returns the traces to process + * + * @return The traces + */ + protected ITmfTrace[] getTraces() { + return fTraces; + } + + /** + * Returns the match processing unit + * + * @return The match processing unit + */ + protected IMatchProcessingUnit getProcessingUnit() { + return fMatches; + } + + /** + * Returns the match event definition corresponding to the trace + * + * @param trace + * The trace + * @return The match event definition object + */ + protected ITmfMatchEventDefinition getEventDefinition(ITmfTrace trace) { + return fMatchMap.get(trace); + } + + /** + * Method that initializes any data structure for the event matching. It + * also assigns to each trace an event matching definition instance that + * applies to the trace + */ + protected void initMatching() { + fMatches.init(fTraces); + List deflist = fMatchDefinitions.get(getMatchingType()); + if (deflist == null) { + return; + } + for (ITmfTrace trace : fTraces) { + for (ITmfMatchEventDefinition def : deflist) { + if (def.canMatchTrace(trace)) { + fMatchMap.put(trace, def); + break; + } + } + } + } + + /** + * Calls any post matching methods of the processing class + */ + protected void finalizeMatching() { + fMatches.matchingEnded(); + } + + /** + * Prints stats from the matching + * + * @return string of statistics + */ + @SuppressWarnings("nls") + @Override + public String toString() { + return getClass().getSimpleName() + " [ " + fMatches + " ]"; + } + + /** + * Matches one event + * + * @param event + * The event to match + * @param traceno + * The number of the trace this event belongs to + */ + protected abstract void matchEvent(ITmfEvent event, int traceno); + + /** + * Returns the matching type this class implements + * + * @return A matching type + */ + protected abstract MatchingType getMatchingType(); + + /** + * Method that start the process of matching events + * + * @return Whether the match was completed correctly or not + */ + @Override + public boolean matchEvents() { + + /* Are there traces to match? If no, return false */ + if (!(fTraces.length > 0)) { + return false; + } + + // TODO Start a new thread here? + initMatching(); + + /** + * For each trace, get the events and for each event, call the + * MatchEvent method + * + * FIXME This would use a lot of memory if the traces are big, because + * all involved events from first trace will have to be kept before a + * first match is possible with second trace. + * + *
+         * Other possible matching strategy:
+         * Incremental:
+         * Sliding window:
+         * Other strategy: start with the shortest trace, take a few events
+         * at the beginning and at the end
+         * Experiment strategy: have the experiment do the request, then events will
+         * come from both traces chronologically, but then instead of ITmfTrace[], it
+         * would be preferable to have experiment
+         * 
+ */ + for (int i = 0; i < fTraces.length; i++) { + + EventMatchingBuildRequest request = new EventMatchingBuildRequest(this, i); + + /* + * Send the request to the trace here, since there is probably no + * experiment. + */ + fTraces[i].sendRequest(request); + try { + request.waitForCompletion(); + } catch (InterruptedException e) { + Activator.logInfo(e.getMessage()); + } + } + + finalizeMatching(); + + return true; + } + + /** + * Registers an event match definition to be used for a certain match type + * + * @param match + * The event matching definition + */ + public static void registerMatchObject(ITmfMatchEventDefinition match) { + for (MatchingType type : match.getApplicableMatchingTypes()) { + if (!fMatchDefinitions.containsKey(type)) { + fMatchDefinitions.put(type, new ArrayList()); + } + fMatchDefinitions.get(type).add(match); + } + } + +} + +class EventMatchingBuildRequest extends TmfEventRequest { + + private final TmfEventMatching matching; + private final int traceno; + + EventMatchingBuildRequest(TmfEventMatching matching, int traceno) { + super(CtfTmfEvent.class, + TmfTimeRange.ETERNITY, + 0, + TmfDataRequest.ALL_DATA, + ITmfDataRequest.ExecutionType.FOREGROUND); + this.matching = matching; + this.traceno = traceno; + } + + @Override + public void handleData(final ITmfEvent event) { + super.handleData(event); + if (event != null) { + matching.matchEvent(event, traceno); + } + } + + @Override + public void handleSuccess() { + super.handleSuccess(); + } + + @Override + public void handleCancel() { + super.handleCancel(); + } + + @Override + public void handleFailure() { + super.handleFailure(); + } +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkEventMatching.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkEventMatching.java new file mode 100644 index 0000000000..06536f4d80 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkEventMatching.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.event.matching.IMatchProcessingUnit; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventDependency; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatching; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * This class matches events typically network-style, ie. where some events are + * 'send' events and the other 'receive' events or out/in events + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfNetworkEventMatching extends TmfEventMatching { + + /** + * Hashtables for unmatches incoming events + */ + private final List, ITmfEvent>> fUnmatchedIn = new ArrayList, ITmfEvent>>(); + + /** + * Hashtables for unmatches outgoing events + */ + private final List, ITmfEvent>> fUnmatchedOut = new ArrayList, ITmfEvent>>(); + + /** + * Enum for in and out types + */ + public enum Direction { + /** + * The event is a 'receive' type of event + */ + IN, + /** + * The event is a 'send' type of event + */ + OUT, + } + + /** + * Constructor with multiple traces and match processing object + * + * @param traces + * The set of traces for which to match events + */ + public TmfNetworkEventMatching(ITmfTrace[] traces) { + this(traces, new TmfEventMatches()); + } + + /** + * Constructor with multiple traces and match processing object + * + * @param traces + * The set of traces for which to match events + * @param tmfEventMatches + * The match processing class + */ + public TmfNetworkEventMatching(ITmfTrace[] traces, IMatchProcessingUnit tmfEventMatches) { + super(traces, tmfEventMatches); + } + + /** + * Method that initializes any data structure for the event matching + */ + @Override + public void initMatching() { + // Initialize the matching infrastructure (unmatched event lists) + fUnmatchedIn.clear(); + fUnmatchedOut.clear(); + for (int i = 0; i < getTraces().length; i++) { + fUnmatchedIn.add(new HashMap, ITmfEvent>()); + fUnmatchedOut.add(new HashMap, ITmfEvent>()); + } + super.initMatching(); + } + + /** + * Function that counts the events in a hashtable. + * + * @param tbl + * The table to count events for + * @return The number of events + */ + protected int countEvents(Map, ITmfEvent> tbl) { + return tbl.size(); + } + + @Override + protected MatchingType getMatchingType() { + return MatchingType.NETWORK; + } + + /** + * Matches one event + * + * @param event + * The event to match + * @param traceno + * The number of the trace this event belongs to + */ + @Override + public void matchEvent(ITmfEvent event, int traceno) { + /* + * TODO: Should find a way to assert the type is right here. For now we + * just hope developers register NetworkMatchDefinition for Network + * match types... + */ + TmfNetworkMatchDefinition def = (TmfNetworkMatchDefinition) getEventDefinition(event.getTrace()); + if (def == null) { + return; + } + + Direction evType = def.getDirection(event); + if (evType == null) { + return; + } + + /* Get the event's unique fields */ + List eventKey = def.getUniqueField(event); + List, ITmfEvent>> unmatchedTbl, companionTbl; + + /* Point to the appropriate table */ + switch (evType) { + case IN: + unmatchedTbl = fUnmatchedIn; + companionTbl = fUnmatchedOut; + break; + case OUT: + unmatchedTbl = fUnmatchedOut; + companionTbl = fUnmatchedIn; + break; + default: + return; + } + + boolean found = false; + TmfEventDependency dep = null; + /* Search for the event in the companion table */ + for (Map, ITmfEvent> map : companionTbl) { + if (map.containsKey(eventKey)) { + found = true; + ITmfEvent companionEvent = map.get(eventKey); + + /* Remove the element from the companion table */ + map.remove(eventKey); + + /* Create the dependency object */ + switch (evType) { + case IN: + dep = new TmfEventDependency(companionEvent, event); + break; + case OUT: + dep = new TmfEventDependency(event, companionEvent); + break; + default: + break; + + } + } + } + + /* + * If no companion was found, add the event to the appropriate unMatched + * lists + */ + if (found) { + getProcessingUnit().addMatch(dep); + } else { + /* + * If an event is already associated with this key, do not add it + * again, we keep the first event chronologically, so if its match + * is eventually found, it is associated with the first send or + * receive event. At best, it is a good guess, at worst, the match + * will be too far off to be accurate. Too bad! + * + * TODO: maybe instead of just one event, we could have a list of + * events as value for the unmatched table. Not necessary right now + * though + */ + if (!unmatchedTbl.get(traceno).containsKey(eventKey)) { + unmatchedTbl.get(traceno).put(eventKey, event); + } + } + + } + + /** + * Prints stats from the matching + * + * @return string of statistics + */ + @SuppressWarnings("nls") + @Override + public String toString() { + final String cr = System.getProperty("line.separator"); + StringBuilder b = new StringBuilder(); + b.append(getProcessingUnit()); + for (int i = 0; i < getTraces().length; i++) { + b.append("Trace " + i + ":" + cr + + " " + countEvents(fUnmatchedIn.get(i)) + " unmatched incoming events" + cr + + " " + countEvents(fUnmatchedOut.get(i)) + " unmatched outgoing events" + cr); + } + + return b.toString(); + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkMatchDefinition.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkMatchDefinition.java new file mode 100644 index 0000000000..1a0d2e1a11 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/event/matching/TmfNetworkMatchDefinition.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.event.matching; + +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkEventMatching.Direction; + +/** + * Base class for all network match definitions, ie traces with send and receive + * events + * + * @author Geneviève Bastien + * @since 3.0 + */ +public abstract class TmfNetworkMatchDefinition implements ITmfMatchEventDefinition { + + /** + * Returns the direction of this event, whether 'send', 'receive' or null if + * event is neither + * + * @param event + * The event to check + * @return The direction of this event, null if uninteresting event + */ + public abstract Direction getDirection(ITmfEvent event); + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceSynchronizedSignal.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceSynchronizedSignal.java new file mode 100644 index 0000000000..fa24bbf702 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceSynchronizedSignal.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.signal; + +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm; + +/** + * Signal indicating a trace synchronization has been done + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfTraceSynchronizedSignal extends TmfSignal { + + private final SynchronizationAlgorithm fAlgoSync; + + /** + * Constructor + * + * @param source + * Object sending this signal + * @param algoSync + * The synchronization algorithm used + */ + public TmfTraceSynchronizedSignal(Object source, SynchronizationAlgorithm algoSync) { + super(source); + fAlgoSync = algoSync; + } + + /** + * Synchronization algorithm getter + * + * @return The algorithm object + */ + public SynchronizationAlgorithm getSyncAlgo() { + return fAlgoSync; + } + + @Override + public String toString() { + return "[" + getClass().getSimpleName() + " (" + fAlgoSync.toString() + ")]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/ITmfTimestampTransform.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/ITmfTimestampTransform.java new file mode 100644 index 0000000000..55bc9e916e --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/ITmfTimestampTransform.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; + +/** + * This class contains a formula to transform the value of a timestamp, for + * example after trace synchronization + * + * @author Geneviève Bastien + * @since 3.0 + */ +public interface ITmfTimestampTransform { + + /** + * Transforms a timestamp + * + * @param timestamp + * The timestamp to transform + * @return the transformed timestamp + */ + ITmfTimestamp transform(ITmfTimestamp timestamp); + + /** + * Transforms a timestamp value + * + * @param timestamp + * The timestamp to transform + * @return the transformed value + */ + long transform(long timestamp); + + /** + * Returns a timestamp transform that is the composition of two timestamp + * transforms. + * + * @param composeWith + * The transform to first apply on the timestamp before applying + * the current object + * @return A new timestamp transform object with the resulting composition. + */ + ITmfTimestampTransform composeWith(ITmfTimestampTransform composeWith); + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/Messages.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/Messages.java new file mode 100644 index 0000000000..c52098186e --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/Messages.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import org.eclipse.osgi.util.NLS; + +/** + * Messages class + * + * @since 3.0 + */ +@SuppressWarnings("javadoc") +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.linuxtools.tmf.core.synchronization.messages"; //$NON-NLS-1$ + public static String SyncAlgorithmFullyIncremental_absent; + public static String SyncAlgorithmFullyIncremental_alpha; + public static String SyncAlgorithmFullyIncremental_beta; + public static String SyncAlgorithmFullyIncremental_T_; + public static String SyncAlgorithmFullyIncremental_otherformula; + public static String SyncAlgorithmFullyIncremental_mult; + public static String SyncAlgorithmFullyIncremental_add; + public static String SyncAlgorithmFullyIncremental_ub; + public static String SyncAlgorithmFullyIncremental_lb; + public static String SyncAlgorithmFullyIncremental_accuracy; + public static String SyncAlgorithmFullyIncremental_accurate; + public static String SyncAlgorithmFullyIncremental_approx; + public static String SyncAlgorithmFullyIncremental_fail; + public static String SyncAlgorithmFullyIncremental_incomplete; + public static String SyncAlgorithmFullyIncremental_nbmatch; + public static String SyncAlgorithmFullyIncremental_nbacc; + public static String SyncAlgorithmFullyIncremental_reftrace; + public static String SyncAlgorithmFullyIncremental_othertrace; + public static String SyncAlgorithmFullyIncremental_refformula; + public static String SyncAlgorithmFullyIncremental_NA; + public static String SyncAlgorithmFullyIncremental_quality; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java new file mode 100644 index 0000000000..7360e7f85f --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SyncAlgorithmFullyIncremental.java @@ -0,0 +1,572 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventDependency; +import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Class implementing fully incremental trace synchronization approach as + * described in + * + * Masoume Jabbarifar, Michel Dagenais and Alireza Shameli-Sendi, + * "Streaming Mode Incremental Clock Synchronization" + * + * Since the algorithm itself applies to two traces, it is implemented in a + * private class, while this public class manages the synchronization between + * all traces. + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class SyncAlgorithmFullyIncremental extends SynchronizationAlgorithm { + + /** + * Auto-generated serial UID + */ + private static final long serialVersionUID = -1782788842774838830L; + + private static final MathContext fMc = MathContext.DECIMAL128; + + private final List fSyncs; + + /** + * Initialization of the attributes + */ + public SyncAlgorithmFullyIncremental() { + fSyncs = new LinkedList(); + } + + /** + * Function called after all matching has been done, to do any post-match + * treatment. For this class, it calculates stats, while the data is + * available + */ + @Override + public void matchingEnded() { + getStats(); + } + + @Override + public void init(ITmfTrace[] fTraces) { + fSyncs.clear(); + /* Create a convex hull for all trace pairs */ + for (int i = 0; i < fTraces.length; i++) { + for (int j = i + 1; j < fTraces.length; j++) { + ConvexHull algo = new ConvexHull(fTraces[i].getName(), fTraces[j].getName()); + fSyncs.add(algo); + } + } + } + + @Override + protected void processMatch(TmfEventDependency match) { + String trace1 = match.getSourceEvent().getTrace().getName(); + String trace2 = match.getDestinationEvent().getTrace().getName(); + + /* Process only if source and destination are different */ + if (trace1.equals(trace2)) { + return; + } + + /* Check if a convex hull algorithm already exists for these 2 traces */ + ConvexHull algo = null; + for (ConvexHull traceSync : fSyncs) { + if (traceSync.isForTraces(trace1, trace2)) { + algo = traceSync; + } + } + if (algo == null) { + algo = new ConvexHull(trace1, trace2); + fSyncs.add(algo); + } + algo.processMatch(match); + + } + + @Override + public ITmfTimestampTransform getTimestampTransform(ITmfTrace trace) { + return getTimestampTransform(trace.getName()); + } + + @Override + public ITmfTimestampTransform getTimestampTransform(String name) { + for (ConvexHull traceSync : fSyncs) { + if (traceSync.isTraceSynced(name)) { + /* + * Since there are many traces, maybe the reference trace is + * also synchronized, so we need to chain sync formulas + */ + ITmfTimestampTransform refTt = getTimestampTransform(traceSync.getReferenceTrace()); + return refTt.composeWith(traceSync.getTimestampTransform(name)); + } + } + return TmfTimestampTransform.IDENTITY; + } + + @Override + public SyncQuality getSynchronizationQuality(ITmfTrace trace1, ITmfTrace trace2) { + for (ConvexHull traceSync : fSyncs) { + if (traceSync.isForTraces(trace1.getName(), trace2.getName())) { + return traceSync.getQuality(); + } + } + return SyncQuality.ABSENT; + } + + @Override + public boolean isTraceSynced(String name) { + boolean traceSynced = false; + for (ConvexHull traceSync : fSyncs) { + traceSynced = traceSynced || traceSync.isTraceSynced(name); + } + return traceSynced; + } + + /** + * Rename one of the traces in the synchronization + * + * @param oldname + * The name of the original trace + * @param newname + * The new name of the trace + */ + @Override + public void renameTrace(String oldname, String newname) { + for (ConvexHull traceSync : fSyncs) { + traceSync.renameTrace(oldname, newname); + } + } + + @Override + public Map> getStats() { + Map> statmap = new LinkedHashMap>(); + for (ConvexHull traceSync : fSyncs) { + statmap.put(traceSync.getReferenceTrace() + " <==> " + traceSync.getOtherTrace(), traceSync.getStats()); //$NON-NLS-1$ + } + return statmap; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + b.append(getClass().getSimpleName() + " "); //$NON-NLS-1$ + b.append(fSyncs); + return b.toString(); + } + + /** + * This is the actual synchronization algorithm between two traces using + * convex hull + */ + private class ConvexHull implements Serializable { + + private static final long serialVersionUID = 8309351175030935291L; + + /** + * The list of meaningful points on the upper hull (received by the + * reference trace, below in a graph) + */ + private final LinkedList fUpperBoundList = new LinkedList(); + + /** + * The list of meaninful points on the lower hull (sent by the reference + * trace, above in a graph) + */ + private final LinkedList fLowerBoundList = new LinkedList(); + + /** Points forming the line with maximum slope */ + private final SyncPoint[] fLmax; + + /** Points forming the line with minimum slope */ + private final SyncPoint[] fLmin; + + /** + * Slopes and ordinate at origin of respectively fLmin, fLmax and the + * bisector + */ + private BigDecimal fAlphamin, fBetamax, fAlphamax, fBetamin, fAlpha, fBeta; + + private int fNbMatches, fNbAccurateMatches; + private String fReferenceTrace = "", fOtherTrace = ""; //$NON-NLS-1$//$NON-NLS-2$ + private SyncQuality fQuality; + + private Map fStats = new LinkedHashMap(); + + /** + * Initialization of the attributes + * + * @param trace1 + * Name of the first trace + * @param trace2 + * Name of the second trace + */ + public ConvexHull(String trace1, String trace2) { + if (trace1.compareTo(trace2) > 0) { + fReferenceTrace = trace2; + fOtherTrace = trace1; + } else { + fReferenceTrace = trace1; + fOtherTrace = trace2; + } + fLmax = new SyncPoint[2]; + fLmin = new SyncPoint[2]; + fAlpha = BigDecimal.ONE; + fAlphamax = BigDecimal.ONE; + fAlphamin = BigDecimal.ONE; + fBeta = BigDecimal.ZERO; + fBetamax = BigDecimal.ZERO; + fBetamin = BigDecimal.ZERO; + fNbMatches = 0; + fNbAccurateMatches = 0; + fQuality = SyncQuality.ABSENT; + } + + protected void processMatch(TmfEventDependency match) { + + LinkedList boundList, otherBoundList; + + SyncPoint[] line, otherLine; + SyncPoint p; + int inversionFactor = 1; + boolean qualify = false; + fNbMatches++; + + /* Initialize data depending on the which hull the match is part of */ + if (match.getSourceEvent().getTrace().getName().compareTo(match.getDestinationEvent().getTrace().getName()) > 0) { + boundList = fUpperBoundList; + otherBoundList = fLowerBoundList; + line = fLmin; + otherLine = fLmax; + p = new SyncPoint(match.getDestinationEvent(), match.getSourceEvent()); + inversionFactor = 1; + } else { + boundList = fLowerBoundList; + otherBoundList = fUpperBoundList; + line = fLmax; + otherLine = fLmin; + p = new SyncPoint(match.getSourceEvent(), match.getDestinationEvent()); + inversionFactor = -1; + } + + /* + * Does the message qualify for the hull, or is in on the wrong side + * of the reference line + */ + if ((line[0] == null) || (line[1] == null) || (p.crossProduct(line[0], line[1]) * inversionFactor > 0)) { + /* + * If message qualifies, verify if points need to be removed + * from the hull and add the new point as the maximum reference + * point for the line. Also clear the stats that are not good + * anymore + */ + fNbAccurateMatches++; + qualify = true; + removeUselessPoints(p, boundList, inversionFactor); + line[1] = p; + fStats.clear(); + } + + /* + * Adjust the boundary of the reference line and if one of the + * reference point of the other line was removed from the hull, also + * adjust the other line + */ + adjustBound(line, otherBoundList, inversionFactor); + if ((otherLine[1] != null) && !boundList.contains(otherLine[0])) { + adjustBound(otherLine, boundList, inversionFactor * -1); + } + + if (qualify) { + approximateSync(); + } + + } + + /** + * Calculates slopes and ordinate at origin of fLmax and fLmin to obtain + * and approximation of the synchronization at this time + */ + private void approximateSync() { + /** + * Line slopes functions + * + * Lmax = alpha_max T + beta_min + * + * Lmin = alpha_min T + beta_max + */ + if ((fLmax[0] != null) || (fLmin[0] != null)) { + fAlphamax = fLmax[1].getAlpha(fLmax[0]); + fBetamin = fLmax[1].getBeta(fAlphamax); + fAlphamin = fLmin[1].getAlpha(fLmin[0]); + fBetamax = fLmin[1].getBeta(fAlphamin); + fAlpha = fAlphamax.add(fAlphamin).divide(BigDecimal.valueOf(2), fMc); + fBeta = fBetamin.add(fBetamax).divide(BigDecimal.valueOf(2), fMc); + if ((fLmax[0] == null) || (fLmin[0] == null)) { + fQuality = SyncQuality.APPROXIMATE; + } + else if (fAlphamax.compareTo(fAlphamin) > 0) { + fQuality = SyncQuality.ACCURATE; + } else { + /* Lines intersect, not good */ + fQuality = SyncQuality.FAIL; + } + } else if (((fLmax[0] == null) && (fLmin[1] == null)) + || ((fLmax[1] == null) && (fLmin[0] == null))) { + /* Either there is no upper hull point or no lower hull */ + fQuality = SyncQuality.INCOMPLETE; + } + } + + /* + * Verify if the line should be adjusted to be more accurate give the + * hull + */ + private void adjustBound(SyncPoint[] line, LinkedList otherBoundList, int inversionFactor) { + SyncPoint minPoint = null, nextPoint; + boolean finishedSearch = false; + + /* + * Find in the other bound, the origin point of the line, start from + * the beginning if the point was lost + */ + int i = Math.max(0, otherBoundList.indexOf(line[0])); + + while ((i < otherBoundList.size() - 1) && !finishedSearch) { + minPoint = otherBoundList.get(i); + nextPoint = otherBoundList.get(i + 1); + + /* + * If the rotation (cross-product) is not optimal, move to next + * point as reference for the line (if available) + * + * Otherwise, the current minPoint is the minPoint of the line + */ + if (minPoint.crossProduct(nextPoint, line[1]) * inversionFactor > 0) { + if (nextPoint.getTimeX() < line[1].getTimeX()) { + i++; + } else { + line[0] = null; + finishedSearch = true; + } + } else { + line[0] = minPoint; + finishedSearch = true; + } + } + + if (line[0] == null) { + line[0] = minPoint; + } + + /* Make sure point 0 is before point 1 */ + if ((line[0] != null) && (line[0].getTimeX() > line[1].getTimeX())) { + line[0] = null; + } + } + + /* + * When a point qualifies to be in a hull, we verify if any of the + * existing points need to be removed from the hull + */ + private void removeUselessPoints(final SyncPoint p, final LinkedList boundList, final int inversionFactor) { + + boolean checkRemove = true; + + while (checkRemove && boundList.size() >= 2) { + if (p.crossProduct(boundList.get(boundList.size() - 2), boundList.getLast()) * inversionFactor > 0) { + boundList.removeLast(); + } else { + checkRemove = false; + } + } + boundList.addLast(p); + } + + public ITmfTimestampTransform getTimestampTransform(String name) { + if (name.equals(fOtherTrace) && (fQuality == SyncQuality.ACCURATE || fQuality == SyncQuality.APPROXIMATE || fQuality == SyncQuality.FAIL)) { + /* alpha: beta => 1 / fAlpha, -1 * fBeta / fAlpha); */ + return new TmfTimestampTransformLinear(BigDecimal.ONE.divide(fAlpha, fMc), BigDecimal.valueOf(-1).multiply(fBeta).divide(fAlpha, fMc)); + } + return TmfTimestampTransform.IDENTITY; + } + + public SyncQuality getQuality() { + return fQuality; + } + + public Map getStats() { + if (fStats.size() == 0) { + String syncQuality; + switch (fQuality) { + case ABSENT: + syncQuality = Messages.SyncAlgorithmFullyIncremental_absent; + break; + case ACCURATE: + syncQuality = Messages.SyncAlgorithmFullyIncremental_accurate; + break; + case APPROXIMATE: + syncQuality = Messages.SyncAlgorithmFullyIncremental_approx; + break; + case INCOMPLETE: + syncQuality = Messages.SyncAlgorithmFullyIncremental_incomplete; + break; + case FAIL: + default: + syncQuality = Messages.SyncAlgorithmFullyIncremental_fail; + break; + } + + fStats.put(Messages.SyncAlgorithmFullyIncremental_reftrace, fReferenceTrace); + fStats.put(Messages.SyncAlgorithmFullyIncremental_othertrace, fOtherTrace); + fStats.put(Messages.SyncAlgorithmFullyIncremental_quality, syncQuality); + fStats.put(Messages.SyncAlgorithmFullyIncremental_alpha, fAlpha); + fStats.put(Messages.SyncAlgorithmFullyIncremental_beta, fBeta); + fStats.put(Messages.SyncAlgorithmFullyIncremental_ub, (fUpperBoundList.size() == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fUpperBoundList.size()); + fStats.put(Messages.SyncAlgorithmFullyIncremental_lb, (fLowerBoundList.size() == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fLowerBoundList.size()); + fStats.put(Messages.SyncAlgorithmFullyIncremental_accuracy, fAlphamax.subtract(fAlphamin).doubleValue()); // - + // fAlphamin); + fStats.put(Messages.SyncAlgorithmFullyIncremental_nbmatch, (fNbMatches == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fNbMatches); + fStats.put(Messages.SyncAlgorithmFullyIncremental_nbacc, (fNbAccurateMatches == 0) ? Messages.SyncAlgorithmFullyIncremental_NA : fNbAccurateMatches); + fStats.put(Messages.SyncAlgorithmFullyIncremental_refformula, Messages.SyncAlgorithmFullyIncremental_T_ + fReferenceTrace); + fStats.put(Messages.SyncAlgorithmFullyIncremental_otherformula, fAlpha + Messages.SyncAlgorithmFullyIncremental_mult + Messages.SyncAlgorithmFullyIncremental_T_ + fReferenceTrace + Messages.SyncAlgorithmFullyIncremental_add + fBeta); + } + return fStats; + + } + + public String getReferenceTrace() { + return fReferenceTrace; + } + + public String getOtherTrace() { + return fOtherTrace; + } + + public boolean isTraceSynced(String name) { + /* Returns true if the timestamp transform is not identity */ + return (name.equals(fOtherTrace) && (fQuality == SyncQuality.ACCURATE || fQuality == SyncQuality.APPROXIMATE || fQuality == SyncQuality.FAIL)); + } + + public boolean isForTraces(String trace1, String trace2) { + return ((fReferenceTrace.equals(trace1) && fOtherTrace.equals(trace2)) || (fReferenceTrace.equals(trace2) && fOtherTrace.equals(trace1))); + } + + public void renameTrace(String oldname, String newname) { + if (oldname.equals(fOtherTrace)) { + fOtherTrace = newname; + } else if (oldname.equals(fReferenceTrace)) { + fReferenceTrace = newname; + } + } + + private void writeObject(ObjectOutputStream s) + throws IOException { + /* + * Remove calculation data because most of it is not serializable. + * We have the statistics anyway + */ + fUpperBoundList.clear(); + fLowerBoundList.clear(); + fLmin[0] = null; + fLmin[1] = null; + fLmax[0] = null; + fLmax[1] = null; + s.defaultWriteObject(); + + } + + @SuppressWarnings("nls") + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + b.append("Between " + fReferenceTrace + " and " + fOtherTrace + " ["); + b.append(" alpha " + fAlpha + " beta " + fBeta + " ]"); + return b.toString(); + } + } + + /** + * Private class representing a point to synchronize on a graph. The x axis + * is the timestamp of the event from the reference trace while the y axis + * is the timestamp of the event on the other trace + */ + private class SyncPoint { + private final ITmfTimestamp x, y; + + public SyncPoint(ITmfEvent ex, ITmfEvent ey) { + x = ex.getTimestamp(); + y = ey.getTimestamp(); + } + + public long getTimeX() { + return x.getValue(); + } + + /** + * Calculate a cross product of 3 points: + * + * If the cross-product < 0, then p, pa, pb are clockwise + * + * If the cross-product > 0, then p, pa, pb are counter-clockwise + * + * If cross-product == 0, then they are in a line + * + * @param pa + * First point + * @param pb + * Second point + * @return The cross product + */ + public long crossProduct(SyncPoint pa, SyncPoint pb) { + long cp = ((pa.x.getValue() - x.getValue()) * (pb.y.getValue() - y.getValue()) - (pa.y.getValue() - y.getValue()) * (pb.x.getValue() - x.getValue())); + return cp; + } + + /* + * Gets the alpha (slope) between two points + */ + public BigDecimal getAlpha(SyncPoint p1) { + if (p1 == null) { + return BigDecimal.ONE; + } + BigDecimal deltay = BigDecimal.valueOf(y.getValue() - p1.y.getValue()); + BigDecimal deltax = BigDecimal.valueOf(x.getValue() - p1.x.getValue()); + if (deltax.equals(BigDecimal.ZERO)) { + return BigDecimal.ONE; + } + return deltay.divide(deltax, fMc); + } + + /* + * Get the beta value (when x = 0) of the line given alpha + */ + public BigDecimal getBeta(BigDecimal alpha) { + return BigDecimal.valueOf(y.getValue()).subtract(alpha.multiply(BigDecimal.valueOf(x.getValue()), fMc)); + } + + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationAlgorithm.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationAlgorithm.java new file mode 100644 index 0000000000..d744bcf2c5 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationAlgorithm.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import java.io.Serializable; +import java.util.Map; + +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventDependency; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfEventMatches; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * Abstract class for synchronization algorithm + * + * @author Geneviève Bastien + * @since 3.0 + */ +public abstract class SynchronizationAlgorithm extends TmfEventMatches implements Serializable { + + private static final long serialVersionUID = -3083906749528872196L; + + /** + * Quality of the result obtained by the synchronization algorithm + */ + public enum SyncQuality { + /** + * Algorithm returned a result satisfying all hypothesis for the + * algorithm + */ + ACCURATE, + /** + * Best effort of the algorithm + */ + APPROXIMATE, + /** + * There is communication only in one direction + */ + INCOMPLETE, + /** + * No communication between two traces + */ + ABSENT, + /** + * Hypothesis of the algorithm are not satisfied for some reason + */ + FAIL + } + + @Override + public void addMatch(TmfEventDependency match) { + super.addMatch(match); + processMatch(match); + } + + /** + * Function for synchronization algorithm to do something with the received + * match + * + * @param match + * The match of events + */ + protected abstract void processMatch(TmfEventDependency match); + + /** + * Returns a map of staticstics relating to this algorithm. Those stats + * could be used to be displayed in a view for example. + * + * @return A map of statistics for this algorithm + */ + public abstract Map> getStats(); + + /** + * Returns a timestamp transformation algorithm + * + * @param trace + * The trace to get the transform for + * @return The timestamp transformation formula + */ + public abstract ITmfTimestampTransform getTimestampTransform(ITmfTrace trace); + + /** + * Returns a timestamp transformation algorithm + * + * @param name + * The name of the trace to get the transform for + * @return The timestamp transformation formula + */ + public abstract ITmfTimestampTransform getTimestampTransform(String name); + + /** + * Gets the quality of the synchronization between two given traces + * + * @param trace1 + * First trace + * @param trace2 + * Second trace + * @return The synchronization quality + */ + public abstract SyncQuality getSynchronizationQuality(ITmfTrace trace1, ITmfTrace trace2); + + /** + * Returns whether a given trace has a synchronization formula that is not + * identity. This function returns true if the synchronization algorithm has + * failed for some reason + * + * @param name + * The name of the trace + * @return true if trace has formula + */ + public abstract boolean isTraceSynced(String name); + + /** + * Rename a trace involved in this algorithm. This function is necessary + * because after synchronization, the trace whose timestamp changes is + * copied with a new name and the synchronization needs to keep track of the + * new name. + * + * @param oldname + * Original name of the trace + * @param newname + * New name of the trace + */ + public abstract void renameTrace(String oldname, String newname); + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationBackend.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationBackend.java new file mode 100644 index 0000000000..1950b3aa73 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationBackend.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +import org.eclipse.linuxtools.internal.tmf.core.Activator; + +/** + * Class to fetch and save synchronization information between traces + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class SynchronizationBackend { + + private static final int SYNC_FILE_MAGIC_NUMBER = 0x0DECAF00; + + private static final int FILE_VERSION = 1; + + private static final int HEADER_SIZE = 20; + + private final File fSyncFile; + + /** + * Constructor + * + * @param syncFile + * The file containing synchronization information + * @throws IOException + * If the file couldn't be opened for some reason + */ + public SynchronizationBackend(File syncFile) throws IOException { + this(syncFile, true); + } + + /** + * Constructor with possibility to tell whether to throw errors on exception + * or not + * + * @param syncFile + * The file containing synchronization information + * @param throwErrors + * Whether to throw exceptions or not + * @throws IOException + * If the file couldn't be opened for some reason + */ + public SynchronizationBackend(File syncFile, boolean throwErrors) throws IOException { + /* + * Open the file ourselves, get the header information we need, then + * pass on the descriptor. + */ + int res; + + fSyncFile = syncFile; + + if (syncFile == null) { + return; + } + + if (!syncFile.exists()) { + if (throwErrors) { + throw new IOException("Selected synchronization file does not exist"); //$NON-NLS-1$ + } + return; + } + if (syncFile.length() <= 0) { + if (throwErrors) { + throw new IOException("Invalid synchronization file selected, " + //$NON-NLS-1$ + "target file is empty"); //$NON-NLS-1$ + } + return; + } + + FileInputStream fis = new FileInputStream(syncFile); + ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE); + FileChannel fc = fis.getChannel(); + buffer.clear(); + fc.read(buffer); + buffer.flip(); + + /* + * Check the magic number,to make sure we're opening the right type of + * file + */ + res = buffer.getInt(); + if (res != SYNC_FILE_MAGIC_NUMBER) { + fc.close(); + fis.close(); + throw new IOException("Selected file does not" + //$NON-NLS-1$ + "look like a synchronization file"); //$NON-NLS-1$ + } + + res = buffer.getInt(); /* Major version number */ + if (res != FILE_VERSION) { + fc.close(); + fis.close(); + throw new IOException("Select synchronization file is of an older " //$NON-NLS-1$ + + "format. Synchronization will have to be computed again."); //$NON-NLS-1$ + } + + res = buffer.getInt(); /* Minor version number */ + + fc.close(); + fis.close(); + } + + /** + * Opens an existing synchronization file + * + * @return The synchronization algorithm contained in the file + * @throws IOException + * Exception returned file functions + */ + public SynchronizationAlgorithm openExistingSync() throws IOException { + + if (fSyncFile == null) { + return null; + } + + /* Set the position after the header */ + FileInputStream fis = new FileInputStream(fSyncFile); + FileChannel fc = fis.getChannel().position(HEADER_SIZE); + + /* Read the input stream */ + ObjectInputStream ois = new ObjectInputStream(fis); + SyncAlgorithmFullyIncremental syncAlgo = null; + try { + syncAlgo = (SyncAlgorithmFullyIncremental) ois.readObject(); + } catch (ClassNotFoundException e) { + + } + ois.close(); + fc.close(); + + fis.close(); + + return syncAlgo; + } + + /** + * Saves the synchronization algorithm object to file + * + * @param syncAlgo + * The algorithm to save + * @throws FileNotFoundException + * propagate callee's exceptions + */ + public void saveSync(SynchronizationAlgorithm syncAlgo) throws FileNotFoundException { + + if (fSyncFile == null) { + return; + } + + FileChannel fc; + FileOutputStream fos; + ObjectOutputStream oos; + ByteBuffer buffer; + int res; + + fos = new FileOutputStream(fSyncFile, false); + fc = fos.getChannel(); + + buffer = ByteBuffer.allocate(HEADER_SIZE); + buffer.clear(); + + /* Save the header of the file */ + try { + fc.position(0); + + buffer.putInt(SYNC_FILE_MAGIC_NUMBER); + + buffer.putInt(FILE_VERSION); + + buffer.flip(); + res = fc.write(buffer); + assert (res <= HEADER_SIZE); + /* done writing the file header */ + + fc.position(HEADER_SIZE); + + oos = new ObjectOutputStream(fos); + oos.writeObject(syncAlgo); + oos.close(); + + } catch (IOException e) { + /* We should not have any problems at this point... */ + Activator.logError("Error saving trace synchronization data", e); //$NON-NLS-1$ + } finally { + try { + fc.close(); + fos.close(); + } catch (IOException e) { + Activator.logError("Error closing synchronization file", e); //$NON-NLS-1$ + } + } + return; + + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationManager.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationManager.java new file mode 100644 index 0000000000..fac513386b --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/SynchronizationManager.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.linuxtools.internal.tmf.core.Activator; +import org.eclipse.linuxtools.tmf.core.component.TmfComponent; +import org.eclipse.linuxtools.tmf.core.event.matching.ITmfEventMatching; +import org.eclipse.linuxtools.tmf.core.event.matching.TmfNetworkEventMatching; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; + +/** + * This abstract manager class handles loading trace synchronization data or + * otherwise their calculation. + * + * @author Geneviève Bastien + * @since 3.0 + */ +public abstract class SynchronizationManager extends TmfComponent { + + /** + * Function called to synchronize traces using the fully incremental + * synchronization algorithm + * + * @param syncFile + * The target name of the synchronization file. If it exists, it + * will be opened, otherwise it will be created and data from + * this synchro run will be saved there + * @param traces + * The list of traces to synchronize + * @param doSync + * Whether to actually synchronize or just try opening a sync + * file + * @return The synchronization object + */ + public static SynchronizationAlgorithm synchronizeTraces(final File syncFile, final ITmfTrace[] traces, boolean doSync) { + + SynchronizationAlgorithm syncAlgo; + if (doSync) { + syncAlgo = synchronize(syncFile, traces, new SyncAlgorithmFullyIncremental()); + } else { + syncAlgo = openExisting(syncFile); + if (syncAlgo == null) { + syncAlgo = new SyncAlgorithmFullyIncremental(); + } + } + return syncAlgo; + } + + /** + * Function called to synchronize traces with a specific synchronization + * algorithm. If a synchronization already exists, but is not the requested + * algorithm, the synchronization is done again using the new algorithm + * + * @param syncFile + * The target name of the synchronization file. If it exists, it + * will be opened, otherwise it will be created and data from + * this synchro run will be saved there + * @param traces + * The list of traces to synchronize + * @param algo + * A synchronization algorithm object to determine the algorithm + * used to synchronization. + * @param doSync + * Whether to actually synchronize or just try opening a sync + * file + * @return The synchronization object + */ + public static SynchronizationAlgorithm synchronizeTraces(final File syncFile, final ITmfTrace[] traces, SynchronizationAlgorithm algo, boolean doSync) { + + SynchronizationAlgorithm syncAlgo; + if (doSync) { + syncAlgo = synchronize(syncFile, traces, algo); + } else { + syncAlgo = openExisting(syncFile); + if (syncAlgo == null || (syncAlgo.getClass() != algo.getClass())) { + if (algo != null) { + syncAlgo = algo; + } else { + syncAlgo = new SyncAlgorithmFullyIncremental(); + } + } + } + + return syncAlgo; + } + + private static SynchronizationAlgorithm openExisting(final File syncFile) { + if ((syncFile != null) && syncFile.exists()) { + /* Load an existing history */ + try { + SynchronizationBackend syncBackend = new SynchronizationBackend(syncFile); + SynchronizationAlgorithm algo = syncBackend.openExistingSync(); + return algo; + } catch (IOException e) { + /* + * There was an error opening the existing file. Perhaps it was + * corrupted, perhaps it's an old version? We'll just + * fall-through and try to build a new one from scratch instead. + */ + Activator.logInfo("Problem opening existing trace synchronization file", e); //$NON-NLS-1$ + } + } + return null; + } + + private static SynchronizationAlgorithm synchronize(final File syncFile, final ITmfTrace[] traces, SynchronizationAlgorithm syncAlgo) { + ITmfEventMatching matching = new TmfNetworkEventMatching(traces, syncAlgo); + matching.matchEvents(); + + SynchronizationBackend syncBackend; + try { + syncBackend = new SynchronizationBackend(syncFile, false); + syncBackend.saveSync(syncAlgo); + } catch (IOException e) { + Activator.logError("Error while saving trace synchronization file", e); //$NON-NLS-1$ + } + return syncAlgo; + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransform.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransform.java new file mode 100644 index 0000000000..73ce661c5d --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransform.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import java.io.Serializable; + +import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; + +/** + * A default simple, identity timestamp transform. It is a singleton class and + * returns the timestamp itself + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfTimestampTransform implements ITmfTimestampTransform, Serializable { + + /** + * Generated serial UID + */ + private static final long serialVersionUID = -1480581417493073304L; + + /** + * The unique instance of this transform, since it is always the same + */ + public static final TmfTimestampTransform IDENTITY = new TmfTimestampTransform(); + + /** + * Default constructor + */ + protected TmfTimestampTransform() { + + } + + @Override + public ITmfTimestamp transform(ITmfTimestamp timestamp) { + return timestamp; + } + + @Override + public long transform(long timestamp) { + return timestamp; + } + + @Override + public ITmfTimestampTransform composeWith(ITmfTimestampTransform composeWith) { + /* Since this transform will not modify anything, return the other */ + return composeWith; + } + + @Override + public boolean equals(Object other) { + return other.getClass().equals(TmfTimestampTransform.class); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = (prime * result) + TmfTimestampTransform.class.hashCode(); + return result; + } + + @Override + public String toString() { + return "TmfTimestampTransform [ IDENTITY ]"; //$NON-NLS-1$ + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransformLinear.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransformLinear.java new file mode 100644 index 0000000000..1a20ea2f8d --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/TmfTimestampTransformLinear.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.core.synchronization; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.MathContext; + +import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; +import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; + +/** + * Class implementing a linear timestamp transform, with a slope and/or offset + * + * f(t) = alpha*t + beta + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfTimestampTransformLinear implements ITmfTimestampTransform, Serializable { + + /** + * Generated serial UID + */ + private static final long serialVersionUID = -4756608071358979461L; + + /** + * Respectively the slope and offset and this linear equation. + * + * FIXME: Maybe doubles will be enough, for the whole synchronization + * package as well, I think BigDecimal is a remnant of past trials and + * errors + */ + private final BigDecimal fAlpha; + private final BigDecimal fBeta; + + private static final MathContext fMc = MathContext.DECIMAL128; + + /** + * Default constructor + */ + public TmfTimestampTransformLinear() { + fAlpha = BigDecimal.ONE; + fBeta = BigDecimal.ZERO; + } + + /** + * Constructor with alpha and beta + * + * @param alpha + * The slope of the linear transform + * @param beta + * The initial offset of the linear transform + */ + public TmfTimestampTransformLinear(final double alpha, final double beta) { + fAlpha = BigDecimal.valueOf(alpha); + fBeta = BigDecimal.valueOf(beta); + } + + /** + * Constructor with alpha and beta in big decimal + * + * @param fAlpha2 + * The slope of the linear transform + * @param fBeta2 + * The initial offset of the linear transform + */ + public TmfTimestampTransformLinear(final BigDecimal fAlpha2, final BigDecimal fBeta2) { + if (fAlpha2 != null) { + fAlpha = fAlpha2; + } else { + fAlpha = BigDecimal.ONE; + } + if (fBeta2 != null) { + fBeta = fBeta2; + } else { + fBeta = BigDecimal.ZERO; + } + } + + @Override + public ITmfTimestamp transform(ITmfTimestamp timestamp) { + BigDecimal newvalue = BigDecimal.valueOf(timestamp.getValue()).multiply(fAlpha, fMc).add(fBeta); + return new TmfTimestamp(timestamp, newvalue.longValue()); + } + + @Override + public long transform(long timestamp) { + BigDecimal t = BigDecimal.valueOf(timestamp).multiply(fAlpha, fMc).add(fBeta); + return t.longValue(); + } + + @Override + public ITmfTimestampTransform composeWith(ITmfTimestampTransform composeWith) { + if (composeWith.equals(TmfTimestampTransform.IDENTITY)) { + /* If composing with identity, just return this */ + return this; + } else if (composeWith instanceof TmfTimestampTransformLinear) { + /* If composeWith is a linear transform, add the two together */ + TmfTimestampTransformLinear ttl = (TmfTimestampTransformLinear) composeWith; + BigDecimal newAlpha = fAlpha.multiply(ttl.fAlpha, fMc); + BigDecimal newBeta = fAlpha.multiply(ttl.fBeta, fMc).add(fBeta); + return new TmfTimestampTransformLinear(newAlpha, newBeta); + } else { + /* + * We do not know what to do with this kind of transform, just + * return this + */ + return this; + } + } + + @Override + public boolean equals(Object other) { + boolean result = false; + if (other instanceof TmfTimestampTransformLinear) { + TmfTimestampTransformLinear that = (TmfTimestampTransformLinear) other; + result = ((that.fAlpha.equals(fAlpha)) && (that.fBeta.equals(fBeta))); + } + return result; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = (prime * result) + (fBeta.multiply(fAlpha).intValue()); + return result; + } + + @Override + public String toString() { + return "TmfTimestampLinear [ alpha = " + fAlpha.toString() + //$NON-NLS-1$ + ", beta = " + fBeta.toString() + //$NON-NLS-1$ + " ]"; //$NON-NLS-1$ + } + +} diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/messages.properties b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/messages.properties new file mode 100644 index 0000000000..fb5cd463ce --- /dev/null +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/synchronization/messages.properties @@ -0,0 +1,21 @@ +SyncAlgorithmFullyIncremental_absent=Absent +SyncAlgorithmFullyIncremental_alpha=Alpha +SyncAlgorithmFullyIncremental_beta=Beta +SyncAlgorithmFullyIncremental_T_=T_ +SyncAlgorithmFullyIncremental_otherformula=C_T1(t) +SyncAlgorithmFullyIncremental_mult=* +SyncAlgorithmFullyIncremental_add=\ + +SyncAlgorithmFullyIncremental_ub=Number of points in upper hull +SyncAlgorithmFullyIncremental_lb=Number of points in lower hull +SyncAlgorithmFullyIncremental_accuracy=Accuracy +SyncAlgorithmFullyIncremental_accurate=Accurate +SyncAlgorithmFullyIncremental_approx=Approximate +SyncAlgorithmFullyIncremental_fail=Fail +SyncAlgorithmFullyIncremental_incomplete=Incomplete +SyncAlgorithmFullyIncremental_nbmatch=Number of matching packets received +SyncAlgorithmFullyIncremental_nbacc=Number of accurate packets +SyncAlgorithmFullyIncremental_reftrace=T0 +SyncAlgorithmFullyIncremental_othertrace=T1 +SyncAlgorithmFullyIncremental_refformula=C_T0(t) +SyncAlgorithmFullyIncremental_NA=N/A +SyncAlgorithmFullyIncremental_quality=Quality \ No newline at end of file diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java index 13ee08a6ea..7fbe99c6a9 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 Ericsson + * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -11,6 +11,7 @@ * Thomas Gatterweh - Updated scaling / synchronization * Francois Chouinard - Refactoring to align with TMF Event Model 1.0 * Francois Chouinard - Implement augmented interface + * Geneviève Bastien - Added copy constructor with new value *******************************************************************************/ package org.eclipse.linuxtools.tmf.core.timestamp; @@ -134,6 +135,24 @@ public class TmfTimestamp implements ITmfTimestamp { fPrecision = timestamp.getPrecision(); } + /** + * Copies a timestamp but with a new time value + * + * @param timestamp + * The timestamp to copy + * @param newvalue + * The value the new timestamp will have + * @since 3.0 + */ + public TmfTimestamp(ITmfTimestamp timestamp, long newvalue) { + if (timestamp == null) { + throw new IllegalArgumentException(); + } + fValue = newvalue; + fScale = timestamp.getScale(); + fPrecision = timestamp.getPrecision(); + } + // ------------------------------------------------------------------------ // ITmfTimestamp // ------------------------------------------------------------------------ diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/ITmfTrace.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/ITmfTrace.java index 6abe83791b..b0f0a38cae 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/ITmfTrace.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/ITmfTrace.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 Ericsson + * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -9,6 +9,8 @@ * Contributors: * Francois Chouinard - Initial API and implementation * Francois Chouinard - Updated as per TMF Trace Model 1.0 + * Geneviève Bastien - Added timestamp transforms and timestamp + * creation functions *******************************************************************************/ package org.eclipse.linuxtools.tmf.core.trace; @@ -24,6 +26,7 @@ import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics; +import org.eclipse.linuxtools.tmf.core.synchronization.ITmfTimestampTransform; import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange; import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer; @@ -39,9 +42,9 @@ import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation; *
  • the time range (span) of the events it contains * * Concrete ITmfTrace classes have to provide a parameter-less constructor and - * an initialization method (initTrace) if they are to be opened from - * the Project View. Also, a validation method (validate) has to be - * provided to ensure that the trace is of the correct type. + * an initialization method (initTrace) if they are to be opened from the + * Project View. Also, a validation method (validate) has to be provided + * to ensure that the trace is of the correct type. *

    * A trace can be accessed simultaneously from multiple threads by various * application components. To avoid obvious multi-threading issues, the trace @@ -82,19 +85,22 @@ import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation; * event = trace.getNext(context); * } * + * * A trace is also an event provider so it can process event requests * asynchronously (and coalesce compatible, concurrent requests). *

    - * - * Example 4: Process a whole trace (see ITmfEventRequest for variants) + * + * Example 4: Process a whole trace (see ITmfEventRequest for + * variants) *

      * ITmfRequest request = new TmfEventRequest<MyEventType>(MyEventType.class) {
    - *     @Override
    + *     @Override
      *     public void handleData(MyEventType event) {
      *         super.handleData(event);
      *         processEvent(event);
      *     }
    - *     @Override
    + *
    + *     @Override
      *     public void handleCompleted() {
      *         finish();
      *         super.handleCompleted();
    @@ -135,23 +141,29 @@ public interface ITmfTrace extends ITmfDataProvider {
          * properly parameterize an ITmfTrace instantiated with its parameterless
          * constructor.
          * 

    - * Typically, the parameterless constructor will provide the block size - * and its associated parser and indexer. + * Typically, the parameterless constructor will provide the block size and + * its associated parser and indexer. * - * @param resource the trace resource - * @param path the trace path - * @param type the trace event type - * @throws TmfTraceException If we couldn't open the trace + * @param resource + * the trace resource + * @param path + * the trace path + * @param type + * the trace event type + * @throws TmfTraceException + * If we couldn't open the trace */ void initTrace(IResource resource, String path, Class type) throws TmfTraceException; /** * Validate that the trace is of the correct type. * - * @param project the eclipse project - * @param path the trace path - * - * @return an IStatus object with validation result. Use severity OK to indicate success. + * @param project + * the eclipse project + * @param path + * the trace path + * @return an IStatus object with validation result. Use severity OK to + * indicate success. * @since 2.0 */ IStatus validate(IProject project, String path); @@ -268,7 +280,8 @@ public interface ITmfTrace extends ITmfDataProvider { /** * Returns the ratio (proportion) corresponding to the specified location. * - * @param location a trace specific location + * @param location + * a trace specific location * @return a floating-point number between 0.0 (beginning) and 1.0 (end) * @since 3.0 */ @@ -287,7 +300,9 @@ public interface ITmfTrace extends ITmfDataProvider { * If not null, the location requested must be valid otherwise the returned * context is undefined (up to the implementation to recover if possible). *

    - * @param location the trace specific location + * + * @param location + * the trace specific location * @return a context which can later be used to read the corresponding event * @since 3.0 */ @@ -296,21 +311,21 @@ public interface ITmfTrace extends ITmfDataProvider { /** * Position the trace at the 'rank'th event in the trace. *

    - * A rank <= 0 is interpreted as seeking for the first event of the - * trace. + * A rank <= 0 is interpreted as seeking for the first event of the trace. *

    * If the requested rank is beyond the last trace event, the context * returned will yield a null event if used in a subsequent read. * - * @param rank the event rank + * @param rank + * the event rank * @return a context which can later be used to read the corresponding event */ ITmfContext seekEvent(long rank); /** * Position the trace at the first event with the specified timestamp. If - * there is no event with the requested timestamp, a context pointing to - * the next chronological event is returned. + * there is no event with the requested timestamp, a context pointing to the + * next chronological event is returned. *

    * A null timestamp is interpreted as seeking for the first event of the * trace. @@ -318,7 +333,8 @@ public interface ITmfTrace extends ITmfDataProvider { * If the requested timestamp is beyond the last trace event, the context * returned will yield a null event if used in a subsequent read. * - * @param timestamp the timestamp of desired event + * @param timestamp + * the timestamp of desired event * @return a context which can later be used to read the corresponding event * @since 2.0 */ @@ -332,7 +348,8 @@ public interface ITmfTrace extends ITmfDataProvider { * voluntarily vague. Typically, it would refer to the event proportional * rank (arguably more intuitive) or timestamp in the trace file. * - * @param ratio the proportional 'rank' in the trace + * @param ratio + * the proportional 'rank' in the trace * @return a context which can later be used to read the corresponding event */ ITmfContext seekEvent(double ratio); @@ -356,6 +373,37 @@ public interface ITmfTrace extends ITmfDataProvider { * @return The host id of this trace * @since 3.0 */ - String getHostId(); + String getHostId(); + + // ------------------------------------------------------------------------ + // Timestamp transformation functions + // ------------------------------------------------------------------------ + + /** + * Returns the timestamp transformation for this trace + * + * @return the timestamp transform + * @since 3.0 + */ + ITmfTimestampTransform getTimestampTransform(); + + /** + * Sets the trace's timestamp transform + * + * @param tt + * The timestamp transform for all timestamps of this trace + * @since 3.0 + */ + void setTimestampTransform(final ITmfTimestampTransform tt); + + /** + * Creates a timestamp for this trace, using the transformation formula + * + * @param ts + * The time in long with which to create the timestamp + * @return The new timestamp + * @since 3.0 + */ + ITmfTimestamp createTimestamp(long ts); } diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java index 8ecd7ed5da..8f5d2c6181 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 Ericsson + * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -11,18 +11,24 @@ * Francois Chouinard - Updated as per TMF Trace Model 1.0 * Patrick Tasse - Updated for removal of context clone * Patrick Tasse - Updated for ranks in experiment location + * Geneviève Bastien - Added support of experiment synchronization *******************************************************************************/ package org.eclipse.linuxtools.tmf.core.trace; +import java.io.File; + import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.linuxtools.internal.tmf.core.Activator; import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentContext; import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentLocation; import org.eclipse.linuxtools.internal.tmf.core.trace.TmfLocationArray; +import org.eclipse.linuxtools.tmf.core.TmfCommonConstants; import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest; @@ -30,6 +36,9 @@ import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest; import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal; import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSynchronizedSignal; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationManager; import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange; import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; @@ -49,6 +58,13 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { // Constants // ------------------------------------------------------------------------ + /** + * The file name of the Synchronization + * + * @since 3.0 + */ + public final static String SYNCHRONIZATION_FILE_NAME = "synchronization.bin"; //$NON-NLS-1$ + /** * The default index page size */ @@ -78,9 +94,12 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { // ------------------------------------------------------------------------ /** - * @param type the event type - * @param id the experiment id - * @param traces the experiment set of traces + * @param type + * the event type + * @param id + * the experiment id + * @param traces + * the experiment set of traces */ public TmfExperiment(final Class type, final String id, final ITmfTrace[] traces) { this(type, id, traces, DEFAULT_INDEX_PAGE_SIZE, null); @@ -102,12 +121,15 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { this(type, id, traces, DEFAULT_INDEX_PAGE_SIZE, resource); } - /** - * @param type the event type - * @param path the experiment path - * @param traces the experiment set of traces - * @param indexPageSize the experiment index page size + * @param type + * the event type + * @param path + * the experiment path + * @param traces + * the experiment set of traces + * @param indexPageSize + * the experiment index page size */ public TmfExperiment(final Class type, final String path, final ITmfTrace[] traces, final int indexPageSize) { this(type, path, traces, indexPageSize, null); @@ -140,6 +162,14 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { } fTraces = traces; + + if (resource != null) { + try { + this.synchronizeTraces(); + } catch (TmfTraceException e) { + Activator.logError("Error synchronizing experiment", e); //$NON-NLS-1$ + } + } } /** @@ -195,7 +225,8 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { * Returns the timestamp of the event at the requested index. If none, * returns null. * - * @param index the event index (rank) + * @param index + * the event index (rank) * @return the corresponding event timestamp * @since 2.0 */ @@ -209,7 +240,8 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { /** * Set the file to be used for bookmarks on this experiment * - * @param file the bookmarks file + * @param file + * the bookmarks file */ public void setBookmarksFile(final IFile file) { fBookmarksFile = file; @@ -240,8 +272,8 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { } if (request instanceof ITmfEventRequest - && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest) request).getRange().getStartTime()) - && request.getIndex() == 0) + && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest) request).getRange().getStartTime()) + && request.getIndex() == 0) { final ITmfContext context = seekEvent(((ITmfEventRequest) request).getRange().getStartTime()); ((ITmfEventRequest) request).setStartIndex((int) context.getRank()); @@ -362,7 +394,8 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { TmfExperimentContext expContext = (TmfExperimentContext) context; - // If an event was consumed previously, first get the next one from that trace + // If an event was consumed previously, first get the next one from that + // trace final int lastTrace = expContext.getLastTrace(); if (lastTrace != TmfExperimentContext.NO_TRACE) { final ITmfContext traceContext = expContext.getContexts()[lastTrace]; @@ -425,6 +458,62 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser { return initTs; } + /** + * Synchronizes the traces of an experiment. By default it only tries to + * read a synchronization file if it exists + * + * @return The synchronization object + * @throws TmfTraceException + * propagate TmfTraceExceptions + * @since 3.0 + */ + public synchronized SynchronizationAlgorithm synchronizeTraces() throws TmfTraceException { + return synchronizeTraces(false); + } + + /** + * Synchronizes the traces of an experiment. + * + * @param doSync + * Whether to actually synchronize or just try opening a sync + * file + * @return The synchronization object + * @throws TmfTraceException + * propagate TmfTraceExceptions + * @since 3.0 + */ + public synchronized SynchronizationAlgorithm synchronizeTraces(boolean doSync) throws TmfTraceException { + + /* Set up the path to the synchronization file we'll use */ + IResource resource = this.getResource(); + String supplDirectory = null; + + try { + /* get the directory where the file will be stored. */ + if (resource != null) { + supplDirectory = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER); + } + } catch (CoreException e) { + throw new TmfTraceException(e.toString(), e); + } + + final File syncFile = (supplDirectory != null) ? new File(supplDirectory + File.separator + SYNCHRONIZATION_FILE_NAME) : null; + + final SynchronizationAlgorithm syncAlgo = SynchronizationManager.synchronizeTraces(syncFile, fTraces, doSync); + + final TmfTraceSynchronizedSignal signal = new TmfTraceSynchronizedSignal(this, syncAlgo); + + /* Broadcast in separate thread to prevent deadlock */ + new Thread() { + @Override + public void run() { + broadcast(signal); + } + }.start(); + + return syncAlgo; + } + @Override @SuppressWarnings("nls") public synchronized String toString() { diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java index 817d852547..ea3f7b59f4 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 Ericsson + * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -10,15 +10,24 @@ * Francois Chouinard - Initial API and implementation * Francois Chouinard - Updated as per TMF Trace Model 1.0 * Patrick Tasse - Updated for removal of context clone + * Geneviève Bastien - Added timestamp transforms, its saving to file and + * timestamp creation functions *******************************************************************************/ package org.eclipse.linuxtools.tmf.core.trace; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -26,6 +35,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.linuxtools.internal.tmf.core.Activator; +import org.eclipse.linuxtools.tmf.core.TmfCommonConstants; import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider; import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; @@ -38,6 +48,8 @@ import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal; import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics; import org.eclipse.linuxtools.tmf.core.statistics.TmfStateStatistics; +import org.eclipse.linuxtools.tmf.core.synchronization.ITmfTimestampTransform; +import org.eclipse.linuxtools.tmf.core.synchronization.TmfTimestampTransform; import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange; import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; @@ -116,6 +128,10 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace { protected final Map fStateSystems = new LinkedHashMap(); + private ITmfTimestampTransform fTsTransform; + + private static final String SYNCHRONIZATION_FORMULA_FILE = "sync_formula"; //$NON-NLS-1$ + // ------------------------------------------------------------------------ // Construction // ------------------------------------------------------------------------ @@ -737,6 +753,102 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace { } } + /** + * Returns the file resource used to store synchronization formula. The file + * may not exist. + * + * @return the synchronization file + */ + private File getSyncFormulaFile() { + File file = null; + if (fResource instanceof IFolder) { + try { + String supplDirectory; + + supplDirectory = fResource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER); + + file = new File(supplDirectory + File.separator + SYNCHRONIZATION_FORMULA_FILE); + + } catch (CoreException e) { + + } + } + return file; + } + + // ------------------------------------------------------------------------ + // Timestamp transformation functions + // ------------------------------------------------------------------------ + + /** + * @since 3.0 + */ + @Override + public ITmfTimestampTransform getTimestampTransform() { + if (fTsTransform == null) { + /* Check if a formula is stored somewhere in the resources */ + File sync_file = getSyncFormulaFile(); + if (sync_file != null && sync_file.exists()) { + + try { + FileInputStream fis = new FileInputStream(sync_file); + ObjectInputStream ois = new ObjectInputStream(fis); + fTsTransform = (ITmfTimestampTransform) ois.readObject(); + + ois.close(); + fis.close(); + } catch (ClassNotFoundException e1) { + fTsTransform = TmfTimestampTransform.IDENTITY; + } catch (FileNotFoundException e1) { + fTsTransform = TmfTimestampTransform.IDENTITY; + } catch (IOException e1) { + fTsTransform = TmfTimestampTransform.IDENTITY; + } + } else { + fTsTransform = TmfTimestampTransform.IDENTITY; + } + } + return fTsTransform; + } + + /** + * @since 3.0 + */ + @Override + public void setTimestampTransform(final ITmfTimestampTransform tt) { + fTsTransform = tt; + + /* Save the timestamp transform to a file */ + File sync_file = getSyncFormulaFile(); + if (sync_file != null) { + if (sync_file.exists()) { + sync_file.delete(); + } + FileOutputStream fos; + ObjectOutputStream oos; + + /* Save the header of the file */ + try { + fos = new FileOutputStream(sync_file, false); + oos = new ObjectOutputStream(fos); + + oos.writeObject(fTsTransform); + oos.close(); + fos.close(); + } catch (IOException e1) { + Activator.logError("Error writing timestamp transform for trace", e1); //$NON-NLS-1$ + } + } + } + + /** + * @since 3.0 + */ + @Override + public ITmfTimestamp createTimestamp(long ts) { + return new TmfTimestamp(getTimestampTransform().transform(ts)); + } + // ------------------------------------------------------------------------ // toString // ------------------------------------------------------------------------ diff --git a/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF index 7d9e01a4cd..19659e2d8f 100644 --- a/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.tmf.ui/META-INF/MANIFEST.MF @@ -43,6 +43,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.ui;x-friends:="org.eclipse.l org.eclipse.linuxtools.tmf.ui.views.histogram, org.eclipse.linuxtools.tmf.ui.views.statesystem, org.eclipse.linuxtools.tmf.ui.views.statistics, + org.eclipse.linuxtools.tmf.ui.views.synchronization, org.eclipse.linuxtools.tmf.ui.views.timechart, org.eclipse.linuxtools.tmf.ui.views.timegraph, org.eclipse.linuxtools.tmf.ui.views.uml2sd, diff --git a/org.eclipse.linuxtools.tmf.ui/icons/eview16/synced.gif b/org.eclipse.linuxtools.tmf.ui/icons/eview16/synced.gif new file mode 100644 index 0000000000000000000000000000000000000000..870934b6934844102afd508e067750591ccc34c0 GIT binary patch literal 160 zcmV;R0AK${Nk%w1VGsZi0J9GOy@VF3ZxE(y5d7@1`{kGX@x%S`!~Xs6{OYOw_SL$V zCjR)|{`lSf_}%;LvH$=7A^8LW000jFEC2ui01yBW000C{@W}_jyqF%FF*sXy0Zg-0 zXf+mw!4@wZTmfPScs^qRLF}SQ4@gmna3g>*IQghNsY+tXkpKpcfp)vCJ_O*fz()`; OzdrMMtX{Vt5db^*GD&v; literal 0 HcmV?d00001 diff --git a/org.eclipse.linuxtools.tmf.ui/plugin.properties b/org.eclipse.linuxtools.tmf.ui/plugin.properties index 4d662a4c53..363e56b37f 100644 --- a/org.eclipse.linuxtools.tmf.ui/plugin.properties +++ b/org.eclipse.linuxtools.tmf.ui/plugin.properties @@ -27,6 +27,8 @@ uml2sd.view.name = Sequence Diagram histogram.view.name = Histogram ssvisualizer.view.name = State System Explorer callstack.view.name = Call Stack +synchronization.view.name = Synchronization + # Tracing wizards project.new.category.name = Tracing @@ -90,6 +92,10 @@ command.batch_import = Batch Import... command.batch_import.mnemonic = B command.batch_import.descriptio = Batch Import +command.synchronize_traces = Synchronize Traces +command.synchronize_traces.mnemonic = y +command.synchronize_traces.description = Synchronize 2 or more traces + ## Trace menu # Open, Copy, Rename, Delete, Delete Supplementary Files, Select Trace Type diff --git a/org.eclipse.linuxtools.tmf.ui/plugin.xml b/org.eclipse.linuxtools.tmf.ui/plugin.xml index 6cfe04131b..93eaaaef58 100644 --- a/org.eclipse.linuxtools.tmf.ui/plugin.xml +++ b/org.eclipse.linuxtools.tmf.ui/plugin.xml @@ -88,6 +88,15 @@ name="%callstack.view.name" restorable="true"> + + @@ -663,6 +672,30 @@ + + + + + + + + + + + + @@ -744,6 +777,12 @@ id="org.eclipse.linuxtools.tmf.ui.command.select_traces" name="%command.select_traces"> + + + + + + + + + + + + + + diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/Messages.java index 5f9ac1c414..a7dd632233 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/Messages.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/Messages.java @@ -43,17 +43,22 @@ public class Messages extends NLS { public static String DeleteExperimentHandler_Error; public static String SelectTraceTypeHandler_ErrorSelectingTrace; - public static String SelectTraceTypeHandler_Title; - public static String SelectTraceTypeHandler_TraceFailedValidation; - public static String SelectTraceTypeHandler_TracesFailedValidation; public static String SelectTraceTypeHandler_InvalidTraceType; public static String DropAdapterAssistant_RenameTraceTitle; public static String DropAdapterAssistant_RenameTraceMessage; + public static String SynchronizeTracesHandler_CopyProblem; + public static String SynchronizeTracesHandler_WrongType; + public static String SynchronizeTracesHandler_WrongTraceNumber; + public static String SynchronizeTracesHandler_Title; + public static String SynchronizeTracesHandler_Error; + public static String SynchronizeTracesHandler_ErrorSynchingExperiment; + public static String SynchronizeTracesHandler_ErrorSynchingForTrace; + static { // initialize resource bundle NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/OpenExperimentHandler.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/OpenExperimentHandler.java index 4b70c4a5b7..c4dbfbe51d 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/OpenExperimentHandler.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/OpenExperimentHandler.java @@ -120,7 +120,7 @@ public class OpenExperimentHandler extends AbstractHandler { return; } - /* Unlike traces, there is no instanceExperiment, so we call this function + /* FIXME Unlike traces, there is no instanceExperiment, so we call this function * here alone. Maybe it would be better to do this on experiment's element * constructor? */ @@ -128,6 +128,7 @@ public class OpenExperimentHandler extends AbstractHandler { // Instantiate the experiment's traces final List traceEntries = experimentElement.getTraces(); + experimentElement.refreshSupplementaryFolder(); final int nbTraces = traceEntries.size(); int cacheSize = Integer.MAX_VALUE; String commonEditorId = null; diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java new file mode 100644 index 0000000000..9ac1c4c017 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/SynchronizeTracesHandler.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.internal.tmf.ui.project.handlers; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.linuxtools.internal.tmf.ui.Activator; +import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; +import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; +import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment; +import org.eclipse.linuxtools.tmf.ui.project.model.ITmfProjectModelElement; +import org.eclipse.linuxtools.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.linuxtools.tmf.ui.project.model.TmfTraceElement; +import org.eclipse.linuxtools.tmf.ui.project.model.TraceUtils; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * Handles the synchronization of an experiment, when the user selects this + * option in the menu + */ +public class SynchronizeTracesHandler extends AbstractHandler { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private TreeSelection fSelection = null; + private static final String CR = System.getProperty("line.separator"); //$NON-NLS-1$ + + // ------------------------------------------------------------------------ + // Validation + // ------------------------------------------------------------------------ + + @Override + public boolean isEnabled() { + return true; + } + + // ------------------------------------------------------------------------ + // Execution + // ------------------------------------------------------------------------ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // Check if we are closing down + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + return null; + } + + // Get the selection + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return false; + } + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider == null) { + return false; + } + ISelection selection = selectionProvider.getSelection(); + + // Make sure selection contains only traces + fSelection = null; + final ArrayList tl = new ArrayList(); + final ArrayList uiexperiment = new ArrayList(); + if (selection instanceof TreeSelection) { + fSelection = (TreeSelection) selection; + Iterator iterator = fSelection.iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof TmfTraceElement) { + tl.add((TmfTraceElement) element); + } else if (element instanceof TmfExperimentElement) { + TmfExperimentElement exp = (TmfExperimentElement) element; + uiexperiment.add(exp); + for (TmfTraceElement trace : exp.getTraces()) { + tl.add(trace); + } + } + } + } + + if ((uiexperiment.size() == 1) && (tl.size() > 1)) { + + Thread thread = new Thread() { + @Override + public void run() { + + final ITmfTrace[] traces = new ITmfTrace[tl.size()]; + final TmfExperimentElement exp = uiexperiment.get(0); + + for (int i = 0; i < tl.size(); i++) { + ITmfTrace trace = tl.get(i).instantiateTrace(); + ITmfEvent traceEvent = tl.get(i).instantiateEvent(); + if (trace == null) { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_WrongType + tl.get(i).getName()); + for (int j = 0; j < i; j++) { + traces[j].dispose(); + } + return; + } + try { + trace.initTrace(tl.get(i).getResource(), tl.get(i).getLocation().getPath(), traceEvent.getClass()); + } catch (TmfTraceException e) { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.OpenTraceHandler_InitError + CR + CR + e); + trace.dispose(); + for (int j = 0; j < i; j++) { + traces[j].dispose(); + } + return; + } + traces[i] = trace; + } + + /* + * FIXME Unlike traces, there is no instanceExperiment, so + * we call this function here alone. Maybe it would be + * better to do this on experiment's element constructor? + */ + exp.refreshSupplementaryFolder(); + final TmfExperiment experiment = new TmfExperiment(ITmfEvent.class, exp.getName(), traces, exp.getResource()); + + try { + final SynchronizationAlgorithm syncAlgo = experiment.synchronizeTraces(true); + + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + /* + * For each trace in the experiment, if there is + * a transform equation, copy the original + * trace, so that a new state system will be + * generated with sync time. + */ + for (int i = 0; i < tl.size(); i++) { + TmfTraceElement traceel = tl.get(i); + try { + if (syncAlgo.isTraceSynced(traceel.getName())) { + + /* Find the original trace */ + TmfTraceElement origtrace = null; + for (ITmfProjectModelElement el : traceel.getProject().getTracesFolder().getTraces()) { + if (el.getName().equals(traceel.getName())) { + origtrace = (TmfTraceElement) el; + } + } + + if (origtrace != null) { + /* + * Make sure a trace with the + * new name does not exist + */ + String newname = traceel.getName(); + boolean traceexists; + do { + traceexists = false; + newname += "_"; //$NON-NLS-1$ + for (ITmfProjectModelElement el : traceel.getProject().getTracesFolder().getTraces()) { + if (el.getName().equals(newname)) { + traceexists = true; + } + } + } while (traceexists); + + /* Copy the original trace */ + TmfTraceElement newtrace = origtrace.copy(newname); + + if (newtrace != null) { + + syncAlgo.renameTrace(origtrace.getName(), newtrace.getName()); + + /* + * Instantiate the new trace + * and set its sync formula + */ + ITmfTrace trace = newtrace.instantiateTrace(); + ITmfEvent traceEvent = newtrace.instantiateEvent(); + + trace.initTrace(newtrace.getResource(), newtrace.getLocation().getPath(), traceEvent.getClass()); + trace.setTimestampTransform(syncAlgo.getTimestampTransform(trace)); + + /* + * Add the new trace to the + * experiment + */ + exp.addTrace(newtrace); + + /* + * Delete the original trace + * element + */ + exp.removeTrace(traceel); + } else { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_Error + CR + CR + String.format(Messages.SynchronizeTracesHandler_CopyProblem, origtrace.getName())); + } + } + } + } catch (CoreException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingForTrace, exp.getName(), traceel.getName()), e); + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_Error + CR + CR + e.getMessage()); + } catch (TmfTraceException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingForTrace, exp.getName(), traceel.getName()), e); + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_Error + CR + CR + e.getMessage()); + } + } + } + }); + + } catch (TmfTraceException e) { + Activator.getDefault().logError(String.format(Messages.SynchronizeTracesHandler_ErrorSynchingExperiment, exp.getName()), e); + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.OpenExperimentHandler_Error + CR + CR + e.getMessage()); + } + } + }; + thread.start(); + + } else { + TraceUtils.displayErrorMsg(Messages.SynchronizeTracesHandler_Title, Messages.SynchronizeTracesHandler_WrongTraceNumber); + } + + return null; + } + +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/messages.properties index 3161c0f95a..e8cfa94dd4 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/messages.properties +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/project/handlers/messages.properties @@ -39,3 +39,13 @@ SelectTraceTypeHandler_InvalidTraceType = Type could not be set for one or more # Drag and drop DropAdapterAssistant_RenameTraceTitle=Confirm rename trace DropAdapterAssistant_RenameTraceMessage=A trace with the name ''{0}'' already exists in the target project.\nRename the dropped trace? + +# Trace synchronization +SynchronizeTracesHandler_CopyProblem=Couldn't copy the original trace %s +SynchronizeTracesHandler_WrongTraceNumber=Experiment must have more than one trace +SynchronizeTracesHandler_Title=Synchronize traces +SynchronizeTracesHandler_WrongType=Trace is not a kernel trace:\n +SynchronizeTracesHandler_Error=Error synchronizing experiment + +SynchronizeTracesHandler_ErrorSynchingExperiment=Error synchronizing experiment %s +SynchronizeTracesHandler_ErrorSynchingForTrace=Error synchronizing experiment %s for trace %s diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfWithFolderElement.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfWithFolderElement.java index a2ca20ee55..8fdf44538a 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfWithFolderElement.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/project/model/TmfWithFolderElement.java @@ -29,7 +29,7 @@ import org.eclipse.linuxtools.tmf.core.trace.TmfTrace; * Base class for project elements who will have folder elements * under them to store supplementary files. * - * @author gbastien + * @author Geneviève Bastien * @since 2.0 */ public abstract class TmfWithFolderElement extends TmfProjectModelElement { @@ -239,7 +239,7 @@ public abstract class TmfWithFolderElement extends TmfProjectModelElement { if (TmfTrace.class.getCanonicalName().equals(member.getPersistentProperty(TmfCommonConstants.TRACETYPE))) { member.delete(true, null); } - if (TmfExperiment.class.getCanonicalName().equals(member.getPersistentProperty(TmfCommonConstants.TRACETYPE))) { + else if (TmfExperiment.class.getCanonicalName().equals(member.getPersistentProperty(TmfCommonConstants.TRACETYPE))) { member.delete(true, null); } } diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/Messages.java new file mode 100644 index 0000000000..41351a01ed --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/Messages.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.ui.views.synchronization; + +import org.eclipse.osgi.util.NLS; + +/** + * Message file for the synchronization view + * @since 3.0 + */ +@SuppressWarnings("javadoc") +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.linuxtools.tmf.ui.views.synchronization.messages"; //$NON-NLS-1$ + public static String TmfSynchronizationView_NameColumn; + public static String TmfSynchronizationView_ValueColumn; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/TmfSynchronizationView.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/TmfSynchronizationView.java new file mode 100644 index 0000000000..ce06df91b6 --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/TmfSynchronizationView.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2013 École Polytechnique de Montréal + * + * 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: + * Geneviève Bastien - Initial implementation and API + *******************************************************************************/ + +package org.eclipse.linuxtools.tmf.ui.views.synchronization; + +import java.util.Map; + +import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; +import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSynchronizedSignal; +import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationAlgorithm; +import org.eclipse.linuxtools.tmf.ui.views.TmfView; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; + +/** + * Small view to display statistics about a synchronization + * + * @author Geneviève Bastien + * @since 3.0 + */ +public class TmfSynchronizationView extends TmfView { + + /** + * The ID corresponds to the package in which this class is embedded. + */ + public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.synchronization"; //$NON-NLS-1$ + + /** + * The view name. + */ + public static final String TMF_SYNCHRONIZATION_VIEW = "SynchronizationView"; //$NON-NLS-1$ + + /** + * The synchronization algorithm to display stats for + */ + private SynchronizationAlgorithm fAlgoSync; + + private Tree fTree; + + /** + * Default constructor + */ + public TmfSynchronizationView() { + super(TMF_SYNCHRONIZATION_VIEW); + } + + @Override + public void createPartControl(Composite parent) { + fTree = new Tree(parent, SWT.NONE); + TreeColumn nameCol = new TreeColumn(fTree, SWT.NONE, 0); + TreeColumn valueCol = new TreeColumn(fTree, SWT.NONE, 1); + nameCol.setText(Messages.TmfSynchronizationView_NameColumn); + valueCol.setText(Messages.TmfSynchronizationView_ValueColumn); + + fTree.setItemCount(0); + + fTree.setHeaderVisible(true); + nameCol.pack(); + valueCol.pack(); + + } + + private void updateTable() { + fTree.setItemCount(0); + if (fAlgoSync == null) { + return; + } + + for (Map.Entry> entry : fAlgoSync.getStats().entrySet()) { + TreeItem item = new TreeItem(fTree, SWT.NONE); + item.setText(0, entry.getKey().toString()); + item.setText(1, entry.getValue().toString()); + + for (Map.Entry subentry : entry.getValue().entrySet()) { + TreeItem subitem = new TreeItem(item, SWT.NONE); + subitem.setText(0, subentry.getKey().toString()); + subitem.setText(1, subentry.getValue().toString()); + } + } + + /* Expand the tree items */ + for (int i = 0; i < fTree.getItemCount(); i++) { + fTree.getItem(i).setExpanded(true); + } + + for (TreeColumn column : fTree.getColumns()) { + column.pack(); + } + } + + @Override + public void setFocus() { + fTree.setFocus(); + } + + /** + * Handler called when traces are synchronized + * + * @param signal + * Contains the information about the selection. + */ + @TmfSignalHandler + public void traceSynchronized(TmfTraceSynchronizedSignal signal) { + if (signal.getSyncAlgo() != fAlgoSync) { + fAlgoSync = signal.getSyncAlgo(); + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + updateTable(); + } + }); + } + } +} diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/messages.properties new file mode 100644 index 0000000000..9f4465874b --- /dev/null +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/synchronization/messages.properties @@ -0,0 +1,2 @@ +TmfSynchronizationView_NameColumn=Synchronization Information +TmfSynchronizationView_ValueColumn=Value -- 2.34.1