From 7b88510c20eb2a6bffdbf4d4abf32a20a40c2de8 Mon Sep 17 00:00:00 2001 From: Vincent Perot Date: Mon, 4 Aug 2014 16:53:05 -0400 Subject: pcap: make PacketStream compute useful information The PacketStream now computes Nb of packets/bytes, duration of the conversation, Bytes per seconds, etc. Also, it now does not store indexes to packet, since it makes the size of PacketStream proportional to the size of the trace. This is unwanted since we have to be able to open traces that are bigger than memory. Change-Id: I8f6bde99ceabc20c4a66786a2dbd25d49251cc9e Signed-off-by: Vincent Perot Reviewed-on: https://git.eclipse.org/r/30998 Tested-by: Hudson CI Reviewed-by: Alexandre Montplaisir Reviewed-by: Matthew Khouzam --- .../pcap/core/tests/stream/StreamBuildTest.java | 82 ++++----- .../META-INF/MANIFEST.MF | 3 +- .../pcap/core/packet/PacketUniqueID.java | 93 ---------- .../linuxtools/pcap/core/stream/PacketStream.java | 192 +++++++++++++++++---- 4 files changed, 193 insertions(+), 177 deletions(-) delete mode 100644 lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/packet/PacketUniqueID.java diff --git a/lttng/org.eclipse.linuxtools.pcap.core.tests/src/org/eclipse/linuxtools/pcap/core/tests/stream/StreamBuildTest.java b/lttng/org.eclipse.linuxtools.pcap.core.tests/src/org/eclipse/linuxtools/pcap/core/tests/stream/StreamBuildTest.java index 90c8e6b93f..41dd1fd7dd 100644 --- a/lttng/org.eclipse.linuxtools.pcap.core.tests/src/org/eclipse/linuxtools/pcap/core/tests/stream/StreamBuildTest.java +++ b/lttng/org.eclipse.linuxtools.pcap.core.tests/src/org/eclipse/linuxtools/pcap/core/tests/stream/StreamBuildTest.java @@ -13,13 +13,10 @@ package org.eclipse.linuxtools.pcap.core.tests.stream; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import java.io.IOException; -import java.util.Set; -import java.util.TreeSet; import org.eclipse.linuxtools.pcap.core.protocol.Protocol; import org.eclipse.linuxtools.pcap.core.stream.PacketStream; @@ -28,8 +25,6 @@ import org.eclipse.linuxtools.pcap.core.tests.shared.PcapTestTrace; import org.eclipse.linuxtools.pcap.core.trace.BadPcapFileException; import org.junit.Test; -import com.google.common.collect.ImmutableSet; - /** * JUnit Class that tests whether packet streams are built correctly. * @@ -37,27 +32,7 @@ import com.google.common.collect.ImmutableSet; */ public class StreamBuildTest { - // Values taken from wireshark - private static final Set TCP_INDEX_SET_STREAM_7_PACKETS = ImmutableSet.of( - // This stream contains 7 packets. - 17L, - 23L, - 25L, - 26L, - 27L, - 35L, - 36L - ); - - private static final Set TCP_INDEX_SET_STREAM_34_PACKETS = new TreeSet<>(); - static { - // This stream contains many packet (34). Some packets doesn't - // belong to it like the 17 or the 23. - for (Long i = new Long(0); i < 43; i++) { - TCP_INDEX_SET_STREAM_34_PACKETS.add(i); - } - TCP_INDEX_SET_STREAM_34_PACKETS.removeAll(TCP_INDEX_SET_STREAM_7_PACKETS); - } + private static final double DELTA = 0.001; /** * Test that verify that stream building is done correctly. @@ -75,13 +50,18 @@ public class StreamBuildTest { assertEquals(Protocol.ETHERNET_II, builder.getProtocol()); // Should do one loop only, so hardcoded values are okay. for (PacketStream stream : builder.getStreams()) { - assertTrue(stream.toString().contains("Stream eth.0, Number of Packets: 43")); - for (int i = 0; i < stream.size(); i++) { - Long id = stream.get(i).getIndex(); - String path = stream.get(i).getPath(); - assertTrue(id >= 0 && id < 43); - assertEquals(file, path); - } + assertEquals("Stream eth.0, Number of Packets: 43\n", stream.toString()); + assertEquals(43, stream.getNbPackets()); + assertEquals(25091, stream.getNbBytes()); + assertEquals(20, stream.getNbPacketsAtoB()); + assertEquals(2323, stream.getNbBytesAtoB()); + assertEquals(23, stream.getNbPacketsBtoA()); + assertEquals(22768, stream.getNbBytesBtoA()); + assertEquals(1084443427311224000L, stream.getStartTime()); + assertEquals(1084443457704928000L, stream.getStopTime()); + assertEquals(30.393704, stream.getDuration(), DELTA); + assertEquals(76.43030280218561, stream.getBPSAtoB(), DELTA); + assertEquals(749.1025114938278, stream.getBPSBtoA(), DELTA); } // Test TCP streams and other constructor @@ -97,13 +77,17 @@ public class StreamBuildTest { assertEquals(Protocol.TCP, stream.getProtocol()); assertEquals(0, stream.getID()); assertEquals("tcp.0", stream.getUniqueID()); - assertEquals(34, stream.size()); - for (int i = 0; i < stream.size(); i++) { - Long id = stream.get(i).getIndex(); - String path = stream.get(i).getPath(); - assertTrue(TCP_INDEX_SET_STREAM_34_PACKETS.contains(id)); - assertEquals(file, path); - } + assertEquals(34, stream.getNbPackets()); + assertEquals(20695, stream.getNbBytes()); + assertEquals(16, stream.getNbPacketsAtoB()); + assertEquals(1351, stream.getNbBytesAtoB()); + assertEquals(18, stream.getNbPacketsBtoA()); + assertEquals(19344, stream.getNbBytesBtoA()); + assertEquals(1084443427311224000L, stream.getStartTime()); + assertEquals(1084443457704928000L, stream.getStopTime()); + assertEquals(30.393704, stream.getDuration(), DELTA); + assertEquals(44.449995301658525, stream.getBPSAtoB(), DELTA); + assertEquals(636.4476011216008, stream.getBPSBtoA(), DELTA); stream = builder.getStream(1); if (stream == null) { @@ -113,13 +97,17 @@ public class StreamBuildTest { assertEquals(Protocol.TCP, stream.getProtocol()); assertEquals(1, stream.getID()); assertEquals("tcp.1", stream.getUniqueID()); - assertEquals(7, stream.size()); - for (int i = 0; i < stream.size(); i++) { - Long id = stream.get(i).getIndex(); - String path = stream.get(i).getPath(); - assertTrue(TCP_INDEX_SET_STREAM_7_PACKETS.contains(id)); - assertEquals(file, path); - } + assertEquals(7, stream.getNbPackets()); + assertEquals(4119, stream.getNbBytes()); + assertEquals(3, stream.getNbPacketsAtoB()); + assertEquals(883, stream.getNbBytesAtoB()); + assertEquals(4, stream.getNbPacketsBtoA()); + assertEquals(3236, stream.getNbBytesBtoA()); + assertEquals(1084443430295515000L, stream.getStartTime()); + assertEquals(1084443432088092000L, stream.getStopTime()); + assertEquals(1.792577, stream.getDuration(), DELTA); + assertEquals(492.58692932019096, stream.getBPSAtoB(), DELTA); + assertEquals(1805.2223140205413, stream.getBPSBtoA(), DELTA); builder.clear(); assertEquals(0, builder.getNbStreams()); diff --git a/lttng/org.eclipse.linuxtools.pcap.core/META-INF/MANIFEST.MF b/lttng/org.eclipse.linuxtools.pcap.core/META-INF/MANIFEST.MF index c28b84b9ae..dce6f70add 100644 --- a/lttng/org.eclipse.linuxtools.pcap.core/META-INF/MANIFEST.MF +++ b/lttng/org.eclipse.linuxtools.pcap.core/META-INF/MANIFEST.MF @@ -24,4 +24,5 @@ Export-Package: org.eclipse.linuxtools.internal.pcap.core;x-friends:="org.eclips org.eclipse.linuxtools.pcap.core.stream, org.eclipse.linuxtools.pcap.core.trace, org.eclipse.linuxtools.pcap.core.util -Import-Package: com.google.common.collect +Import-Package: com.google.common.collect, + com.google.common.math diff --git a/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/packet/PacketUniqueID.java b/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/packet/PacketUniqueID.java deleted file mode 100644 index 5ce9f4571b..0000000000 --- a/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/packet/PacketUniqueID.java +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Vincent Perot - Initial API and implementation - *******************************************************************************/ - -package org.eclipse.linuxtools.pcap.core.packet; - -import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.linuxtools.pcap.core.packet.Packet; -import org.eclipse.linuxtools.pcap.core.protocol.Protocol; -import org.eclipse.linuxtools.pcap.core.protocol.pcap.PcapPacket; - -/** - * Class that represents a Packet ID. Using the information contained in this - * class, it is possible to retrieve a packet. This allows to tremendously - * reduce memory usage of packet streams while keeping good performance. - * - * @author Vincent Perot - */ -public class PacketUniqueID { - - private final String fPath; - private final long fIndex; - - /** - * Constructor. It builds the packet ID from a packet. - * - * @param packet - * The packet to build the ID from. - */ - public PacketUniqueID(Packet packet) { - fPath = packet.getPcapFile().getPath(); - PcapPacket pcapPacket = (PcapPacket) packet.getPacket(Protocol.PCAP); - fIndex = (pcapPacket == null ? -1 : pcapPacket.getIndex()); - } - - /** - * Getter method that returns the file path of the packet. - * - * @return The file path. - */ - public String getPath() { - return fPath; - } - - /** - * Getter method that returns the index within the file of the packet. - * - * @return The packet index. - */ - public long getIndex() { - return fIndex; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (fIndex ^ (fIndex >>> 32)); - result = prime * result + fPath.hashCode(); - return result; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - - PacketUniqueID other = (PacketUniqueID) obj; - if (fIndex != other.fIndex) { - return false; - } - if (fPath != other.fPath) { - return false; - } - return true; - } - -} diff --git a/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/stream/PacketStream.java b/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/stream/PacketStream.java index fb7c25174d..c6492ea38b 100644 --- a/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/stream/PacketStream.java +++ b/lttng/org.eclipse.linuxtools.pcap.core/src/org/eclipse/linuxtools/pcap/core/stream/PacketStream.java @@ -12,14 +12,14 @@ package org.eclipse.linuxtools.pcap.core.stream; -import java.util.ArrayList; -import java.util.List; - +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.linuxtools.pcap.core.endpoint.ProtocolEndpointPair; -import org.eclipse.linuxtools.pcap.core.packet.PacketUniqueID; +import org.eclipse.linuxtools.pcap.core.packet.Packet; import org.eclipse.linuxtools.pcap.core.protocol.Protocol; import org.eclipse.linuxtools.pcap.core.protocol.pcap.PcapPacket; +import com.google.common.math.DoubleMath; + // TODO decide if default modifier a good idea. This allows only the // stream builder to call that method (and any class that is added to this // package). This effectively makes the stream read-only. @@ -34,12 +34,19 @@ import org.eclipse.linuxtools.pcap.core.protocol.pcap.PcapPacket; */ public class PacketStream { - private static final String EMPTY_STRING = ""; //$NON-NLS-1$ - private final List fListIndex; + private static final double SECOND_TO_NANOSECOND = 1000000000.0; + private static final double DELTA = 0.000000001; private final Protocol fProtocol; private final int fId; private final ProtocolEndpointPair fEndpointPair; + private long fNbPacketsAtoB; + private long fNbPacketsBtoA; + private long fNbBytesAtoB; + private long fNbBytesBtoA; + private long fStartTime; + private long fEndTime; + /** * Constructor of a packet stream. * @@ -53,34 +60,57 @@ public class PacketStream { */ PacketStream(Protocol protocol, int id, ProtocolEndpointPair endpointPair) { fProtocol = protocol; - fListIndex = new ArrayList<>(); fId = id; fEndpointPair = endpointPair; + fNbPacketsAtoB = 0; + fNbPacketsBtoA = 0; + fNbBytesAtoB = 0; + fNbBytesBtoA = 0; + fStartTime = Long.MAX_VALUE; + fEndTime = Long.MIN_VALUE; } /** - * Add a packet unique ID to the stream. + * Add a packet to the stream. * * @param packet - * The packet unique ID that must be added. + * The packet that must be added. */ synchronized void add(PcapPacket packet) { - fListIndex.add(new PacketUniqueID(packet)); - } - /** - * Get a packet unique ID in file from the stream. - * - * @param index - * The index in the stream of the packet to be retrieved. - * @return The retrieved packet unique ID. - */ - public synchronized PacketUniqueID get(int index) { - PacketUniqueID id = fListIndex.get(index); - if (id == null) { - throw new IllegalStateException("PacketUniqueID is null!"); //$NON-NLS-1$ + Packet newPacket = packet.getPacket(fProtocol); + if (newPacket == null) { + return; + } + + // Update packet and byte number + if (fEndpointPair.getFirstEndpoint().equals(newPacket.getSourceEndpoint()) && + fEndpointPair.getSecondEndpoint().equals(newPacket.getDestinationEndpoint())) { + fNbPacketsAtoB++; + fNbBytesAtoB += packet.getOriginalLength(); + } else if (fEndpointPair.getFirstEndpoint().equals(newPacket.getDestinationEndpoint()) && + fEndpointPair.getSecondEndpoint().equals(newPacket.getSourceEndpoint())) { + fNbPacketsBtoA++; + fNbBytesBtoA += packet.getOriginalLength(); + } else { + throw new IllegalStateException(); } - return id; + + // Update start and stop time + // Stream timestamp is ALWAYS in nanoseconds. + long timestamp; + switch (packet.getTimestampScale()) { + case MICROSECOND: + timestamp = packet.getTimestamp() * 1000; + break; + case NANOSECOND: + timestamp = packet.getTimestamp(); + break; + default: + throw new IllegalArgumentException("The timestamp precision is not valid!"); //$NON-NLS-1$ + } + fStartTime = Math.min(fStartTime, timestamp); + fEndTime = Math.max(fEndTime, timestamp); } /** @@ -123,27 +153,117 @@ public class PacketStream { @Override public synchronized String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Stream " + getUniqueID() + ", Number of Packets: " + fListIndex.size() + "\n"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - - for (int i = 0; i < fListIndex.size(); i++) { - sb.append(fListIndex.get(i) + ", "); //$NON-NLS-1$ - } + sb.append("Stream " + getUniqueID() + ", Number of Packets: " + getNbPackets() + "\n"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - String string = sb.toString(); - if (string == null) { - return EMPTY_STRING; - } + @SuppressWarnings("null") + @NonNull String string = sb.toString(); return string; } /** - * Method that returns the number of packets in the stream. + * Get the number of packets going from the first endpoint to the second. + * + * @return The number of packets from A to B. + */ + public synchronized long getNbPacketsAtoB() { + return fNbPacketsAtoB; + } + + /** + * Get the number of packets going from the second endpoint to the first. + * + * @return The number of packets from B to A. + */ + public synchronized long getNbPacketsBtoA() { + return fNbPacketsBtoA; + } + + /** + * Get the total number of packets in this stream. + * + * @return The total number of packets. + */ + public synchronized long getNbPackets() { + return fNbPacketsAtoB + fNbPacketsBtoA; + } + + /** + * Get the number of bytes going from the first endpoint to the second. + * + * @return The number of bytes from A to B. + */ + public synchronized long getNbBytesAtoB() { + return fNbBytesAtoB; + } + + /** + * Get the number of bytes going from the second endpoint to the first. + * + * @return The number of bytes from B to A. + */ + public synchronized long getNbBytesBtoA() { + return fNbBytesBtoA; + } + + /** + * Get the total number of bytes in this stream. * - * @return The number of packets in the stream. + * @return The total number of bytes. */ - public synchronized int size() { - return fListIndex.size(); + public synchronized long getNbBytes() { + return fNbBytesAtoB + fNbBytesBtoA; + } + + /** + * Get the start time of this stream, in nanoseconds relative to epoch. + * + * @return The start time. + */ + public synchronized long getStartTime() { + return fStartTime; + } + + /** + * Get the stop time of this stream, in nanoseconds relative to epoch. + * + * @return The stop time. + */ + public synchronized long getStopTime() { + return fEndTime; + } + + /** + * Get the duration of this stream, in seconds + * + * @return The duration of this stream. + */ + public synchronized double getDuration() { + return (fEndTime - fStartTime) / SECOND_TO_NANOSECOND; + } + + /** + * Get the the average byte per second from A to B. + * + * @return the average byte per second from A to B. + */ + public synchronized double getBPSAtoB() { + if (DoubleMath.fuzzyEquals(getDuration(), 0, DELTA)) { + return 0; + } + return fNbBytesAtoB / getDuration(); + } + + /** + * Get the the average byte per second from B to A. + * + * @return the average byte per second from B to A. + */ + public synchronized double getBPSBtoA() { + if (DoubleMath.fuzzyEquals(getDuration(), 0, DELTA)) { + return 0; + } + return fNbBytesBtoA / getDuration(); } } -- cgit v1.2.3