Merge ~djacobs98/checkbox-iiotg/+git/checkbox-provider-intliotg:cyclictest into ~checkbox-dev/checkbox-iiotg/+git/checkbox-provider-intliotg:master

Proposed by Doug Jacobs
Status: Rejected
Rejected by: Vic Liu
Proposed branch: ~djacobs98/checkbox-iiotg/+git/checkbox-provider-intliotg:cyclictest
Merge into: ~checkbox-dev/checkbox-iiotg/+git/checkbox-provider-intliotg:master
Diff against target: 211 lines (+172/-0)
5 files modified
bin/run_cyclictest.py (+141/-0)
units/cyclictest/category.pxu (+3/-0)
units/cyclictest/jobs.pxu (+26/-0)
units/test-plan-desktop.pxu (+1/-0)
units/test-plan-server.pxu (+1/-0)
Reviewer Review Type Date Requested Status
PeiYao Chang Needs Fixing
Vic Liu Pending
Review via email: mp+440716@code.launchpad.net

Commit message

Initial commit.
Add cyclictest script and test case to stress test test plan for desktop and server.

To post a comment you must log in.
Revision history for this message
PeiYao Chang (baconyao) wrote :

Doug, there are few things need you to fix, I list them below.

1. The style of Checkbox job
  - Always have the test-plan.pxu and well structure for each units.
  - Problem:
    - Missing the test-plan.pxu in cyclictest unit
    - Do not include the job into the intliotg-desktop-22-04-stress and intliotg-server-22-04-stress, you can reference the ishtp sample (https://git.launchpad.net/~checkbox-dev/checkbox-iiotg/+git/checkbox-provider-intliotg/tree/units/ishtp/test-plan.pxu)

2. There are some errors thrown by flake8
  - After setting up the dev environment of Checkbox, run flake8 to check python scripts
    - Checkbox dev environment: https://github.com/canonical/checkbox/blob/main/CONTRIBUTING.md
    - flake8 command: `python -m flake8 bin/run_cyclictest.py`
  - Errors
    ```
    bin/run_cyclictest.py:10:80: E501 line too long (80 > 79 characters)
    bin/run_cyclictest.py:24:1: F401 'sys' imported but unused
    bin/run_cyclictest.py:31:1: E302 expected 2 blank lines, found 1
    bin/run_cyclictest.py:31:32: W291 trailing whitespace
    bin/run_cyclictest.py:33:80: E501 line too long (91 > 79 characters)
    bin/run_cyclictest.py:34:5: F841 local variable 'test_timeout' is assigned to but never used
    bin/run_cyclictest.py:37:80: E501 line too long (183 > 79 characters)
    bin/run_cyclictest.py:50:11: E275 missing whitespace after keyword
    bin/run_cyclictest.py:57:1: E302 expected 2 blank lines, found 1
    bin/run_cyclictest.py:59:1: E115 expected an indented block (comment)
    bin/run_cyclictest.py:60:1: E115 expected an indented block (comment)
    bin/run_cyclictest.py:68:11: E275 missing whitespace after keyword
    bin/run_cyclictest.py:83:1: E302 expected 2 blank lines, found 1
    bin/run_cyclictest.py:96:22: E701 multiple statements on one line (colon)
    bin/run_cyclictest.py:103:80: E501 line too long (130 > 79 characters)
    bin/run_cyclictest.py:113:80: E501 line too long (93 > 79 characters)
    bin/run_cyclictest.py:120:11: E275 missing whitespace after keyword
    bin/run_cyclictest.py:131:63: E261 at least two spaces before inline comment
    ```

review: Needs Fixing
Revision history for this message
Doug Jacobs (djacobs98) wrote :

Sample output from a 1 second run:
https://pastebin.canonical.com/p/4fPRnbbFSQ/

Revision history for this message
Doug Jacobs (djacobs98) wrote :

Sample output of 1 second test from Checkbox take 2:
https://pastebin.canonical.com/p/KrG9qv55VJ/

Unmerged commits

cc3c353... by Doug Jacobs

Initial commit. Add cyclictest to stress tests for Desktop & Server.
The test is run as a python script in bin/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/run_cyclictest.py b/bin/run_cyclictest.py
2new file mode 100755
3index 0000000..9a6c1a3
4--- /dev/null
5+++ b/bin/run_cyclictest.py
6@@ -0,0 +1,141 @@
7+#!/usr/bin/env python3
8+# Copyright Canonical 2023
9+# run_cyclictest.py
10+#
11+# Uses the cylictest binary to run cyclictest and measure process latency.
12+# This test needs to run for at least 24 hours in order to provide useful data.
13+#
14+# The output from the test, as well as any errors, are then dumped into a file
15+# so the second part can check the results. A passing test will depend on the
16+# maximum latency observed and whether that is an acceptable number. This value
17+# depends on the DUT's platform and CPU. These values are provided by Intel as
18+# part of the Real Time Key Performance Indicator (RT KPI) document.
19+#
20+# Pass conditions:
21+# * Max latency is equal to or lower than the expected value for the DUT's HW
22+# * 0 overflows (caused by a process waiting too long. also called a "miss")
23+#
24+# Fail conditions:
25+# * Any errors from the test.
26+# * Unacceptable values for Max Latency or Overflows.
27+
28+import argparse
29+import subprocess
30+import sys
31+import os
32+
33+# This function runs the cyclictest command, and captures output and also
34+# stores the output in a file for processing.
35+# filename - the path and filename of the output file.
36+# duration - the desired duration of the test in seconds.
37+def run_it(filename, duration):
38+
39+ # timeout must be larger than the test duration, otherwise the test will be interrupted
40+ test_timeout = duration + 1
41+
42+ result = subprocess.run(
43+ ["sudo", "chrt", "-f", "99", "cyclictest", "-a2-3", "-t2", "-m", "-p99", "-i250", "-h700", "-q", "-D", str(duration)], capture_output=True, text=True, timeout=(duration+1)
44+ )
45+
46+ print("stdout:", result.stdout)
47+ print("stderr:", result.stderr)
48+
49+ with open(filename, 'w') as f:
50+ f.write(result.stdout)
51+ f.write(result.stderr)
52+
53+ # Note: A returncode of 0 simply means the command executed successfully.
54+ # It does NOT mean the test passed (or failed.)
55+ # That will be determined by a separate function.
56+ return(result.returncode)
57+
58+# The expected maximum latency is based on the HW platform and CPU.
59+# For instance, ADL-S with an i7-12700 has an expected maximum latency of 11ms
60+#
61+# However, some hardware may not proper identification yet, in which case just
62+# return the largest latency listed in the document.
63+def lookup_max_latency():
64+
65+# In case we cannot determine the HW or the CPU of the DUT, use the largest
66+# value from the table of expected maximum latency.
67+ MAX_ALLOWED_LATENCY = 17
68+
69+# TODO: Implement the methods to determine the platform and CPU, and use that
70+# to lookup the expected maximum latency.
71+#
72+# For now, just return MAX_ALLOWED_LATENCY
73+
74+ return(MAX_ALLOWED_LATENCY)
75+
76+# This function takes a filename containing the output from a run of cyclictest
77+# and verifies two things:
78+# 1. The maximum latency from each thread did not exceed the maximum latency
79+# specified by Intel for the DUT's HW Platform and CPU.
80+#
81+# 2. The number of overflows (scheduling misses) was 0 for each thread.
82+#
83+# Sample output for these lines looks like:
84+# # Max Latencies: 00041 00046
85+# # Histogram Overflows: 00000 00000
86+# The values after these strings are the results from each thread.
87+#
88+# All other lines are ignored.
89+def verify_cyclictest_results(cyclictest_file):
90+ max_latency = lookup_max_latency()
91+ print("Maximum latency allowed: " + str(max_latency))
92+ latencies = []
93+ overflows = []
94+ strings = []
95+
96+ return_code = 0
97+
98+ f = open(cyclictest_file, "r")
99+
100+ for line in f:
101+ line = line.strip()
102+ if line == "": continue
103+
104+ strings = line.split(":")
105+ if strings[0] == "# Max Latencies":
106+ latencies = strings[1].split()
107+ for latency in latencies:
108+ if int(latency) > max_latency:
109+ print("Latency : " + latency + " -- Maximum Latency value of: " + str(max_latency) + " exceeded. Test fails.")
110+ return_code = 1
111+ else:
112+ print("Latency : " + latency + " -- OK.")
113+ continue
114+
115+ if strings[0] == "# Histogram Overflows":
116+ overflows = strings[1].split()
117+ for overflow in overflows:
118+ if int(overflow) > 0:
119+ print("Overflow: " + overflow + " -- 0 Overflows expected. Test fails.")
120+ return_code = 1
121+ else:
122+ print("Overflow: " + overflow + " -- OK.")
123+ continue
124+
125+ f.close()
126+ return(return_code)
127+
128+
129+if __name__ == "__main__":
130+ PLAINBOX_SESSION_SHARE = os.environ.get('PLAINBOX_SESSION_SHARE', '')
131+ return_code = 0
132+
133+ # path inside Checkbox for files, plus the default filename
134+ filename = PLAINBOX_SESSION_SHARE + "cyclictest.log"
135+
136+ parser = argparse.ArgumentParser()
137+ parser.add_argument("--duration", type=int, default=86400) # default = 24h
138+ args = parser.parse_args()
139+
140+ return_code = run_it(filename, args.duration)
141+ if return_code != 0:
142+ print("Error occurred during execution - aborting")
143+ exit(return_code)
144+
145+ return_code = verify_cyclictest_results(filename)
146+
147+ exit(return_code)
148diff --git a/units/cyclictest/category.pxu b/units/cyclictest/category.pxu
149new file mode 100644
150index 0000000..41c847c
151--- /dev/null
152+++ b/units/cyclictest/category.pxu
153@@ -0,0 +1,3 @@
154+unit: category
155+id: cyclictest-latency-performance-test
156+_name: Cyclictest Latency Performance Test
157diff --git a/units/cyclictest/jobs.pxu b/units/cyclictest/jobs.pxu
158new file mode 100644
159index 0000000..a352fba
160--- /dev/null
161+++ b/units/cyclictest/jobs.pxu
162@@ -0,0 +1,26 @@
163+# test based on Intel's document "Real-Time Key Performance Indicators (KPIs)
164+# Latest version: https://drive.google.com/drive/u/0/folders/1oP5YaynNkB1TEUp8hz0iPPfswZK3N5_O
165+#
166+# Add to stress tests (for now)
167+
168+# Test case: cyclictest_24h_rt_latency
169+# Purpose: Test scheduling latency by running the cyclictest tool for 24 hours.
170+# Test described in Intel's document on Real-Time Key Performance Indicators.
171+#
172+# The expected Maximum Latency will vary based on the Platform and CPU that the
173+# test is run on. However for now, just use the largest value of 17 microseconds.
174+#
175+# This test will pass if:
176+# * The maximum latency is 17 microseconds or lower.
177+# * There are no overflows.
178+#
179+# Otherwise the test will fails.
180+
181+id: stress/cyclictest_24h_rt_latency
182+category_id: com.canonical.plainbox::stress
183+_summary:
184+ Run cyclictest for 24 hours to test the scheduling latency for RT kernel.
185+plugin: shell
186+user: root
187+command:
188+ run_cyclictest.py
189diff --git a/units/test-plan-desktop.pxu b/units/test-plan-desktop.pxu
190index 23c0390..877d87a 100644
191--- a/units/test-plan-desktop.pxu
192+++ b/units/test-plan-desktop.pxu
193@@ -135,6 +135,7 @@ include:
194 nested_part:
195 com.canonical.certification::stress-iperf3-automated # keep if ethernet is supported
196 com.canonical.certification::client-cert-iot-server-22-04-stress
197+ com.canonical.certification::stress/cyclictest_24h_rt_latency
198 exclude:
199 com.canonical.certification::stress-tests/hibernate.*
200
201diff --git a/units/test-plan-server.pxu b/units/test-plan-server.pxu
202index d8c0f95..708b0d7 100644
203--- a/units/test-plan-server.pxu
204+++ b/units/test-plan-server.pxu
205@@ -124,6 +124,7 @@ include:
206 nested_part:
207 com.canonical.certification::stress-iperf3-automated # keep if ethernet is supported
208 com.canonical.certification::client-cert-iot-server-22-04-stress
209+ com.canonical.certification::stress/cyclictest_24h_rt_latency
210 exclude:
211 com.canonical.certification::stress-tests/hibernate.*
212

Subscribers

People subscribed via source and target branches