Skip to content

Commit c290aca

Browse files
author
Darius
authored
[SDFAB-488] Use PyPy interpreter to analyze INT report PCAP to decrease runtime test completion (#378)
* Implement PyPy compiler for `int_traffic_trace` to decrease runtime test completion * Install PyPy and `ptf` PyPy module in Dockerfile * Add temporary comments in relevant files for debugging Python interpreter (CPython or PyPy) * Enable PyPy for parsing linerate PTF pcap file results * Test time improved in `int_traffic_trace` tests from ~28 minutes each to ~10 minutes each * Clean int_single_flow to match current linerate tests, added simple result verification * Changed Dockerfile to install PyPy * Clean `xnt.py` * Add copyright and licensing information * Address comments * Remove test.py and run code in python command * Save dictionary in command to pickle, and depickle in function * Address comments * Remove obsolete Dockerfile dependencies * Move new pcap function to `xnt.py` * Update analyze pcap functions in test files * Add more verification to `int_single_flow.py` * Remove reduntant code from `pypy_analyze_int_report_pcap` * Add FIXME to `int_single_flow` runtime INT report mismatch * Remove unused param PTF_VER from Dockerfile * Add comment explaining new Dockerfile packages
1 parent 9eb665e commit c290aca

File tree

4 files changed

+81
-20
lines changed

4 files changed

+81
-20
lines changed

ptf/Dockerfile

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ ARG P4RUNTIME_SHELL_VER
8383
ARG UNITTEST_XML_REPORTING_VER
8484

8585
ENV RUNTIME_DEPS \
86-
python3 \
87-
python3-pip \
88-
python3-setuptools \
86+
python3 \
87+
python3-pip \
88+
python3-setuptools \
8989
git
9090

9191
ENV PIP_DEPS \
@@ -132,7 +132,11 @@ ENV RUNTIME_DEPS \
132132
python3-dev \
133133
build-essential \
134134
python3-pip \
135-
netbase
135+
wget \
136+
netbase \
137+
# below packages are necessary dependencies for installing scipy in PyPy
138+
libatlas-base-dev \
139+
gfortran
136140

137141
RUN apt update && apt install -y $RUNTIME_DEPS
138142
RUN pip3 install --no-cache-dir scipy==1.5.4 numpy==1.19.4 matplotlib==3.3.3 pyyaml==5.4.1
@@ -144,6 +148,14 @@ COPY --from=proto-deps /output /usr/lib/python3.8/dist-packages
144148
COPY --from=ptf-deps /python_output /
145149
# Install custom scapy version from TRex
146150
RUN cd ${TREX_EXT_LIBS}/scapy-${SCAPY_VER}/ && python3 setup.py install
151+
# Build pypy from source for traffic trace tests
152+
RUN cd /opt/ && \
153+
wget -nv https://downloads.python.org/pypy/pypy3.7-v7.3.5-linux64.tar.bz2 && \
154+
tar xf pypy3.7-v7.3.5-linux64.tar.bz2 && \
155+
ln -s /opt/pypy3.7-v7.3.5-linux64/bin/pypy /usr/local/bin/pypy
156+
RUN pypy -m ensurepip && \
157+
pypy -mpip install -U pip wheel
158+
RUN pypy -mpip install --no-cache-dir six scipy==1.5.4 numpy==1.19.4 matplotlib==3.3.3 pyyaml==5.4.1 scapy==2.4.5
147159
RUN ldconfig
148160

149161
ENTRYPOINT []

ptf/tests/common/xnt.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import logging
77
import os
88
from os.path import abspath, exists, splitext
9+
from subprocess import Popen
10+
import pickle
911

1012
import matplotlib.pyplot as plt
1113
import numpy as np
@@ -347,6 +349,29 @@ def analyze_report_pcap(pcap_file: str, total_flows_from_trace: int = 0) -> dict
347349
return results
348350

349351

352+
def pypy_analyze_int_report_pcap(pcap_file: str, total_flows: int = 0) -> dict:
353+
code = "import pickle\n" \
354+
"from xnt import analyze_report_pcap\n"
355+
356+
if total_flows:
357+
code += f"result = analyze_report_pcap('{pcap_file}', {total_flows})\n"
358+
else:
359+
code += f"result = analyze_report_pcap('{pcap_file}')\n"
360+
361+
# pickle dictionary from analyze_report_pcap
362+
code += "with open('trace.pickle', 'wb') as handle:\n" \
363+
" pickle.dump(result, handle, protocol=pickle.HIGHEST_PROTOCOL)"
364+
365+
cmd = ["pypy", "-c", code]
366+
p = Popen(cmd)
367+
p.wait()
368+
369+
with open('trace.pickle', 'rb') as handle:
370+
result = pickle.load(handle)
371+
372+
return result
373+
374+
350375
def plot_histogram_and_cdf(report_plot_file, valid_report_irgs):
351376
if exists(report_plot_file):
352377
os.remove(report_plot_file)

ptf/tests/linerate/int_single_flow.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@
99
from trex_stl_lib.api import STLPktBuilder, STLStream, STLTXCont
1010
from trex_test import TRexTest
1111
from trex_utils import list_port_status
12-
from xnt import analyze_report_pcap
12+
from xnt import pypy_analyze_int_report_pcap
1313

1414
TRAFFIC_MULT = "40gbpsl1"
1515
TEST_DURATION = 10
16-
CAPTURE_LIMIT = 20
16+
CAPTURE_LIMIT = 30
1717

18-
SENDER_PORTS = [0]
19-
RECEIVER_PORTS = [1]
20-
INT_COLLECTOR_PORTS = [2]
18+
MIN_FLOW_REPORTS = 28
19+
20+
SENDER_PORT = 0
21+
RECEIVER_PORT = 1
22+
INT_COLLECTOR_PORT = 2
2123

2224

2325
@group("int")
@@ -50,28 +52,50 @@ def doRunTest(
5052

5153
# Define traffic to be sent
5254
stream = STLStream(packet=STLPktBuilder(pkt=pkt, vm=[]), mode=STLTXCont())
53-
self.trex_client.add_streams(stream, ports=SENDER_PORTS)
55+
self.trex_client.add_streams(stream, ports=[SENDER_PORT])
5456

5557
# Capture INT packets
56-
self.trex_client.set_service_mode(ports=INT_COLLECTOR_PORTS, enabled=True)
58+
self.trex_client.set_service_mode(ports=[INT_COLLECTOR_PORT], enabled=True)
5759
capture = self.trex_client.start_capture(
58-
rx_ports=INT_COLLECTOR_PORTS,
60+
rx_ports=[INT_COLLECTOR_PORT],
5961
limit=CAPTURE_LIMIT,
6062
bpf_filter="udp and dst port 32766",
6163
)
6264

6365
# Start sending stateless traffic
64-
self.trex_client.start(ports=SENDER_PORTS, mult=mult, duration=TEST_DURATION)
65-
self.trex_client.wait_on_traffic(ports=SENDER_PORTS)
66+
self.trex_client.start(ports=[SENDER_PORT], mult=mult, duration=TEST_DURATION)
67+
self.trex_client.wait_on_traffic(ports=[SENDER_PORT])
6668

6769
output = "/tmp/int-single-flow-{}.pcap".format(
6870
datetime.now().strftime("%Y%m%d-%H%M%S")
6971
)
7072
self.trex_client.stop_capture(capture["id"], output)
71-
analyze_report_pcap(output)
72-
list_port_status(self.trex_client.get_stats())
7373

74-
# TODO: parse data and verify results
74+
results = pypy_analyze_int_report_pcap(output)
75+
port_stats = self.trex_client.get_stats()
76+
77+
sent_packets = port_stats[SENDER_PORT]["opackets"]
78+
recv_packets = port_stats[RECEIVER_PORT]["ipackets"]
79+
80+
list_port_status(port_stats)
81+
82+
"""
83+
Verify the following:
84+
- Packet loss: No packets were dropped during the test
85+
- INT reports: 1 INT report per second per flow was generated
86+
"""
87+
self.failIf(
88+
sent_packets != recv_packets,
89+
f"Didn't receive all packets; sent {sent_packets}, received {recv_packets}",
90+
)
91+
92+
# FIXME: Although duration specified is 10, test in reality runs for 29-30 seconds, and
93+
# thus generates 28-29 INT flow reports
94+
local_reports = results["local_reports"]
95+
self.failIf(
96+
local_reports < MIN_FLOW_REPORTS,
97+
f"Flow reports generated for ~30 second test should be at least 28, was {local_reports}",
98+
)
7599

76100
def runTest(self):
77101
# TODO: iterate all possible parameters of test

ptf/tests/linerate/int_traffic_trace.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from ptf.testutils import group
99
from trex_test import TRexTest
1010
from trex_utils import list_port_status
11-
from xnt import analyze_report_pcap
11+
from xnt import pypy_analyze_int_report_pcap
1212

1313
TRAFFIC_SPEEDUP = 1.0
1414
TEST_DURATION = 60
@@ -77,7 +77,7 @@ def runTest(self):
7777
datetime.now().strftime("%Y%m%d-%H%M%S")
7878
)
7979
self.trex_client.stop_capture(capture["id"], output)
80-
results = analyze_report_pcap(output, TOTAL_FLOWS)
80+
results = pypy_analyze_int_report_pcap(output, TOTAL_FLOWS)
8181

8282
port_stats = self.trex_client.get_stats()
8383
sent_packets = port_stats[SENDER_PORT]["opackets"]
@@ -161,7 +161,7 @@ def runTest(self):
161161
datetime.now().strftime("%Y%m%d-%H%M%S")
162162
)
163163
self.trex_client.stop_capture(capture["id"], output)
164-
results = analyze_report_pcap(output, TOTAL_FLOWS)
164+
results = pypy_analyze_int_report_pcap(output, TOTAL_FLOWS)
165165

166166
port_stats = self.trex_client.get_stats()
167167
sent_packets = port_stats[SENDER_PORT]["opackets"]

0 commit comments

Comments
 (0)