CIRCT 24.0.0git
Loading...
Searching...
No Matches
test_esitester.py
Go to the documentation of this file.
1# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2# See https://llvm.org/LICENSE.txt for license information.
3# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5from __future__ import annotations
6
7import subprocess
8
9import esiaccel
10from esiaccel.accelerator import AcceleratorConnection
11from esiaccel.cosim.pytest import cosim_test
12import esiaccel.types as types
13import pytest
14
15from .conftest import HW_DIR, check_lines, require_tool, run_cmd
16
17
18@cosim_test(HW_DIR / "esitester.py", args=("{tmp_dir}", "cosim"))
20
21 def setup_method(self) -> None:
22 require_tool("esitester")
23 require_tool("esiquery")
24
25 def test_callback(self, host: str, port: int) -> None:
26 conn = f"{host}:{port}"
27 stdout = run_cmd(["esitester", "-v", "cosim", conn, "callback", "-i", "5"])
28 check_lines(stdout, [
29 "[CONNECT] connecting to backend",
30 ])
31 # The callback loop should print values 0 through 4.
32 for i in range(5):
33 assert f"callback: {i}" in stdout, \
34 f"Expected 'callback: {i}' in stdout"
35
36 def test_streaming_add(self, host: str, port: int) -> None:
37 conn = f"{host}:{port}"
38 stdout = run_cmd(["esitester", "cosim", conn, "streaming_add"])
39 check_lines(stdout, [
40 "Streaming add test results:",
41 "input[0]=222709 + 5 = 222714 (expected 222714)",
42 "input[1]=894611 + 5 = 894616 (expected 894616)",
43 "input[2]=772894 + 5 = 772899 (expected 772899)",
44 "input[3]=429150 + 5 = 429155 (expected 429155)",
45 "input[4]=629806 + 5 = 629811 (expected 629811)",
46 "Streaming add test passed",
47 ])
48
49 def test_streaming_add_quiet(self, host: str, port: int) -> None:
50 conn = f"{host}:{port}"
51 stdout = run_cmd(["esitester", "cosim", conn, "streaming_add", "-t"])
52 check_lines(stdout, [
53 "Streaming add test results:",
54 "Streaming add test passed",
55 ])
56
57 def test_translate_coords(self, host: str, port: int) -> None:
58 conn = f"{host}:{port}"
59 stdout = run_cmd(["esitester", "cosim", conn, "translate_coords"])
60 check_lines(stdout, [
61 "Coord translate test results:",
62 "coord[0]=(222709,894611) + (10,20) = (222719,894631)",
63 "coord[1]=(772894,429150) + (10,20) = (772904,429170)",
64 "coord[2]=(629806,138727) + (10,20) = (629816,138747)",
65 "coord[3]=(218516,390276) + (10,20) = (218526,390296)",
66 "coord[4]=(750021,423525) + (10,20) = (750031,423545)",
67 "Coord translate test passed",
68 ])
69
70 def test_serial_coords(self, host: str, port: int) -> None:
71 conn = f"{host}:{port}"
72 stdout = run_cmd(
73 ["esitester", "cosim", conn, "serial_coords", "-n", "40", "-b", "33"])
74 check_lines(stdout, [
75 "Serial coord translate test results:",
76 "coord[0]=",
77 "Serial coord translate test passed",
78 ])
79
80 def test_auto_serial_coords(self, host: str, port: int) -> None:
81 conn = f"{host}:{port}"
82 stdout = run_cmd(
83 ["esitester", "cosim", conn, "auto_serial_coords", "-n", "5"])
84 check_lines(stdout, [
85 "Auto serial coord translate test results:",
86 "coord[0]=",
87 "Auto serial coord translate test passed",
88 ])
89
90 def test_channel(self, host: str, port: int) -> None:
91 conn = f"{host}:{port}"
92 stdout = run_cmd(["esitester", "cosim", conn, "channel", "-i", "3"])
93 check_lines(stdout, [
94 "[channel] producer i=0 got=0",
95 "[channel] producer i=1 got=1",
96 "[channel] producer i=2 got=2",
97 "[channel] loopback i=0",
98 "[channel] loopback i=1",
99 "[channel] loopback i=2",
100 "Channel test passed",
101 ])
102
103 def test_telemetry(self, host: str, port: int) -> None:
104 conn = f"{host}:{port}"
105 result = subprocess.run(
106 ["esiquery", "cosim", conn, "telemetry"],
107 check=False,
108 capture_output=True,
109 text=True,
110 )
111 assert result.returncode == 0, result.stdout + result.stderr
112 stdout = result.stdout
113 check_lines(stdout, [
114 "* Telemetry",
115 "fromhostdma[32].fromHostChecksum: 0",
116 "fromhostdma[32].fromHostCycles: 0",
117 "readmem[32].addrCmdIssued: 0",
118 "readmem[32].addrCmdResponses: 0",
119 "readmem[32].lastReadLSB: 0",
120 "readmem[32].readChecksum: 0",
121 "tohostdma[32].toHostCycles: 0",
122 "tohostdma[32].totalWrites: 0",
123 "writemem[32].addrCmdIssued: 0",
124 "writemem[32].addrCmdResponses: 0",
125 "readmem[32].addrCmdResp.cycles: 0",
126 "writemem[32].addrCmdResp.cycles: 0",
127 ])
128
129 def test_reset(self, host: str, port: int) -> None:
130 conn = f"{host}:{port}"
131 stdout = run_cmd(["esitester", "cosim", conn, "reset"])
132 check_lines(stdout, [
133 "[reset] reset requested",
134 "[reset] telemetry addrCmdResponses after reset = 0",
135 "Reset test passed",
136 ])
137
138 def test_channel_python(self, conn: AcceleratorConnection) -> None:
139 """Test ChannelService ToHost and FromHost ports from Python."""
140 acc = conn.build_accelerator()
141 channel_test = acc.children[esiaccel.AppID("channel_test")]
142 ports = channel_test.ports
143
144 # Get the MMIO port and trigger the producer to send 5 values.
145 mmio = ports[esiaccel.AppID("cmd")]
146 assert isinstance(mmio, types.MMIORegion), \
147 f"Expected MMIORegion, got {type(mmio)}"
148
149 producer = ports[esiaccel.AppID("producer")]
150 assert isinstance(producer, types.ToHostPort), \
151 f"Expected ToHostPort, got {type(producer)}"
152 producer.connect()
153
154 num_values = 5
155 mmio.write(0x0, num_values)
156 for i in range(num_values):
157 result = producer.read().result()
158 assert result == i, f"Producer: expected {i}, got {result}"
159
160 # Test from_host -> to_host loopback.
161 loopback_in = ports[esiaccel.AppID("loopback_in")]
162 assert isinstance(loopback_in, types.FromHostPort), \
163 f"Expected FromHostPort, got {type(loopback_in)}"
164 loopback_in.connect()
165
166 loopback_out = ports[esiaccel.AppID("loopback_out")]
167 assert isinstance(loopback_out, types.ToHostPort), \
168 f"Expected ToHostPort, got {type(loopback_out)}"
169 loopback_out.connect()
170
171 for i in range(5):
172 loopback_in.write(42 + i)
173 result = loopback_out.read().result()
174 assert result == 42 + i, \
175 f"Loopback: expected {42 + i}, got {result}"
176
177
178@cosim_test(HW_DIR / "esitester.py", args=("{tmp_dir}", "cosim_dma"))
180
181 def setup_method(self) -> None:
182 require_tool("esitester")
183 require_tool("esiquery")
184
185 def test_hostmem(self, host: str, port: int) -> None:
186 conn = f"{host}:{port}"
187 run_cmd(["esitester", "cosim", conn, "hostmem"])
188
189 def test_dma(self, host: str, port: int) -> None:
190 conn = f"{host}:{port}"
191 result = subprocess.run(
192 ["esitester", "cosim", conn, "dma", "-w", "-r"],
193 check=False,
194 capture_output=True,
195 text=True,
196 )
197 assert result.returncode == 0, result.stdout + result.stderr
198
199 def test_bandwidth_data_integrity(self, host: str, port: int) -> None:
200 """Verify complete engine payloads in both transfer directions."""
201 conn = f"{host}:{port}"
202 result = subprocess.run(
203 [
204 "esitester",
205 "cosim",
206 conn,
207 "bandwidth",
208 "-w",
209 "-r",
210 "--check-data",
211 "--widths",
212 "24",
213 "64",
214 "534",
215 "--count",
216 "24",
217 ],
218 check=False,
219 capture_output=True,
220 text=True,
221 )
222 assert result.returncode == 0, result.stdout + result.stderr
223
224 def test_hostmembw(self, host: str, port: int) -> None:
225 conn = f"{host}:{port}"
226 # Widths chosen to cover every element-vs-engine-word relationship the read
227 # gearbox must unpack from a contiguous, byte-packed layout: 24 (sub-word,
228 # does not divide the 64-bit engine word), 32 (sub-word divisor), 72
229 # (wider than the word, not a multiple -> straddles words), and 128 (a whole
230 # number of words). A 1000-element 24-bit read burst is 3000 bytes, which
231 # exceeds the PCIe maximum read request size and so exercises the
232 # read-request splitter. The -w/-r data-integrity checks verify each element
233 # landed at / was fetched from the right bytes.
234 result = subprocess.run(
235 [
236 "esitester",
237 "cosim",
238 conn,
239 "hostmembw",
240 "-w",
241 "-r",
242 "-c",
243 "1000",
244 ],
245 check=False,
246 capture_output=True,
247 text=True,
248 )
249 combined = result.stdout + result.stderr
250 assert result.returncode == 0, combined
251 assert "exceeds the PCIe maximum read request size" not in combined, \
252 combined
253
254 def test_aggbandwidth(self, host: str, port: int) -> None:
255 conn = f"{host}:{port}"
256 # Aggregate bandwidth across the width-512 readmem*/writemem* units
257 # (4 read + 4 write), exercising the multi-unit nested-AppID resolution
258 # (mmio[width]/cmd and addrCmdResp/cycles) of the burst modules.
259 result = subprocess.run(
260 [
261 "esitester", "cosim", conn, "aggbandwidth", "--width", "512", "-r",
262 "-w", "-c", "64"
263 ],
264 check=False,
265 capture_output=True,
266 text=True,
267 )
268 assert result.returncode == 0, result.stdout + result.stderr
269
270 def test_telemetry(self, host: str, port: int) -> None:
271 conn = f"{host}:{port}"
272 result = subprocess.run(
273 ["esiquery", "cosim", conn, "telemetry"],
274 check=False,
275 capture_output=True,
276 text=True,
277 )
278 assert result.returncode == 0, result.stdout + result.stderr
279 stdout = result.stdout
280 check_lines(stdout, [
281 "* Telemetry",
282 "fromhostdma[32].fromHostChecksum: 0",
283 "fromhostdma[32].fromHostCycles: 0",
284 "tohostdma[32].toHostCycles: 0",
285 ])
286
287 def test_channel(self, host: str, port: int) -> None:
288 conn = f"{host}:{port}"
289 stdout = run_cmd(["esitester", "cosim", conn, "channel", "-i", "3"])
290 check_lines(stdout, [
291 "[channel] producer i=0 got=0",
292 "[channel] producer i=1 got=1",
293 "[channel] producer i=2 got=2",
294 "[channel] loopback i=0",
295 "[channel] loopback i=1",
296 "[channel] loopback i=2",
297 "Channel test passed",
298 ])
299
300 def test_serial_coords(self, host: str, port: int) -> None:
301 conn = f"{host}:{port}"
302 stdout = run_cmd(
303 ["esitester", "cosim", conn, "serial_coords", "-n", "40", "-b", "33"])
304 check_lines(stdout, [
305 "Serial coord translate test results:",
306 "coord[0]=",
307 "Serial coord translate test passed",
308 ])
None test_bandwidth_data_integrity(self, str host, int port)
None test_channel_python(self, AcceleratorConnection conn)
None test_streaming_add_quiet(self, str host, int port)
None test_translate_coords(self, str host, int port)
None test_streaming_add(self, str host, int port)
None test_serial_coords(self, str host, int port)
None test_auto_serial_coords(self, str host, int port)