| /******************************************************************************* |
| * Copyright (c) 2013, 2015 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Alexandre Montplaisir - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.ctf.core.tests.event; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace; |
| import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; |
| import org.eclipse.tracecompass.tmf.core.event.ITmfLostEvent; |
| import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest; |
| import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest; |
| import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory; |
| import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; |
| import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; |
| import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfContext; |
| import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent; |
| import org.eclipse.tracecompass.tmf.ctf.core.tests.shared.CtfTmfTestTraceUtils; |
| import org.eclipse.tracecompass.tmf.ctf.core.trace.CtfTmfTrace; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| /** |
| * Tests to verify that lost events are handled correctly. |
| * |
| * Be wary if you are using Babeltrace to cross-check those values. There could |
| * be a bug in Babeltrace with regards to lost events. See |
| * http://bugs.lttng.org/issues/589 |
| * |
| * It's not 100% sure at this point which implementation is correct, so for now |
| * these tests assume the Java implementation is the right one. |
| * |
| * @author Alexandre Montplaisir |
| */ |
| public class CtfTmfLostEventsTest { |
| |
| private static final @NonNull CtfTestTrace testTrace = CtfTestTrace.HELLO_LOST; |
| |
| private CtfTmfTrace fixture = null; |
| |
| /** |
| * Class setup |
| */ |
| @Before |
| public void setUp() { |
| fixture = CtfTmfTestTraceUtils.getTrace(testTrace); |
| fixture.indexTrace(true); |
| } |
| |
| /** |
| * Clean-up |
| */ |
| @After |
| public void tearDown() { |
| if (fixture != null) { |
| fixture.dispose(); |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Test methods |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Test that the number of events is reported correctly (a range of lost |
| * events is counted as one event). |
| */ |
| @Test |
| public void testNbEvents() { |
| final long expectedReal = 32300; |
| final long expectedLost = 562; |
| |
| EventCountRequest req = new EventCountRequest(); |
| fixture.sendRequest(req); |
| try { |
| req.waitForCompletion(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| |
| assertEquals(expectedReal, req.getReal()); |
| assertEquals(expectedLost, req.getLost()); |
| } |
| |
| /** |
| * Test that the number of events is reported correctly (a range of lost |
| * events is counted as one event). Events could be wrongly counted as lost |
| * events in certain situations. |
| */ |
| @Test |
| public void testNbEventsBug475007() { |
| final CtfTestTrace tmfTestTrace = CtfTestTrace.DYNSCOPE; |
| CtfTmfTrace trace = CtfTmfTestTraceUtils.getTrace(tmfTestTrace); |
| trace.indexTrace(true); |
| |
| final long expectedReal = 100003; |
| final long expectedLost = 1; |
| |
| EventCountRequest req = new EventCountRequest(); |
| trace.sendRequest(req); |
| try { |
| req.waitForCompletion(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| |
| assertEquals(expectedReal, req.getReal()); |
| assertEquals(expectedLost, req.getLost()); |
| |
| trace.dispose(); |
| } |
| |
| /** |
| * Test getting the first lost event from the trace. |
| */ |
| @Test |
| public void testFirstLostEvent() { |
| final long rank = 190; |
| final long startTime = 1376592664828900165L; |
| final ITmfTimestamp start = TmfTimestamp.fromNanos(startTime); |
| final ITmfTimestamp end = TmfTimestamp.fromNanos(startTime + 502911L); |
| final long nbLost = 859; |
| |
| validateLostEvent(rank, start, end, nbLost); |
| } |
| |
| /** |
| * Test getting the second lost event from the trace. |
| */ |
| @Test |
| public void testSecondLostEvent() { |
| final long rank = 229; |
| final long startTime = 1376592664829477058L; |
| final ITmfTimestamp start = TmfTimestamp.fromNanos(startTime); |
| final ITmfTimestamp end = TmfTimestamp.fromNanos(startTime + 347456L); |
| final long nbLost = 488; |
| |
| validateLostEvent(rank, start, end, nbLost); |
| } |
| |
| private void validateLostEvent(final long rank, final @NonNull ITmfTimestamp start, final ITmfTimestamp end, final long nbLost) { |
| final CtfTmfEvent ev = getOneEventTime(start); |
| /* Make sure seeking by rank yields the same event */ |
| final CtfTmfEvent ev2 = getOneEventRank(rank); |
| assertEquals(ev, ev2); |
| |
| assertTrue(ev instanceof ITmfLostEvent); |
| ITmfLostEvent event = (ITmfLostEvent) ev; |
| |
| assertEquals(start, event.getTimestamp()); |
| assertEquals(start, event.getTimeRange().getStartTime()); |
| assertEquals(end, event.getTimeRange().getEndTime()); |
| assertEquals(nbLost, event.getNbLostEvents()); |
| } |
| |
| /** |
| * Test getting one normal event from the trace (lost events should not |
| * interfere). |
| */ |
| @Test |
| public void testNormalEvent() { |
| final long rank = 200; |
| final ITmfTimestamp ts = TmfTimestamp.fromNanos(1376592664829425780L); |
| |
| final CtfTmfEvent event = getOneEventTime(ts); |
| /* Make sure seeking by rank yields the same event */ |
| final CtfTmfEvent event2 = getOneEventRank(rank); |
| assertEquals(event, event2); |
| |
| assertFalse(event instanceof ITmfLostEvent); |
| assertEquals(ts, event.getTimestamp()); |
| } |
| |
| /** |
| * Test getting a lost event from a trace that has a timestamp transform. |
| */ |
| @Test |
| public void testLostEventWithTransform() { |
| CtfTmfTrace trace = CtfTmfTestTraceUtils.getTrace(testTrace); |
| long offset = 1234567890L; |
| trace.setTimestampTransform(TimestampTransformFactory.createWithOffset(offset)); |
| trace.indexTrace(true); |
| |
| final long rank = 190; |
| final ITmfTimestamp start = TmfTimestamp.fromNanos(1376592664828900165L + offset); |
| final ITmfTimestamp end = TmfTimestamp.fromNanos(1376592664828900165L + 502911L + offset); |
| final long nbLost = 859; |
| |
| ITmfContext context = trace.seekEvent(rank); |
| final CtfTmfEvent ev = trace.getNext(context); |
| context.dispose(); |
| |
| assertTrue(ev instanceof ITmfLostEvent); |
| ITmfLostEvent event = (ITmfLostEvent) ev; |
| |
| assertEquals(start, event.getTimestamp()); |
| assertEquals(start, event.getTimeRange().getStartTime()); |
| assertEquals(end, event.getTimeRange().getEndTime()); |
| assertEquals(nbLost, event.getNbLostEvents()); |
| |
| trace.setTimestampTransform(null); |
| trace.dispose(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Event requests |
| // ------------------------------------------------------------------------ |
| |
| private CtfTmfEvent getOneEventRank(long rank) { |
| OneEventRequestPerRank req = new OneEventRequestPerRank(rank); |
| fixture.sendRequest(req); |
| try { |
| req.waitForCompletion(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| return req.getEvent(); |
| } |
| |
| private CtfTmfEvent getOneEventTime(@NonNull ITmfTimestamp ts) { |
| OneEventRequestPerTs req = new OneEventRequestPerTs(ts); |
| fixture.sendRequest(req); |
| try { |
| req.waitForCompletion(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| return req.getEvent(); |
| } |
| |
| private class OneEventRequestPerRank extends TmfEventRequest { |
| |
| private CtfTmfEvent event = null; |
| |
| public OneEventRequestPerRank(long rank) { |
| super(CtfTmfEvent.class, TmfTimeRange.ETERNITY, rank, 1, ExecutionType.FOREGROUND); |
| } |
| |
| @Override |
| public void handleData(ITmfEvent ev) { |
| /* Type is checked by the request, cast should be safe */ |
| event = (CtfTmfEvent) ev; |
| } |
| |
| public CtfTmfEvent getEvent() { |
| return event; |
| } |
| } |
| |
| private class OneEventRequestPerTs extends TmfEventRequest { |
| |
| private CtfTmfEvent event = null; |
| |
| public OneEventRequestPerTs(@NonNull ITmfTimestamp ts) { |
| super(CtfTmfEvent.class, |
| new TmfTimeRange(ts, ts), |
| 0, ITmfEventRequest.ALL_DATA, ExecutionType.FOREGROUND); |
| } |
| |
| @Override |
| public void handleData(ITmfEvent ev) { |
| event = (CtfTmfEvent) ev; |
| } |
| |
| public CtfTmfEvent getEvent() { |
| return event; |
| } |
| } |
| |
| private class EventCountRequest extends TmfEventRequest { |
| |
| private long nbReal = 0; |
| private long nbLost = 0; |
| |
| public EventCountRequest() { |
| super(CtfTmfEvent.class, TmfTimeRange.ETERNITY, 0, |
| ITmfEventRequest.ALL_DATA, ExecutionType.FOREGROUND); |
| } |
| |
| @Override |
| public void handleData(ITmfEvent event) { |
| if (event instanceof ITmfLostEvent) { |
| nbLost++; |
| } else { |
| nbReal++; |
| } |
| } |
| |
| public long getReal() { |
| return nbReal; |
| } |
| |
| public long getLost() { |
| return nbLost; |
| } |
| } |
| } |