49 const std::vector<uint32_t> &widths,
bool write,
53 const std::vector<uint32_t> &widths,
bool read,
56 const std::vector<uint32_t> &widths,
bool read,
bool write);
58 const std::vector<uint32_t> &widths,
59 uint32_t xferCount,
bool read,
bool write,
67 uint32_t xferCount,
bool read,
70 uint32_t addAmt, uint32_t numItems);
72 uint32_t addAmt, uint32_t numItems);
74 uint32_t xTrans, uint32_t yTrans,
77 uint32_t xTrans, uint32_t yTrans,
78 uint32_t numCoords,
size_t batchSizeLimit);
80 uint32_t xTrans, uint32_t yTrans,
101 const char *unit =
"B/s";
102 double value = bytesPerSec;
103 if (bytesPerSec >= 1e9) {
105 value = bytesPerSec / 1e9;
106 }
else if (bytesPerSec >= 1e6) {
108 value = bytesPerSec / 1e6;
109 }
else if (bytesPerSec >= 1e3) {
111 value = bytesPerSec / 1e3;
113 std::ostringstream oss;
114 oss.setf(std::ios::fixed);
116 oss << value <<
" " << unit;
122 const char *units[] = {
"B",
"KB",
"MB",
"GB",
"TB"};
123 double v = (double)bytes;
125 while (v >= 1024.0 && u < 4) {
129 std::ostringstream oss;
130 oss.setf(std::ios::fixed);
131 oss.precision(u == 0 ? 0 : 2);
132 oss << v <<
" " << units[u];
139 return std::to_string(us) +
" us";
140 double ms = us / 1000.0;
142 std::ostringstream oss;
143 oss.setf(std::ios::fixed);
144 oss.precision(ms < 10.0 ? 2 : (ms < 100.0 ? 1 : 0));
148 double sec = ms / 1000.0;
149 std::ostringstream oss;
150 oss.setf(std::ios::fixed);
151 oss.precision(sec < 10.0 ? 3 : 2);
160 void *ptr = _aligned_malloc(size, alignment);
162 throw std::bad_alloc();
165 void *ptr = std::aligned_alloc(alignment, size);
167 throw std::bad_alloc();
180int main(
int argc,
const char *argv[]) {
182 cli.description(
"Test an ESI system running the ESI tester image.");
183 cli.require_subcommand(1);
185 CLI::App *callback_test =
186 cli.add_subcommand(
"callback",
"initiate callback test");
187 uint32_t cb_iters = 1;
188 callback_test->add_option(
"-i,--iters", cb_iters,
189 "Number of iterations to run");
191 CLI::App *hostmemtestSub =
192 cli.add_subcommand(
"hostmem",
"Run the host memory test");
194 bool hmWrite =
false;
197 hostmemtestSub->add_flag(
"-w,--write", hmWrite,
198 "Enable host memory write test");
199 hostmemtestSub->add_flag(
"-r,--read", hmRead,
"Enable host memory read test");
200 hostmemtestSub->add_option(
201 "--widths", hostmemWidths,
204 CLI::App *dmatestSub = cli.add_subcommand(
"dma",
"Run the DMA test");
205 bool dmaRead =
false;
206 bool dmaWrite =
false;
208 dmatestSub->add_flag(
"-w,--write", dmaWrite,
"Enable dma write test");
209 dmatestSub->add_flag(
"-r,--read", dmaRead,
"Enable dma read test");
210 dmatestSub->add_option(
"--widths", dmaWidths,
214 CLI::App *bandwidthSub =
215 cli.add_subcommand(
"bandwidth",
"Run the bandwidth test");
216 uint32_t xferCount = 1000;
217 bandwidthSub->add_option(
"-c,--count", xferCount,
218 "Number of transfers to perform");
219 bool bandwidthRead =
false;
220 bool bandwidthWrite =
false;
221 bool bandwidthCheckData =
false;
224 bandwidthSub->add_option(
"--widths", bandwidthWidths,
225 "Width of the transfers to perform (default: " +
227 bandwidthSub->add_flag(
"-w,--write", bandwidthWrite,
228 "Enable bandwidth write");
229 bandwidthSub->add_flag(
"-r,--read", bandwidthRead,
"Enable bandwidth read");
230 bandwidthSub->add_flag(
"--check-data", bandwidthCheckData,
231 "Verify every transferred payload byte");
233 CLI::App *hostmembwSub =
234 cli.add_subcommand(
"hostmembw",
"Run the host memory bandwidth test");
235 uint32_t hmBwCount = 1000;
236 bool hmBwRead =
false;
237 bool hmBwWrite =
false;
239 hostmembwSub->add_option(
"-c,--count", hmBwCount,
240 "Number of hostmem transfers");
241 hostmembwSub->add_option(
242 "--widths", hmBwWidths,
244 hostmembwSub->add_flag(
"-w,--write", hmBwWrite,
245 "Measure hostmem write bandwidth");
246 hostmembwSub->add_flag(
"-r,--read", hmBwRead,
247 "Measure hostmem read bandwidth");
249 CLI::App *loopbackSub =
250 cli.add_subcommand(
"loopback",
"Test LoopbackInOutAdd function service");
251 uint32_t loopbackIters = 10;
252 bool loopbackPipeline =
false;
253 loopbackSub->add_option(
"-i,--iters", loopbackIters,
254 "Number of function invocations (default 10)");
255 loopbackSub->add_flag(
"-p,--pipeline", loopbackPipeline,
256 "Pipeline all calls then collect results");
258 CLI::App *aggBwSub = cli.add_subcommand(
260 "Aggregate hostmem bandwidth across four units (readmem*, writemem*)");
261 uint32_t aggWidth = 512;
262 uint32_t aggCount = 1000;
263 bool aggRead =
false;
264 bool aggWrite =
false;
265 aggBwSub->add_option(
267 "Bit width (default 512; other widths ignored if absent)");
268 aggBwSub->add_option(
"-c,--count", aggCount,
"Flits per unit (default 1000)");
269 aggBwSub->add_flag(
"-r,--read", aggRead,
"Include read units");
270 aggBwSub->add_flag(
"-w,--write", aggWrite,
"Include write units");
272 CLI::App *streamingAddSub = cli.add_subcommand(
273 "streaming_add",
"Test StreamingAdder function service with list input");
274 uint32_t streamingAddAmt = 5;
275 uint32_t streamingNumItems = 5;
276 bool streamingTranslate =
false;
277 streamingAddSub->add_option(
"-a,--add", streamingAddAmt,
278 "Amount to add to each element (default 5)");
279 streamingAddSub->add_option(
"-n,--num-items", streamingNumItems,
280 "Number of random items in the list (default 5)");
281 streamingAddSub->add_flag(
"-t,--translate", streamingTranslate,
282 "Use message translation (list translation)");
284 CLI::App *coordTranslateSub = cli.add_subcommand(
286 "Test CoordTranslator function service with list of coordinates");
287 uint32_t coordXTrans = 10;
288 uint32_t coordYTrans = 20;
289 uint32_t coordNumItems = 5;
290 coordTranslateSub->add_option(
"-x,--x-translation", coordXTrans,
291 "X translation amount (default 10)");
292 coordTranslateSub->add_option(
"-y,--y-translation", coordYTrans,
293 "Y translation amount (default 20)");
294 coordTranslateSub->add_option(
"-n,--num-coords", coordNumItems,
295 "Number of random coordinates (default 5)");
297 CLI::App *serialCoordTranslateSub = cli.add_subcommand(
299 "Test SerialCoordTranslator function service with list of coordinates");
300 uint32_t serialBatchSize = 240;
301 serialCoordTranslateSub->add_option(
"-x,--x-translation", coordXTrans,
302 "X translation amount (default 10)");
303 serialCoordTranslateSub->add_option(
"-y,--y-translation", coordYTrans,
304 "Y translation amount (default 20)");
305 serialCoordTranslateSub->add_option(
306 "-n,--num-coords", coordNumItems,
307 "Number of random coordinates (default 5)");
308 serialCoordTranslateSub
309 ->add_option(
"-b,--batch-size", serialBatchSize,
310 "Coordinates per header (default 240, max 65535)")
311 ->check(CLI::Range(1u, 0xFFFFu));
313 CLI::App *autoSerialCoordTranslateSub = cli.add_subcommand(
314 "auto_serial_coords",
315 "Test AutoSerialCoordTranslator (uses ListWindowToParallel/Serial "
316 "converters under the hood)");
317 uint32_t autoCoordXTrans = 10;
318 uint32_t autoCoordYTrans = 20;
319 uint32_t autoCoordNumItems = 5;
320 autoSerialCoordTranslateSub->add_option(
"-x,--x-translation", autoCoordXTrans,
321 "X translation amount (default 10)");
322 autoSerialCoordTranslateSub->add_option(
"-y,--y-translation", autoCoordYTrans,
323 "Y translation amount (default 20)");
324 autoSerialCoordTranslateSub->add_option(
325 "-n,--num-coords", autoCoordNumItems,
326 "Number of random coordinates (default 5)");
328 CLI::App *channelTestSub = cli.add_subcommand(
329 "channel",
"Test ChannelService to_host and from_host");
330 uint32_t channelIters = 10;
331 channelTestSub->add_option(
"-i,--iters", channelIters,
332 "Number of loopback iterations (default 10)");
334 CLI::App *resetSub = cli.add_subcommand(
335 "reset",
"Test the design reset feature (telemetry clears after reset)");
337 if (
int rc = cli.
esiParse(argc, argv))
339 if (!cli.get_help_ptr()->empty())
346 ctxt.
getLogger().
info(
"esitester",
"Connected to accelerator.");
347 Manifest manifest(ctxt, info.getJsonManifest());
350 acc->getServiceThread()->addPoll(*accel);
352 if (*callback_test) {
354 }
else if (*hostmemtestSub) {
355 hostmemTest(acc, accel, hostmemWidths, hmWrite, hmRead);
356 }
else if (*loopbackSub) {
358 }
else if (*dmatestSub) {
359 dmaTest(acc, accel, dmaWidths, dmaRead, dmaWrite);
360 }
else if (*bandwidthSub) {
361 bandwidthTest(acc, accel, bandwidthWidths, xferCount, bandwidthRead,
362 bandwidthWrite, bandwidthCheckData);
363 }
else if (*hostmembwSub) {
366 }
else if (*aggBwSub) {
369 }
else if (*streamingAddSub) {
370 if (streamingTranslate)
375 }
else if (*coordTranslateSub) {
377 }
else if (*serialCoordTranslateSub) {
379 coordNumItems, serialBatchSize);
380 }
else if (*autoSerialCoordTranslateSub) {
383 }
else if (*channelTestSub) {
385 }
else if (*resetSub) {
390 }
catch (std::exception &e) {
395 std::cout <<
"Exiting successfully\n";
400 uint32_t iterations) {
403 throw std::runtime_error(
"No cb_test child found in accelerator");
404 auto &ports = cb_test->second->getPorts();
405 auto cmd_port = ports.find(
AppID(
"cmd"));
406 if (cmd_port == ports.end())
407 throw std::runtime_error(
"No cmd port found in cb_test child");
410 throw std::runtime_error(
"cb_test cmd port is not MMIO");
412 auto f = ports.find(
AppID(
"cb"));
413 if (f == ports.end())
414 throw std::runtime_error(
"No cb port found in accelerator");
418 throw std::runtime_error(
"cb port is not a CallService::Callback");
420 std::atomic<uint32_t> callbackCount = 0;
423 conn->getLogger().debug(
424 [&](std::string &subsystem, std::string &msg,
425 std::unique_ptr<std::map<std::string, std::any>> &details) {
426 subsystem =
"ESITESTER";
427 msg =
"Received callback";
428 details = std::make_unique<std::map<std::string, std::any>>();
429 details->emplace(
"data", data);
431 std::cout <<
"callback: " << *data.as<uint64_t>() << std::endl;
432 callbackCount.fetch_add(1);
437 for (uint32_t i = 0; i < iterations; ++i) {
438 conn->getLogger().info(
"esitester",
"Issuing callback command iteration " +
439 std::to_string(i) +
"/" +
440 std::to_string(iterations));
441 cmdMMIO->write(0x10, i);
443 for (uint32_t wait = 0; wait < 1000; ++wait) {
444 if (callbackCount.load() > i)
446 std::this_thread::sleep_for(std::chrono::milliseconds(1));
448 if (callbackCount.load() <= i)
449 throw std::runtime_error(
"Callback test failed. No callback received");
454 uint64_t address, uint64_t flits) {
455 struct RegisterExpectation {
460 const RegisterExpectation expectations[] = {
461 {0x00, 0,
"flits_left"},
462 {0x08, address,
"start_addr"},
463 {0x10, flits,
"flits_total"},
465 for (
const auto &[offset, expected, name] : expectations) {
466 uint64_t actual = mmio.
read(offset);
467 if (actual != expected)
468 throw std::runtime_error(
"BurstCommand MMIO readback for " +
469 std::string(name) +
" failed: expected " +
478 std::cout <<
"Running hostmem WRITE test with width " << width << std::endl;
479 uint64_t *dataPtr =
static_cast<uint64_t *
>(region.
getPtr());
480 auto check = [&](
bool print) {
482 for (
size_t i = 0; i < 9; ++i) {
484 printf(
"[write] dataPtr[%zu] = 0x%016lx\n", i, dataPtr[i]);
485 if (i < (width + 63) / 64 && dataPtr[i] == 0xFFFFFFFFFFFFFFFFull)
491 auto writeMemChildIter = acc->getChildren().find(
AppID(
"writemem", width));
492 if (writeMemChildIter == acc->getChildren().end())
493 throw std::runtime_error(
494 "hostmem write test failed. No writemem child found");
495 auto &writeMemPorts = writeMemChildIter->second->getPorts();
501 BundlePort *cmdPortBundle = acc->resolvePort(
502 {
AppID(
"writemem", width),
AppID(
"mmio", width),
AppID(
"cmd")}, cmdPath);
504 throw std::runtime_error(
505 "hostmem write test failed. No mmio[width]/cmd MMIO port");
508 throw std::runtime_error(
509 "hostmem write test failed. mmio[width]/cmd port not MMIO");
511 auto issuedPortIter = writeMemPorts.find(
AppID(
"addrCmdIssued"));
512 if (issuedPortIter == writeMemPorts.end())
513 throw std::runtime_error(
514 "hostmem write test failed. addrCmdIssued missing");
515 auto *addrCmdIssuedPort =
517 if (!addrCmdIssuedPort)
518 throw std::runtime_error(
519 "hostmem write test failed. addrCmdIssued not telemetry");
520 addrCmdIssuedPort->connect();
522 auto responsesPortIter = writeMemPorts.find(
AppID(
"addrCmdResponses"));
523 if (responsesPortIter == writeMemPorts.end())
524 throw std::runtime_error(
525 "hostmem write test failed. addrCmdResponses missing");
526 auto *addrCmdResponsesPort =
528 if (!addrCmdResponsesPort)
529 throw std::runtime_error(
530 "hostmem write test failed. addrCmdResponses not telemetry");
531 addrCmdResponsesPort->connect();
533 for (
size_t i = 0, e = 9; i < e; ++i)
534 dataPtr[i] = 0xFFFFFFFFFFFFFFFFull;
536 uint64_t devPtr =
reinterpret_cast<uint64_t
>(region.
getDevicePtr());
537 cmdMMIO->write(0x08, devPtr);
538 cmdMMIO->write(0x10, 1);
540 cmdMMIO->write(0x18, 1);
542 for (
int i = 0; i < 100; ++i) {
543 auto issued = addrCmdIssuedPort->readInt();
544 auto responses = addrCmdResponsesPort->readInt();
545 if (issued == 1 && responses == 1) {
549 std::this_thread::sleep_for(std::chrono::microseconds(100));
553 throw std::runtime_error(
"hostmem write test (" + std::to_string(width) +
554 " bits) timeout waiting for completion");
557 throw std::runtime_error(
"hostmem write test failed (" +
558 std::to_string(width) +
" bits)");
564 std::cout <<
"Running hostmem READ test with width " << width << std::endl;
565 auto readMemChildIter = acc->getChildren().find(
AppID(
"readmem", width));
566 if (readMemChildIter == acc->getChildren().end())
567 throw std::runtime_error(
568 "hostmem read test failed. No readmem child found");
570 auto &readMemPorts = readMemChildIter->second->getPorts();
575 BundlePort *addrCmdPortBundle = acc->resolvePort(
578 if (!addrCmdPortBundle)
579 throw std::runtime_error(
580 "hostmem read test failed. No mmio[width]/cmd MMIO port");
583 throw std::runtime_error(
584 "hostmem read test failed. mmio[width]/cmd port not MMIO");
586 auto lastReadPortIter = readMemPorts.find(
AppID(
"lastReadLSB"));
587 if (lastReadPortIter == readMemPorts.end())
588 throw std::runtime_error(
"hostmem read test failed. lastReadLSB missing");
592 throw std::runtime_error(
593 "hostmem read test failed. lastReadLSB not telemetry");
594 lastReadPort->connect();
596 auto issuedPortIter = readMemPorts.find(
AppID(
"addrCmdIssued"));
597 if (issuedPortIter == readMemPorts.end())
598 throw std::runtime_error(
"hostmem read test failed. addrCmdIssued missing");
599 auto *addrCmdIssuedPort =
601 if (!addrCmdIssuedPort)
602 throw std::runtime_error(
603 "hostmem read test failed. addrCmdIssued not telemetry");
604 addrCmdIssuedPort->connect();
606 auto responsesPortIter = readMemPorts.find(
AppID(
"addrCmdResponses"));
607 if (responsesPortIter == readMemPorts.end())
608 throw std::runtime_error(
609 "hostmem read test failed. addrCmdResponses missing");
610 auto *addrCmdResponsesPort =
612 if (!addrCmdResponsesPort)
613 throw std::runtime_error(
614 "hostmem read test failed. addrCmdResponses not telemetry");
615 addrCmdResponsesPort->connect();
617 for (
size_t i = 0; i < 8; ++i) {
618 auto *dataPtr =
static_cast<uint64_t *
>(region.
getPtr());
619 dataPtr[0] = 0x12345678ull << i;
620 dataPtr[1] = 0xDEADBEEFull << i;
622 uint64_t devPtr =
reinterpret_cast<uint64_t
>(region.
getDevicePtr());
623 addrCmdMMIO->write(0x08, devPtr);
624 addrCmdMMIO->write(0x10, 1);
626 addrCmdMMIO->write(0x18, 1);
628 for (
int waitLoop = 0; waitLoop < 100; ++waitLoop) {
629 auto issued = addrCmdIssuedPort->readInt();
630 auto responses = addrCmdResponsesPort->readInt();
631 if (issued == 1 && responses == 1) {
635 std::this_thread::sleep_for(std::chrono::milliseconds(10));
638 throw std::runtime_error(
"hostmem read (" + std::to_string(width) +
639 " bits) timeout waiting for completion");
640 uint64_t captured = lastReadPort->readInt();
641 uint64_t expected = dataPtr[0];
643 expected &= ((1ull << width) - 1);
644 if (captured != expected)
645 throw std::runtime_error(
"hostmem read test (" + std::to_string(width) +
646 " bits) failed. Expected " +
653 const std::vector<uint32_t> &widths,
bool write,
658 auto scratchRegion = hostmem->allocate(1024 * 1024,
659 {.writeable =
true});
661 throw std::runtime_error(
"hostmem test: failed to allocate host memory");
662 uint64_t *dataPtr =
static_cast<uint64_t *
>(scratchRegion->getPtr());
663 conn->getLogger().info(
"esitester",
664 "Running host memory test with region size " +
665 std::to_string(scratchRegion->getSize()) +
666 " bytes at 0x" +
toHex(dataPtr));
667 for (
size_t i = 0; i < scratchRegion->getSize() / 8; ++i)
669 scratchRegion->flush();
672 for (
size_t width : widths) {
678 }
catch (std::exception &e) {
679 conn->getLogger().error(
"esitester",
"Hostmem test failed for width " +
680 std::to_string(width) +
": " +
686 throw std::runtime_error(
"Hostmem test failed");
687 std::cout <<
"Hostmem test passed" << std::endl;
692 Logger &logger = conn->getLogger();
693 logger.
info(
"esitester",
694 "== Running DMA read test with width " + std::to_string(width));
696 BundlePort *toHostMMIOPort =
697 acc->resolvePort({
AppID(
"tohostdma", width),
AppID(
"cmd")}, lastPath);
699 throw std::runtime_error(
"dma read test failed. No tohostdma[" +
700 std::to_string(width) +
"] found");
703 throw std::runtime_error(
"dma read test failed. MMIO port is not MMIO");
705 BundlePort *outPortBundle =
706 acc->resolvePort({
AppID(
"tohostdma", width),
AppID(
"out")}, lastPath);
710 size_t xferCount = 24;
712 toHostMMIO->write(0, xferCount);
713 const size_t wireBytes = (width + 7) / 8;
714 for (
size_t index = 0; index < xferCount; ++index) {
716 if (data.getSize() != wireBytes)
717 throw std::runtime_error(
"dma read test failed. Expected " +
718 std::to_string(wireBytes) +
" bytes, got " +
719 std::to_string(data.getSize()));
720 for (
size_t byte = 0;
byte < wireBytes; ++byte) {
723 if (data.getBytes()[
byte] != expected)
724 throw std::runtime_error(
725 "dma read test failed. Data mismatch at item " +
726 std::to_string(index) +
" byte " + std::to_string(
byte) +
727 ": expected " +
toHex(expected) +
", got " +
728 toHex(data.getBytes()[
byte]));
730 logger.
debug(
"esitester",
731 "Payload [" + std::to_string(index) +
"] = 0x" + data.toHex());
734 std::cout <<
" DMA read test for " << width <<
" bits passed" << std::endl;
739 Logger &logger = conn->getLogger();
740 logger.
info(
"esitester",
741 "Running DMA write test with width " + std::to_string(width));
743 BundlePort *fromHostMMIOPort =
744 acc->resolvePort({
AppID(
"fromhostdma", width),
AppID(
"cmd")}, lastPath);
745 if (!fromHostMMIOPort)
746 throw std::runtime_error(
"dma read test for " +
toString(width) +
747 " bits failed. No fromhostdma[" +
748 std::to_string(width) +
"] found");
751 throw std::runtime_error(
"dma write test for " +
toString(width) +
752 " bits failed. MMIO port is not MMIO");
754 BundlePort *outPortBundle =
755 acc->resolvePort({
AppID(
"fromhostdma", width),
AppID(
"in")}, lastPath);
757 throw std::runtime_error(
"dma write test for " +
toString(width) +
758 " bits failed. No out port found");
762 size_t xferCount = 24;
763 std::vector<uint8_t> data((width + 7) / 8, 0);
764 fromHostMMIO->read(8);
765 fromHostMMIO->write(0, xferCount);
766 for (
size_t i = 1; i < xferCount + 1; ++i) {
773 std::this_thread::sleep_for(std::chrono::milliseconds(10));
775 }
while (!successWrite && ++attempts < 100);
777 throw std::runtime_error(
"dma write test for " +
toString(width) +
778 " bits failed. Write failed");
779 uint64_t lastReadMMIO;
780 for (
size_t a = 0; a < 20; ++a) {
781 lastReadMMIO = fromHostMMIO->read(8);
782 if (lastReadMMIO == i)
784 std::this_thread::sleep_for(std::chrono::milliseconds(10));
786 throw std::runtime_error(
"dma write for " +
toString(width) +
787 " bits test failed. Read from MMIO failed");
791 std::cout <<
" DMA write test for " << width <<
" bits passed" << std::endl;
795 const std::vector<uint32_t> &widths,
bool read,
799 for (
size_t width : widths)
802 }
catch (std::exception &e) {
804 std::cerr <<
"DMA write test for " << width
805 <<
" bits failed: " << e.what() << std::endl;
808 for (
size_t width : widths)
811 throw std::runtime_error(
"DMA test failed");
812 std::cout <<
"DMA test passed" << std::endl;
822 const size_t tailBits = bitWidth % 8;
824 value &= (uint8_t(1) << tailBits) - 1;
831 for (
size_t byte = 0;
byte < bytes.size(); ++byte)
837 const size_t numChunks = (bitWidth + 63) / 64;
839 for (
size_t chunkIndex = 0; chunkIndex < numChunks; ++chunkIndex) {
841 for (
size_t byteInChunk = 0; byteInChunk < 8; ++byteInChunk) {
842 const size_t byteIndex = chunkIndex * 8 + byteInChunk;
845 << (8 * byteInChunk);
847 const unsigned rotate = (8 * chunkIndex) % 64;
848 fold ^= rotate ? ((chunk << rotate) | (chunk >> (64 - rotate))) : chunk;
854 size_t width,
size_t xferCount,
bool checkData) {
857 BundlePort *toHostMMIOPort =
858 acc->resolvePort({
AppID(
"tohostdma", width),
AppID(
"cmd")}, lastPath);
860 throw std::runtime_error(
"bandwidth test failed. No tohostdma[" +
861 std::to_string(width) +
"] found");
864 throw std::runtime_error(
"bandwidth test failed. MMIO port is not MMIO");
866 BundlePort *outPortBundle =
867 acc->resolvePort({
AppID(
"tohostdma", width),
AppID(
"out")}, lastPath);
871 Logger &logger = conn->getLogger();
872 logger.
info(
"esitester",
"Starting read bandwidth test with " +
873 std::to_string(xferCount) +
" x " +
874 std::to_string(width) +
" bit transfers");
876 size_t sizeMismatches = 0;
877 size_t dataMismatches = 0;
878 size_t firstMismatchItem = 0;
879 size_t firstMismatchByte = 0;
880 uint8_t firstExpected = 0;
881 uint8_t firstActual = 0;
882 auto start = std::chrono::high_resolution_clock::now();
883 toHostMMIO->write(0, xferCount);
884 for (
size_t index = 0; index < xferCount; ++index) {
888 if (data.getSize() != wireBytes) {
891 for (
size_t byte = 0;
byte < wireBytes; ++byte) {
892 const uint8_t expected =
894 if (data.getBytes()[
byte] != expected) {
895 if (dataMismatches == 0) {
896 firstMismatchItem = index;
897 firstMismatchByte = byte;
898 firstExpected = expected;
899 firstActual = data.getBytes()[byte];
908 &data](std::string &subsystem, std::string &msg,
909 std::unique_ptr<std::map<std::string, std::any>> &details) {
910 subsystem =
"esitester";
911 msg =
"Payload [" + std::to_string(index) +
"] = 0x" + data.toHex();
914 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
915 std::chrono::high_resolution_clock::now() - start);
917 if (checkData && sizeMismatches != 0)
918 throw std::runtime_error(
919 "bandwidth read data mismatch: " + std::to_string(sizeMismatches) +
920 " payload(s) had the wrong wire size");
921 if (checkData && dataMismatches != 0)
922 throw std::runtime_error(
923 "bandwidth read data mismatch: " + std::to_string(dataMismatches) +
924 " bytes wrong; first at item " + std::to_string(firstMismatchItem) +
925 " byte " + std::to_string(firstMismatchByte) +
": expected " +
926 toHex(firstExpected) +
", got " +
toHex(firstActual));
928 (double)xferCount * (width / 8.0) * 1e6 / (double)duration.count();
929 logger.
info(
"esitester",
930 " Bandwidth test: " + std::to_string(xferCount) +
" x " +
931 std::to_string(width) +
" bit transfers in " +
932 std::to_string(duration.count()) +
" microseconds");
935 logger.
info(
"esitester",
" data integrity: passed");
939 size_t width,
size_t xferCount,
bool checkData) {
942 BundlePort *fromHostMMIOPort =
943 acc->resolvePort({
AppID(
"fromhostdma", width),
AppID(
"cmd")}, lastPath);
944 if (!fromHostMMIOPort)
945 throw std::runtime_error(
"bandwidth test failed. No fromhostdma[" +
946 std::to_string(width) +
"] found");
949 throw std::runtime_error(
"bandwidth test failed. MMIO port is not MMIO");
952 auto fromHostChild = acc->getChildren().find(
AppID(
"fromhostdma", width));
953 if (fromHostChild == acc->getChildren().end())
954 throw std::runtime_error(
"bandwidth test failed. No fromhostdma[" +
955 std::to_string(width) +
"] found");
957 fromHostChild->second->getPorts().find(
AppID(
"fromHostChecksum"));
958 if (checksumIter == fromHostChild->second->getPorts().end())
959 throw std::runtime_error(
960 "bandwidth write data check failed. fromHostChecksum missing");
964 throw std::runtime_error(
"bandwidth write data check failed. "
965 "fromHostChecksum not telemetry");
969 BundlePort *inPortBundle =
970 acc->resolvePort({
AppID(
"fromhostdma", width),
AppID(
"in")}, lastPath);
974 Logger &logger = conn->getLogger();
975 logger.
info(
"esitester",
"Starting write bandwidth test with " +
976 std::to_string(xferCount) +
" x " +
977 std::to_string(width) +
" bit transfers");
979 for (
size_t i = 0; i < dataVec.size(); ++i)
982 uint64_t expectedChecksum = 0;
983 auto start = std::chrono::high_resolution_clock::now();
984 fromHostMMIO->read(8);
985 fromHostMMIO->write(0, xferCount);
986 for (
size_t index = 0; index < xferCount; ++index) {
996 &data](std::string &subsystem, std::string &msg,
997 std::unique_ptr<std::map<std::string, std::any>> &details) {
998 subsystem =
"esitester";
999 msg =
"Payload [" + std::to_string(index) +
"] = 0x" + data.toHex();
1002 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
1003 std::chrono::high_resolution_clock::now() - start);
1005 std::vector<uint8_t> expectedLast;
1009 uint64_t expectedLastValue = 0;
1010 if (!expectedLast.empty())
1011 std::memcpy(&expectedLastValue, expectedLast.data(),
1012 std::min(expectedLast.size(),
sizeof(expectedLastValue)));
1013 bool complete = xferCount == 0;
1014 uint64_t lastReadValue = 0;
1015 for (
size_t attempt = 0; !complete && attempt < 5000; ++attempt) {
1016 lastReadValue = fromHostMMIO->read(8);
1017 if (lastReadValue == expectedLastValue) {
1021 std::this_thread::sleep_for(std::chrono::milliseconds(1));
1024 throw std::runtime_error(
1025 "bandwidth write data check timed out waiting for completion: "
1026 "expected final payload " +
1027 toHex(expectedLastValue) +
", got " +
toHex(lastReadValue));
1028 const uint64_t actualChecksum = checksumPort->
readInt();
1029 if (actualChecksum != expectedChecksum)
1030 throw std::runtime_error(
1031 "bandwidth write data mismatch: checksum expected " +
1032 toHex(expectedChecksum) +
", got " +
toHex(actualChecksum));
1036 double bytesPerSec =
1037 (double)xferCount * (width / 8.0) * 1e6 / (double)duration.count();
1038 logger.
info(
"esitester",
1039 " Bandwidth test: " + std::to_string(xferCount) +
" x " +
1040 std::to_string(width) +
" bit transfers in " +
1041 std::to_string(duration.count()) +
" microseconds");
1044 logger.
info(
"esitester",
" data integrity: passed");
1048 const std::vector<uint32_t> &widths,
1049 uint32_t xferCount,
bool read,
bool write,
1052 for (uint32_t w : widths)
1055 for (uint32_t w : widths)
1069 return (uint8_t)(
seq >> (8 * (j % 8))) ^ (uint8_t)(j * 0x9D);
1077 const size_t tailBits = width % 8;
1079 value &= (uint8_t(1) << tailBits) - 1;
1088 size_t numChunks = (width + 63) / 64;
1090 for (
size_t c = 0; c < numChunks; ++c) {
1092 for (
size_t b = 0; b < 8; ++b) {
1093 size_t j = 8 * c + b;
1097 unsigned r = (8 * c) % 64;
1098 fold ^= r ? ((chunk << r) | (chunk >> (64 - r))) : chunk;
1110 uint32_t width, uint32_t xferCount) {
1111 Logger &logger = conn->getLogger();
1112 logger.
info(
"esitester",
"Starting hostmem WRITE bandwidth test: " +
1113 std::to_string(xferCount) +
" x " +
1114 std::to_string(width) +
" bits");
1116 auto writeMemChildIter = acc->getChildren().find(
AppID(
"writemem", width));
1117 if (writeMemChildIter == acc->getChildren().end())
1118 throw std::runtime_error(
"hostmem write bandwidth: writemem child missing");
1119 auto &writeMemPorts = writeMemChildIter->second->getPorts();
1125 BundlePort *cmdPortBundle = acc->resolvePort(
1126 {
AppID(
"writemem", width),
AppID(
"mmio", width),
AppID(
"cmd")}, cmdPath);
1128 throw std::runtime_error(
"hostmem write bandwidth: cmd MMIO missing");
1131 throw std::runtime_error(
"hostmem write bandwidth: cmd not MMIO");
1134 BundlePort *cyclePortBundle = acc->resolvePort(
1137 auto issuedIter = writeMemPorts.find(
AppID(
"addrCmdIssued"));
1138 auto respIter = writeMemPorts.find(
AppID(
"addrCmdResponses"));
1139 if (issuedIter == writeMemPorts.end() || respIter == writeMemPorts.end() ||
1141 throw std::runtime_error(
"hostmem write bandwidth: telemetry missing");
1147 if (!issuedPort || !respPort || !cyclePort)
1148 throw std::runtime_error(
1149 "hostmem write bandwidth: telemetry type mismatch");
1151 issuedPort->connect();
1156 uint64_t *dataPtr =
static_cast<uint64_t *
>(region.
getPtr());
1157 size_t words = region.
getSize() / 8;
1158 for (
size_t i = 0; i < words; ++i)
1159 dataPtr[i] = i + 0xA5A50000;
1162 auto start = std::chrono::high_resolution_clock::now();
1164 uint64_t devPtr =
reinterpret_cast<uint64_t
>(region.
getDevicePtr());
1165 cmdMMIO->write(0x08, devPtr);
1166 cmdMMIO->write(0x10, xferCount);
1167 cmdMMIO->write(0x18, 1);
1170 bool completed =
false;
1171 for (
int wait = 0; wait < 100000; ++wait) {
1172 uint64_t respNow = respPort->
readInt();
1173 if (respNow == xferCount) {
1177 std::this_thread::sleep_for(std::chrono::microseconds(50));
1180 throw std::runtime_error(
"hostmem write bandwidth timeout");
1181 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
1182 std::chrono::high_resolution_clock::now() - start);
1183 double bytesPerSec =
1184 (double)xferCount * (width / 8.0) * 1e6 / (double)duration.count();
1185 uint64_t cycles = cyclePort->
readInt();
1186 double bytesPerCycle = (double)xferCount * (width / 8.0) / (double)cycles;
1187 std::cout <<
"[WRITE] Hostmem bandwidth (" << std::to_string(width)
1189 << std::to_string(xferCount) <<
" flits in "
1190 << std::to_string(duration.count()) <<
" us, "
1191 << std::to_string(cycles) <<
" cycles, " << bytesPerCycle
1192 <<
" bytes/cycle" << std::endl;
1198 uint8_t *bytePtr =
static_cast<uint8_t *
>(region.
getPtr());
1200 size_t mismatches = 0;
1201 uint32_t firstMismatch = 0;
1202 size_t firstByte = 0;
1203 uint8_t firstExpected = 0, firstActual = 0;
1204 for (uint32_t i = 0; i < xferCount; ++i) {
1205 for (
size_t j = 0; j < elemBytes; ++j) {
1207 uint8_t actual = bytePtr[(size_t)i * elemBytes + j];
1208 if (actual != expected) {
1209 if (mismatches == 0) {
1212 firstExpected = expected;
1213 firstActual = actual;
1219 if (mismatches != 0) {
1221 std::snprintf(eb,
sizeof(eb),
"0x%02x", firstExpected);
1222 std::snprintf(gb,
sizeof(gb),
"0x%02x", firstActual);
1223 throw std::runtime_error(
1224 "hostmem write bandwidth data mismatch: " + std::to_string(mismatches) +
1225 " bytes wrong; first at element " + std::to_string(firstMismatch) +
1226 " byte " + std::to_string(firstByte) +
" expected=" + eb +
1234 uint32_t width, uint32_t xferCount) {
1235 Logger &logger = conn->getLogger();
1236 logger.
info(
"esitester",
"Starting hostmem READ bandwidth test: " +
1237 std::to_string(xferCount) +
" x " +
1238 std::to_string(width) +
" bits");
1240 auto readMemChildIter = acc->getChildren().find(
AppID(
"readmem", width));
1241 if (readMemChildIter == acc->getChildren().end())
1242 throw std::runtime_error(
"hostmem read bandwidth: readmem child missing");
1243 auto &readMemPorts = readMemChildIter->second->getPorts();
1248 BundlePort *cmdPortBundle = acc->resolvePort(
1249 {
AppID(
"readmem", width),
AppID(
"mmio", width),
AppID(
"cmd")}, cmdPath);
1251 throw std::runtime_error(
"hostmem read bandwidth: cmd MMIO missing");
1254 throw std::runtime_error(
"hostmem read bandwidth: cmd not MMIO");
1257 BundlePort *cyclePortBundle = acc->resolvePort(
1260 auto issuedIter = readMemPorts.find(
AppID(
"addrCmdIssued"));
1261 auto respIter = readMemPorts.find(
AppID(
"addrCmdResponses"));
1262 auto checksumIter = readMemPorts.find(
AppID(
"readChecksum"));
1263 if (issuedIter == readMemPorts.end() || respIter == readMemPorts.end() ||
1264 checksumIter == readMemPorts.end() || !cyclePortBundle)
1265 throw std::runtime_error(
"hostmem read bandwidth: telemetry missing");
1269 auto *checksumPort =
1271 auto *cycleCntPort =
1273 if (!issuedPort || !respPort || !checksumPort || !cycleCntPort)
1274 throw std::runtime_error(
"hostmem read bandwidth: telemetry type mismatch");
1275 issuedPort->connect();
1284 uint8_t *bytePtr =
static_cast<uint8_t *
>(region.
getPtr());
1286 uint64_t expectedChecksum = 0;
1287 for (uint32_t i = 0; i < xferCount; ++i) {
1288 for (
size_t j = 0; j < elemBytes; ++j)
1293 uint64_t devPtr =
reinterpret_cast<uint64_t
>(region.
getDevicePtr());
1294 auto start = std::chrono::high_resolution_clock::now();
1296 cmdMMIO->write(0x08, devPtr);
1297 cmdMMIO->write(0x10, xferCount);
1298 cmdMMIO->write(0x18, 1);
1300 bool timeout =
true;
1301 for (
int wait = 0; wait < 100000; ++wait) {
1302 uint64_t respNow = respPort->
readInt();
1303 if (respNow == xferCount) {
1307 std::this_thread::sleep_for(std::chrono::microseconds(50));
1310 throw std::runtime_error(
"hostmem read bandwidth timeout");
1311 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
1312 std::chrono::high_resolution_clock::now() - start);
1313 double bytesPerSec =
1314 (double)xferCount * (width / 8.0) * 1e6 / (double)duration.count();
1315 uint64_t cycles = cycleCntPort->
readInt();
1316 double bytesPerCycle = (double)xferCount * (width / 8.0) / (double)cycles;
1317 std::cout <<
"[ READ] Hostmem bandwidth (" << width
1319 <<
" flits in " << duration.count() <<
" us, " << cycles
1320 <<
" cycles, " << bytesPerCycle <<
" bytes/cycle" << std::endl;
1322 uint64_t gotChecksum = checksumPort->
readInt();
1323 if (gotChecksum != expectedChecksum) {
1324 char eb[24], gb[24];
1325 std::snprintf(eb,
sizeof(eb),
"0x%016llx",
1326 (
unsigned long long)expectedChecksum);
1327 std::snprintf(gb,
sizeof(gb),
"0x%016llx", (
unsigned long long)gotChecksum);
1328 throw std::runtime_error(
1330 "hostmem read bandwidth data mismatch: checksum expected ") +
1337 const std::vector<uint32_t> &widths,
bool read,
1340 hostmemSvc->
start();
1341 auto region = hostmemSvc->allocate(1024 * 1024 * 1024,
1342 {.writeable =
true});
1344 throw std::runtime_error(
1345 "hostmem bandwidth test: failed to allocate host memory");
1346 for (uint32_t w : widths) {
1355 uint32_t iterations,
bool pipeline) {
1356 Logger &logger = conn->getLogger();
1359 throw std::runtime_error(
"Loopback test: no 'loopback' child");
1360 auto &ports = loopbackChild->second->getPorts();
1361 auto addIter = ports.find(
AppID(
"add"));
1362 if (addIter == ports.end())
1363 throw std::runtime_error(
"Loopback test: no 'add' port");
1368 throw std::runtime_error(
1369 "Loopback test: 'add' port not a FuncService::Function");
1370 funcPort->connect();
1371 if (iterations == 0) {
1372 logger.
info(
"esitester",
"Loopback add test: 0 iterations (skipped)");
1375 std::mt19937_64 rng(0xC0FFEE);
1376 std::uniform_int_distribution<uint32_t> dist(0, (1u << 24) - 1);
1379 auto start = std::chrono::high_resolution_clock::now();
1380 for (uint32_t i = 0; i < iterations; ++i) {
1381 uint32_t argVal = dist(rng);
1382 uint32_t expected = (argVal + 11) & 0xFFFF;
1383 uint8_t argBytes[3] = {
1384 static_cast<uint8_t
>(argVal & 0xFF),
1385 static_cast<uint8_t
>((argVal >> 8) & 0xFF),
1386 static_cast<uint8_t
>((argVal >> 16) & 0xFF),
1389 MessageData resMsg = funcPort->call(argMsg).get();
1390 uint16_t got = *resMsg.
as<uint16_t>();
1391 std::cout <<
"[loopback] i=" << i <<
" arg=0x" <<
esi::toHex(argVal)
1394 if (got != expected)
1395 throw std::runtime_error(
"Loopback mismatch (non-pipelined)");
1397 auto end = std::chrono::high_resolution_clock::now();
1398 auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start)
1400 double callsPerSec = (double)iterations * 1e6 / (
double)us;
1401 logger.
info(
"esitester",
"Loopback add test passed (non-pipelined, " +
1402 std::to_string(iterations) +
" calls, " +
1403 std::to_string(us) +
" us, " +
1404 std::to_string(callsPerSec) +
" calls/s)");
1407 std::vector<std::future<MessageData>> futures;
1408 futures.reserve(iterations);
1409 std::vector<uint32_t> expectedVals;
1410 expectedVals.reserve(iterations);
1412 auto issueStart = std::chrono::high_resolution_clock::now();
1413 for (uint32_t i = 0; i < iterations; ++i) {
1414 uint32_t argVal = dist(rng);
1415 uint32_t expected = (argVal + 11) & 0xFFFF;
1416 uint8_t argBytes[3] = {
1417 static_cast<uint8_t
>(argVal & 0xFF),
1418 static_cast<uint8_t
>((argVal >> 8) & 0xFF),
1419 static_cast<uint8_t
>((argVal >> 16) & 0xFF),
1421 futures.emplace_back(funcPort->call(
MessageData(argBytes, 3)));
1422 expectedVals.emplace_back(expected);
1424 auto issueEnd = std::chrono::high_resolution_clock::now();
1426 for (uint32_t i = 0; i < iterations; ++i) {
1428 uint16_t got = *resMsg.
as<uint16_t>();
1429 uint16_t exp = (uint16_t)expectedVals[i];
1430 std::cout <<
"[loopback-pipelined] i=" << i <<
" got=0x"
1433 throw std::runtime_error(
"Loopback mismatch (pipelined) idx=" +
1436 auto collectEnd = std::chrono::high_resolution_clock::now();
1438 auto issueUs = std::chrono::duration_cast<std::chrono::microseconds>(
1439 issueEnd - issueStart)
1441 auto totalUs = std::chrono::duration_cast<std::chrono::microseconds>(
1442 collectEnd - issueStart)
1445 double issueRate = (double)iterations * 1e6 / (
double)issueUs;
1446 double completionRate = (double)iterations * 1e6 / (
double)totalUs;
1448 logger.
info(
"esitester",
"Loopback add test passed (pipelined). Issued " +
1449 std::to_string(iterations) +
" in " +
1450 std::to_string(issueUs) +
" us (" +
1451 std::to_string(issueRate) +
1452 " calls/s), total " + std::to_string(totalUs) +
1453 " us (" + std::to_string(completionRate) +
1454 " calls/s effective)");
1464 Logger &logger = conn->getLogger();
1465 constexpr uint32_t width = 64;
1473 auto writeMemChildIter = accel->
getChildren().find(
AppID(
"writemem", width));
1474 if (writeMemChildIter == accel->
getChildren().end())
1475 throw std::runtime_error(
"Reset test: no 'writemem' child");
1476 auto &ports = writeMemChildIter->second->getPorts();
1477 auto respIter = ports.find(
AppID(
"addrCmdResponses"));
1478 if (respIter == ports.end())
1479 throw std::runtime_error(
1480 "Reset test: no 'addrCmdResponses' telemetry port");
1484 throw std::runtime_error(
"Reset test: 'addrCmdResponses' not telemetry");
1485 respMetric->connect();
1487 uint64_t before = respMetric->readInt();
1488 std::cout <<
"[reset] telemetry addrCmdResponses before reset = " << before
1491 throw std::runtime_error(
1492 "Reset test: telemetry was not incremented by the hostmem write");
1495 logger.
info(
"esitester",
"Requesting design reset");
1497 throw std::runtime_error(
"Reset test: reset() reported failure");
1498 std::cout <<
"[reset] reset requested" << std::endl;
1502 uint64_t after = before;
1503 constexpr int maxPolls = 1000000;
1504 for (
int polls = 0; polls < maxPolls; ++polls) {
1505 after = respMetric->readInt();
1508 std::this_thread::sleep_for(std::chrono::microseconds(1));
1510 std::cout <<
"[reset] telemetry addrCmdResponses after reset = " << after
1513 throw std::runtime_error(
1514 "Reset test: telemetry was not cleared by the reset (got " +
1515 std::to_string(after) +
")");
1517 std::cout <<
"Reset test passed" << std::endl;
1522 uint32_t xferCount,
bool read,
1524 Logger &logger = conn->getLogger();
1525 if (!read && !write) {
1526 std::cout <<
"aggbandwidth: nothing to do (enable --read and/or --write)\n";
1531 "Aggregate hostmem bandwidth start width=" + std::to_string(width) +
1532 " count=" + std::to_string(xferCount) +
1533 " read=" + (read ?
"Y" :
"N") +
" write=" + (write ?
"Y" :
"N"));
1536 hostmemSvc->
start();
1540 bool isRead =
false;
1541 bool isWrite =
false;
1542 std::unique_ptr<esi::services::HostMem::HostMemRegion> region;
1546 bool launched =
false;
1549 uint64_t duration_us = 0;
1550 uint64_t cycleCount = 0;
1551 std::chrono::high_resolution_clock::time_point start;
1553 std::vector<Unit> units;
1554 const std::vector<std::string> readPrefixes = {
"readmem",
"readmem_0",
1555 "readmem_1",
"readmem_2"};
1556 const std::vector<std::string> writePrefixes = {
"writemem",
"writemem_0",
1557 "writemem_1",
"writemem_2"};
1561 size_t strideBytes = ((width + 31) / 32) * 4;
1562 size_t neededBytes =
static_cast<size_t>(xferCount) * strideBytes;
1563 size_t regionBytes = neededBytes < (1u << 20) ? (1u << 20) : neededBytes;
1565 auto addUnits = [&](
const std::vector<std::string> &pref,
bool doRead,
1567 for (
auto &p : pref) {
1569 auto childIt = acc->getChildren().find(
id);
1570 if (childIt == acc->getChildren().end())
1572 auto &ports = childIt->second->getPorts();
1573 auto respIt = ports.find(
AppID(
"addrCmdResponses"));
1577 BundlePort *cmdBundle =
1578 acc->resolvePort({id,
AppID(
"mmio", width),
AppID(
"cmd")}, cmdPath);
1579 BundlePort *cycBundle = acc->resolvePort(
1580 {id,
AppID(
"addrCmdResp"),
AppID(
"cycles")}, cycPath);
1581 if (respIt == ports.end() || !cmdBundle || !cycBundle)
1586 if (!cmd || !resp || !cyc)
1593 u.isWrite = doWrite;
1594 u.region = hostmemSvc->allocate(regionBytes, {.writeable =
true});
1596 throw std::runtime_error(
1597 "hostmem bandwidth test: failed to allocate host memory");
1599 uint64_t *ptr =
static_cast<uint64_t *
>(u.region->getPtr());
1600 size_t words = u.region->getSize() / 8;
1601 for (
size_t i = 0; i < words; ++i)
1603 (p[0] ==
'w' ? (0xA5A500000000ull + i) : (0xCAFEBABE0000ull + i));
1608 u.bytes = uint64_t(xferCount) * (width / 8);
1609 units.emplace_back(std::move(u));
1613 addUnits(readPrefixes,
true,
false);
1615 addUnits(writePrefixes,
false,
true);
1616 if (units.empty()) {
1617 std::cout <<
"aggbandwidth: no matching units present for width " << width
1622 auto wallStart = std::chrono::high_resolution_clock::now();
1624 for (
auto &u : units) {
1625 uint64_t devPtr =
reinterpret_cast<uint64_t
>(u.region->getDevicePtr());
1626 u.cmd->write(0x08, devPtr);
1627 u.cmd->write(0x10, xferCount);
1628 u.cmd->write(0x18, 1);
1629 u.start = std::chrono::high_resolution_clock::now();
1634 const uint64_t timeoutLoops = 200000;
1637 bool allDone =
true;
1638 for (
auto &u : units) {
1641 if (u.resp->readInt() == xferCount) {
1642 auto end = std::chrono::high_resolution_clock::now();
1644 std::chrono::duration_cast<std::chrono::microseconds>(end - u.start)
1646 u.cycleCount = u.cycles->readInt();
1654 if (++loops >= timeoutLoops)
1655 throw std::runtime_error(
"aggbandwidth: timeout");
1656 std::this_thread::sleep_for(std::chrono::microseconds(50));
1658 auto wallUs = std::chrono::duration_cast<std::chrono::microseconds>(
1659 std::chrono::high_resolution_clock::now() - wallStart)
1662 uint64_t totalBytes = 0;
1663 uint64_t totalReadBytes = 0;
1664 uint64_t totalWriteBytes = 0;
1665 for (
auto &u : units) {
1666 totalBytes += u.bytes;
1668 totalReadBytes += u.bytes;
1670 totalWriteBytes += u.bytes;
1671 double unitBps = (double)u.bytes * 1e6 / (
double)u.duration_us;
1672 std::cout <<
"[agg-unit] " << u.prefix <<
"[" << width <<
"] "
1673 << (u.isRead ?
"READ" : (u.isWrite ?
"WRITE" :
"UNK"))
1674 <<
" bytes=" <<
humanBytes(u.bytes) <<
" (" << u.bytes <<
" B)"
1675 <<
" time=" <<
humanTimeUS(u.duration_us) <<
" (" << u.duration_us
1676 <<
" us) cycles=" << u.cycleCount
1682 totalReadBytes ? (double)totalReadBytes * 1e6 / (
double)wallUs : 0.0;
1683 double aggWriteBps =
1684 totalWriteBytes ? (double)totalWriteBytes * 1e6 / (
double)wallUs : 0.0;
1685 double aggCombinedBps =
1686 totalBytes ? (double)totalBytes * 1e6 / (
double)wallUs : 0.0;
1688 std::cout <<
"[agg-total] units=" << units.size()
1689 <<
" read_bytes=" <<
humanBytes(totalReadBytes) <<
" ("
1690 << totalReadBytes <<
" B)"
1692 <<
" write_bytes=" <<
humanBytes(totalWriteBytes) <<
" ("
1693 << totalWriteBytes <<
" B)"
1695 <<
" combined_bytes=" <<
humanBytes(totalBytes) <<
" ("
1696 << totalBytes <<
" B)"
1698 <<
" wall_time=" <<
humanTimeUS(wallUs) <<
" (" << wallUs <<
" us)"
1700 logger.
info(
"esitester",
"Aggregate hostmem bandwidth test complete");
1706#pragma pack(push, 1)
1714 "StreamingAddArg must be 9 bytes packed");
1719#pragma pack(push, 1)
1726 "StreamingAddResult must be 5 bytes packed");
1732 uint32_t addAmt, uint32_t numItems) {
1733 Logger &logger = conn->getLogger();
1734 logger.
info(
"esitester",
"Starting streaming add test with add_amt=" +
1735 std::to_string(addAmt) +
1736 ", num_items=" + std::to_string(numItems));
1739 std::mt19937 rng(0xDEADBEEF);
1740 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
1741 std::vector<uint32_t> inputData;
1742 inputData.reserve(numItems);
1743 for (uint32_t i = 0; i < numItems; ++i)
1744 inputData.push_back(dist(rng));
1747 auto streamingAdderChild =
1749 if (streamingAdderChild == accel->
getChildren().end())
1750 throw std::runtime_error(
1751 "Streaming add test: no 'streaming_adder' child found");
1753 auto &ports = streamingAdderChild->second->getPorts();
1754 auto addIter = ports.find(
AppID(
"streaming_add"));
1755 if (addIter == ports.end())
1756 throw std::runtime_error(
1757 "Streaming add test: no 'streaming_add' port found");
1769 for (
size_t i = 0; i < inputData.size(); ++i) {
1772 arg.
input = inputData[i];
1773 arg.
last = (i == inputData.size() - 1) ? 1 : 0;
1775 MessageData(
reinterpret_cast<const uint8_t *
>(&arg),
sizeof(arg)));
1776 logger.
debug(
"esitester",
"Sent {add_amt=" + std::to_string(arg.
addAmt) +
1777 ", input=" + std::to_string(arg.
input) +
1778 ", last=" + (arg.
last ?
"true" :
"false") +
1783 std::vector<uint32_t> results;
1784 bool lastSeen =
false;
1787 resultPort.
read(resMsg);
1789 throw std::runtime_error(
1790 "Streaming add test: unexpected result message size");
1794 lastSeen = res->last != 0;
1795 results.push_back(res->data);
1796 logger.
debug(
"esitester",
"Received result=" + std::to_string(res->data) +
1797 " (last=" + (lastSeen ?
"true" :
"false") +
1802 if (results.size() != inputData.size())
1803 throw std::runtime_error(
1804 "Streaming add test: result size mismatch. Expected " +
1805 std::to_string(inputData.size()) +
", got " +
1806 std::to_string(results.size()));
1809 std::cout <<
"Streaming add test results:" << std::endl;
1810 for (
size_t i = 0; i < inputData.size(); ++i) {
1811 uint32_t expected = inputData[i] + addAmt;
1812 std::cout <<
" input[" << i <<
"]=" << inputData[i] <<
" + " << addAmt
1813 <<
" = " << results[i] <<
" (expected " << expected <<
")";
1814 if (results[i] != expected) {
1815 std::cout <<
" MISMATCH!";
1818 std::cout << std::endl;
1825 throw std::runtime_error(
"Streaming add test failed: result mismatch");
1827 logger.
info(
"esitester",
"Streaming add test passed");
1828 std::cout <<
"Streaming add test passed" << std::endl;
1847#pragma pack(push, 1)
1855 uint32_t *
inputData() {
return reinterpret_cast<uint32_t *
>(
this + 1); }
1857 return reinterpret_cast<const uint32_t *
>(
this + 1);
1876#pragma pack(push, 1)
1882 uint32_t *
data() {
return reinterpret_cast<uint32_t *
>(
this + 1); }
1884 return reinterpret_cast<const uint32_t *
>(
this + 1);
1898 uint32_t numItems) {
1899 Logger &logger = conn->getLogger();
1900 logger.
info(
"esitester",
1901 "Starting streaming add test (translated) with add_amt=" +
1902 std::to_string(addAmt) +
1903 ", num_items=" + std::to_string(numItems));
1906 std::mt19937 rng(0xDEADBEEF);
1907 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
1908 std::vector<uint32_t> inputData;
1909 inputData.reserve(numItems);
1910 for (uint32_t i = 0; i < numItems; ++i)
1911 inputData.push_back(dist(rng));
1914 auto streamingAdderChild =
1916 if (streamingAdderChild == accel->
getChildren().end())
1917 throw std::runtime_error(
1918 "Streaming add test: no 'streaming_adder' child found");
1920 auto &ports = streamingAdderChild->second->getPorts();
1921 auto addIter = ports.find(
AppID(
"streaming_add"));
1922 if (addIter == ports.end())
1923 throw std::runtime_error(
1924 "Streaming add test: no 'streaming_add' port found");
1940 size_t allocSize = ((argSize + alignment - 1) / alignment) * alignment;
1943 throw std::bad_alloc();
1945 std::unique_ptr<void,
decltype(argDeleter)> argBuffer(argRaw, argDeleter);
1948 arg->addAmt = addAmt;
1949 for (uint32_t i = 0; i < numItems; ++i)
1950 arg->inputData()[i] = inputData[i];
1952 logger.
debug(
"esitester",
1953 "Sending translated argument: " + std::to_string(argSize) +
1954 " bytes, list_length=" + std::to_string(arg->inputLength) +
1955 ", add_amt=" + std::to_string(arg->addAmt));
1958 argPort.
write(
MessageData(
reinterpret_cast<const uint8_t *
>(arg), argSize));
1963 resultPort.
read(resMsg);
1965 logger.
debug(
"esitester",
"Received translated result: " +
1966 std::to_string(resMsg.
getSize()) +
" bytes");
1969 throw std::runtime_error(
1970 "Streaming add test (translated): result too small");
1972 const auto *result =
1977 throw std::runtime_error(
1978 "Streaming add test (translated): result data truncated");
1981 if (result->dataLength != inputData.size())
1982 throw std::runtime_error(
1983 "Streaming add test (translated): result size mismatch. Expected " +
1984 std::to_string(inputData.size()) +
", got " +
1985 std::to_string(result->dataLength));
1988 std::cout <<
"Streaming add test results:" << std::endl;
1989 for (
size_t i = 0; i < inputData.size(); ++i) {
1990 uint32_t expected = inputData[i] + addAmt;
1991 std::cout <<
" input[" << i <<
"]=" << inputData[i] <<
" + " << addAmt
1992 <<
" = " << result->data()[i] <<
" (expected " << expected <<
")";
1993 if (result->data()[i] != expected) {
1994 std::cout <<
" MISMATCH!";
1997 std::cout << std::endl;
2004 throw std::runtime_error(
2005 "Streaming add test (translated) failed: result mismatch");
2007 logger.
info(
"esitester",
"Streaming add test passed (translated)");
2008 std::cout <<
"Streaming add test passed" << std::endl;
2019#pragma pack(push, 1)
2025static_assert(
sizeof(
Coord) == 8,
"Coord must be 8 bytes packed");
2036#pragma pack(push, 1)
2046 return reinterpret_cast<const Coord *
>(
this + 1);
2063#pragma pack(push, 1)
2071 return reinterpret_cast<const Coord *
>(
this + 1);
2084 uint32_t xTrans, uint32_t yTrans,
2085 uint32_t numCoords) {
2086 Logger &logger = conn->getLogger();
2087 logger.
info(
"esitester",
"Starting coord translate test with x_trans=" +
2088 std::to_string(xTrans) +
2089 ", y_trans=" + std::to_string(yTrans) +
2090 ", num_coords=" + std::to_string(numCoords));
2095 std::mt19937 rng(0xDEADBEEF);
2096 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
2097 std::vector<Coord> inputCoords;
2098 inputCoords.reserve(numCoords);
2099 for (uint32_t i = 0; i < numCoords; ++i) {
2103 inputCoords.push_back(c);
2107 auto coordTranslatorChild =
2109 if (coordTranslatorChild == accel->
getChildren().end())
2110 throw std::runtime_error(
2111 "Coord translate test: no 'coord_translator' child found");
2113 auto &ports = coordTranslatorChild->second->getPorts();
2114 auto translateIter = ports.find(
AppID(
"translate_coords"));
2115 if (translateIter == ports.end())
2116 throw std::runtime_error(
2117 "Coord translate test: no 'translate_coords' port found");
2123 throw std::runtime_error(
2124 "Coord translate test: 'translate_coords' port not a "
2125 "FuncService::Function");
2126 funcPort->connect();
2133 size_t allocSize = ((argSize + alignment - 1) / alignment) * alignment;
2136 throw std::bad_alloc();
2138 std::unique_ptr<void,
decltype(argDeleter)> argBuffer(argRaw, argDeleter);
2141 arg->xTranslation = xTrans;
2142 arg->yTranslation = yTrans;
2143 for (uint32_t i = 0; i < numCoords; ++i)
2144 arg->coords()[i] = inputCoords[i];
2148 "Sending coord translate argument: " + std::to_string(argSize) +
2149 " bytes, coords_length=" + std::to_string(arg->coordsLength) +
2150 ", x_trans=" + std::to_string(arg->xTranslation) +
2151 ", y_trans=" + std::to_string(arg->yTranslation));
2156 ->call(
MessageData(
reinterpret_cast<const uint8_t *
>(arg), argSize))
2160 logger.
debug(
"esitester",
"Received coord translate result: " +
2161 std::to_string(resMsg.
getSize()) +
" bytes");
2164 throw std::runtime_error(
"Coord translate test: result too small");
2166 const auto *result =
2170 throw std::runtime_error(
"Coord translate test: result data truncated");
2173 if (result->coordsLength != inputCoords.size())
2174 throw std::runtime_error(
2175 "Coord translate test: result size mismatch. Expected " +
2176 std::to_string(inputCoords.size()) +
", got " +
2177 std::to_string(result->coordsLength));
2180 std::cout <<
"Coord translate test results:" << std::endl;
2181 for (
size_t i = 0; i < inputCoords.size(); ++i) {
2182 uint32_t expectedX = inputCoords[i].x + xTrans;
2183 uint32_t expectedY = inputCoords[i].y + yTrans;
2184 std::cout <<
" coord[" << i <<
"]=(" << inputCoords[i].x <<
","
2185 << inputCoords[i].y <<
") + (" << xTrans <<
"," << yTrans
2186 <<
") = (" << result->coords()[i].x <<
","
2187 << result->coords()[i].y <<
")";
2188 if (result->coords()[i].x != expectedX ||
2189 result->coords()[i].y != expectedY) {
2190 std::cout <<
" MISMATCH! (expected (" << expectedX <<
"," << expectedY
2194 std::cout << std::endl;
2198 throw std::runtime_error(
"Coord translate test failed: result mismatch");
2200 logger.
info(
"esitester",
"Coord translate test passed");
2201 std::cout <<
"Coord translate test passed" << std::endl;
2208#pragma pack(push, 1)
2251 coords.emplace_back(x, y);
2259 return {
reinterpret_cast<const uint8_t *
>(&
header),
sizeof(
header)};
2261 return {
reinterpret_cast<const uint8_t *
>(
coords.data()),
2264 return {
reinterpret_cast<const uint8_t *
>(&
footer),
sizeof(
footer)};
2266 throw std::out_of_range(
"SerialCoordInput: invalid segment index");
2288 coords.emplace_back(x, y);
2295 return {
reinterpret_cast<const uint8_t *
>(&
header),
sizeof(
header)};
2297 return {
reinterpret_cast<const uint8_t *
>(
coords.data()),
2300 throw std::out_of_range(
"SerialCoordBurst: invalid segment index");
2304#pragma pack(push, 1)
2343 const uint8_t *bytes = flat.
getBytes();
2348 while (offset < size) {
2350 size_t chunkSize = std::min(needed, size - offset);
2352 bytes + offset + chunkSize);
2353 offset += chunkSize;
2365 if (batchCount == 0) {
2367 auto batch = std::make_unique<SerialCoordOutputBatch>();
2370 decoded.push_back(std::move(batch));
2394 uint32_t yTrans, uint32_t numCoords,
2395 size_t batchSizeLimit) {
2396 Logger &logger = conn->getLogger();
2397 logger.
info(
"esitester",
"Starting Serial coord translate test");
2400 std::mt19937 rng(0xDEADBEEF);
2401 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
2402 std::vector<Coord> inputCoords;
2403 inputCoords.reserve(numCoords);
2404 for (uint32_t i = 0; i < numCoords; ++i)
2405 inputCoords.push_back({dist(rng), dist(rng)});
2409 throw std::runtime_error(
"Serial coord translate test: no "
2410 "'coord_translator_serial' child found");
2412 auto &ports = child->second->getPorts();
2413 auto portIter = ports.find(
AppID(
"translate_coords_serial"));
2414 if (portIter == ports.end())
2415 throw std::runtime_error(
"Serial coord translate test: no "
2416 "'translate_coords_serial' port found");
2419 portIter->second.getRawWrite(
"arg"));
2434 while (sent < numCoords) {
2435 size_t batchSize = std::min(batchSizeLimit, numCoords - sent);
2440 auto batch = std::make_unique<SerialCoordBurst>();
2441 batch->xTranslation(sent == 0 ? xTrans : 0);
2442 batch->yTranslation(sent == 0 ? yTrans : 0);
2444 for (
size_t i = 0; i < batchSize; ++i) {
2445 batch->appendCoord(inputCoords[sent + i].x, inputCoords[sent + i].y);
2447 argPort.
write(batch);
2451 auto footerBurst = std::make_unique<SerialCoordBurst>();
2452 argPort.
write(footerBurst);
2461 std::vector<uint8_t> rxBuf;
2463 while (rxBuf.size() < frameSize) {
2465 resultRaw.
read(data);
2466 rxBuf.insert(rxBuf.end(), data.getBytes(),
2467 data.getBytes() + data.getSize());
2469 std::memcpy(&out, rxBuf.data(), frameSize);
2470 rxBuf.erase(rxBuf.begin(), rxBuf.begin() + frameSize);
2473 std::vector<Coord> results;
2474 results.reserve(numCoords);
2479 if (batchCount == 0)
2481 for (uint16_t i = 0; i < batchCount; ++i) {
2484 results.push_back({frame.
data.
y, frame.
data.
x});
2490 std::cout <<
"Serial coord translate test results:" << std::endl;
2491 if (results.size() != inputCoords.size()) {
2492 std::cout <<
"Result size mismatch. Expected " << inputCoords.size()
2493 <<
", got " << results.size() << std::endl;
2496 for (
size_t i = 0; i < std::min(inputCoords.size(), results.size()); ++i) {
2497 uint32_t expX = inputCoords[i].x + xTrans;
2498 uint32_t expY = inputCoords[i].y + yTrans;
2499 std::cout <<
" coord[" << i <<
"]=(" << inputCoords[i].x <<
","
2500 << inputCoords[i].y <<
") + (" << xTrans <<
"," << yTrans
2501 <<
") = (" << results[i].x <<
"," << results[i].y
2502 <<
") (expected (" << expX <<
"," << expY <<
"))";
2503 if (results[i].x != expX || results[i].y != expY) {
2504 std::cout <<
" MISMATCH!";
2507 std::cout << std::endl;
2514 throw std::runtime_error(
"Serial coord translate test failed");
2516 logger.
info(
"esitester",
"Serial coord translate test passed");
2517 std::cout <<
"Serial coord translate test passed" << std::endl;
2537 uint32_t yTrans, uint32_t numCoords) {
2538 Logger &logger = conn->getLogger();
2539 logger.
info(
"esitester",
"Starting Auto serial coord translate test");
2542 std::mt19937 rng(0xDEADBEEF);
2543 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
2544 std::vector<Coord> inputCoords;
2545 inputCoords.reserve(numCoords);
2546 for (uint32_t i = 0; i < numCoords; ++i)
2547 inputCoords.push_back({dist(rng), dist(rng)});
2549 auto child = accel->
getChildren().find(
AppID(
"coord_translator_auto_serial"));
2551 throw std::runtime_error(
"Auto serial coord translate test: no "
2552 "'coord_translator_auto_serial' child found");
2554 auto &ports = child->second->getPorts();
2555 auto portIter = ports.find(
AppID(
"translate_coords_auto_serial"));
2556 if (portIter == ports.end())
2557 throw std::runtime_error(
"Auto serial coord translate test: no "
2558 "'translate_coords_auto_serial' port found");
2563 portIter->second.getRawWrite(
"arg"));
2579 auto batch = std::make_unique<SerialCoordInput>();
2580 batch->xTranslation(xTrans);
2581 batch->yTranslation(yTrans);
2582 for (uint32_t i = 0; i < numCoords; ++i)
2583 batch->appendCoord(inputCoords[i].x, inputCoords[i].y);
2584 argPort.
write(batch);
2590 std::vector<uint8_t> rxBuf;
2592 while (rxBuf.size() < frameSize) {
2594 resultRaw.
read(data);
2595 rxBuf.insert(rxBuf.end(), data.getBytes(),
2596 data.getBytes() + data.getSize());
2598 std::memcpy(&out, rxBuf.data(), frameSize);
2599 rxBuf.erase(rxBuf.begin(), rxBuf.begin() + frameSize);
2605 std::vector<Coord> results;
2606 results.reserve(numCoords);
2611 if (burstCount == 0)
2613 if (results.size() + burstCount > numCoords)
2614 throw std::runtime_error(
"Auto serial coord translate test: bursts "
2615 "overflow expected total " +
2616 std::to_string(numCoords));
2617 for (uint32_t i = 0; i < burstCount; ++i) {
2620 results.push_back({frame.
data.
y, frame.
data.
x});
2623 if (results.size() != numCoords)
2624 throw std::runtime_error(
"Auto serial coord translate test: got " +
2625 std::to_string(results.size()) +
2626 " coords across all bursts " +
"(expected " +
2627 std::to_string(numCoords) +
")");
2633 std::cout <<
"Auto serial coord translate test results:" << std::endl;
2634 for (
size_t i = 0; i < inputCoords.size(); ++i) {
2635 uint32_t expX = inputCoords[i].x + xTrans;
2636 uint32_t expY = inputCoords[i].y + yTrans;
2637 std::cout <<
" coord[" << i <<
"]=(" << inputCoords[i].x <<
","
2638 << inputCoords[i].y <<
") + (" << xTrans <<
"," << yTrans
2639 <<
") = (" << results[i].x <<
"," << results[i].y
2640 <<
") (expected (" << expX <<
"," << expY <<
"))";
2641 if (results[i].x != expX || results[i].y != expY) {
2642 std::cout <<
" MISMATCH!";
2645 std::cout << std::endl;
2649 throw std::runtime_error(
"Auto serial coord translate test failed");
2651 logger.
info(
"esitester",
"Auto serial coord translate test passed");
2652 std::cout <<
"Auto serial coord translate test passed" << std::endl;
2656 uint32_t iterations) {
2657 Logger &logger = conn->getLogger();
2661 throw std::runtime_error(
"Channel test: no 'channel_test' child");
2662 auto &ports = channelChild->second->getPorts();
2665 auto cmdIter = ports.find(
AppID(
"cmd"));
2666 if (cmdIter == ports.end())
2667 throw std::runtime_error(
"Channel test: no 'cmd' port");
2670 throw std::runtime_error(
"Channel test: 'cmd' is not MMIO");
2673 auto producerIter = ports.find(
AppID(
"producer"));
2674 if (producerIter == ports.end())
2675 throw std::runtime_error(
"Channel test: no 'producer' port");
2676 auto *producerPort =
2679 throw std::runtime_error(
2680 "Channel test: 'producer' is not a ChannelService::ToHost");
2681 producerPort->connect();
2685 cmdMMIO->write(0x0, iterations);
2687 for (uint32_t i = 0; i < iterations; ++i) {
2688 MessageData recvData = producerPort->read().get();
2689 uint32_t got = *recvData.
as<uint32_t>();
2690 std::cout <<
"[channel] producer i=" << i <<
" got=" << got << std::endl;
2692 throw std::runtime_error(
"Channel producer: expected " +
2693 std::to_string(i) +
", got " +
2694 std::to_string(got));
2696 logger.
info(
"esitester",
"Channel test: producer passed (" +
2697 std::to_string(iterations) +
2698 " incrementing values)");
2701 auto loopbackInIter = ports.find(
AppID(
"loopback_in"));
2702 if (loopbackInIter == ports.end())
2703 throw std::runtime_error(
"Channel test: no 'loopback_in' port");
2704 auto *fromHostPort =
2707 throw std::runtime_error(
2708 "Channel test: 'loopback_in' is not a ChannelService::FromHost");
2709 fromHostPort->connect();
2711 auto loopbackOutIter = ports.find(
AppID(
"loopback_out"));
2712 if (loopbackOutIter == ports.end())
2713 throw std::runtime_error(
"Channel test: no 'loopback_out' port");
2714 auto *loopbackOutPort =
2716 if (!loopbackOutPort)
2717 throw std::runtime_error(
2718 "Channel test: 'loopback_out' is not a ChannelService::ToHost");
2719 loopbackOutPort->connect();
2721 std::mt19937_64 rng(0xDEADBEEF);
2722 std::uniform_int_distribution<uint32_t> dist(0, UINT32_MAX);
2724 for (uint32_t i = 0; i < iterations; ++i) {
2725 uint32_t sendVal = dist(rng);
2727 MessageData recvData = loopbackOutPort->read().get();
2728 uint32_t recvVal = *recvData.
as<uint32_t>();
2729 std::cout <<
"[channel] loopback i=" << i <<
" sent=0x"
2732 if (recvVal != sendVal)
2733 throw std::runtime_error(
"Channel loopback mismatch at i=" +
2737 logger.
info(
"esitester",
"Channel test: loopback passed (" +
2738 std::to_string(iterations) +
" iterations)");
2739 std::cout <<
"Channel test passed" << std::endl;
static void print(TypedAttr val, llvm::raw_ostream &os)
TypeDeserializer(OutputCallback output)
QueuedDecodeTypeDeserializer< SerialCoordOutputBatch > Base
Base::OutputCallback OutputCallback
std::vector< uint8_t > partialFrameBytes
Base::DecodedOutputs DecodedOutputs
DecodedOutputs decode(std::unique_ptr< SegmentedMessageData > &msg) override
Decode one raw message into zero or more typed outputs.
std::vector< Coord > accumulated
Abstract class representing a connection to an accelerator.
Top level accelerator class.
T * getAs() const
Cast this Bundle port to a subclass which is actually useful.
Common options and code for ESI runtime tools.
Context & getContext()
Get the context.
AcceleratorConnection * connect()
Connect to the accelerator using the specified backend and connection.
int esiParse(int argc, const char **argv)
Run the parser.
AcceleratorConnections, Accelerators, and Manifests must all share a context.
const std::map< AppID, Instance * > & getChildren() const
Access the module's children by ID.
virtual void error(const std::string &subsystem, const std::string &msg, const std::map< std::string, std::any > *details=nullptr)
Report an error.
virtual void info(const std::string &subsystem, const std::string &msg, const std::map< std::string, std::any > *details=nullptr)
Report an informational message.
void debug(const std::string &subsystem, const std::string &msg, const std::map< std::string, std::any > *details=nullptr)
Report a debug message.
Class to parse a manifest.
Accelerator * buildAccelerator(AcceleratorConnection &acc) const
A concrete flat message backed by a single vector of bytes.
const uint8_t * getBytes() const
const T * as() const
Cast to a type.
size_t getSize() const
Get the size of the data in bytes.
static MessageData from(T &t)
Cast from a type to its raw bytes.
detail::TypedReadOwnedCallback< SerialCoordOutputBatch > OutputCallback
QueuedDecodeTypeDeserializer(OutputCallback output)
std::vector< std::unique_ptr< SerialCoordOutputBatch > > DecodedOutputs
A ChannelPort which reads data from the accelerator.
virtual void connect(ReadCallback callback, const ConnectOptions &options={})
virtual void disconnect() override
Disconnect the channel.
virtual void read(MessageData &outData)
Specify a buffer to read into.
Abstract multi-segment message.
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
void write(const T &data)
A ChannelPort which sends data to the accelerator.
virtual void disconnect() override
void write(const MessageData &data)
A very basic blocking write API.
bool tryWrite(const MessageData &data)
A basic non-blocking write API.
virtual void connect(const ConnectOptions &options={}) override
Set up a connection to the accelerator.
A function call which gets attached to a service port.
A port which writes data to the accelerator (from_host).
A port which reads data from the accelerator (to_host).
A function call which gets attached to a service port.
virtual void start()
In cases where necessary, enable host memory services.
services::HostMemRegion HostMemRegion
RAII memory region for host memory. See services::HostMemRegion.
A "slice" of some parent MMIO space.
virtual uint64_t read(uint32_t addr) const
Read a 64-bit value from this region, not the global address space.
Information about the Accelerator system.
A telemetry port which gets attached to a service port.
void connect()
Connect to a particular telemetry port. Offset should be non-nullopt.
static void * alignedAllocCompat(std::size_t alignment, std::size_t size)
static void bandwidthReadTest(AcceleratorConnection *conn, Accelerator *acc, size_t width, size_t xferCount, bool checkData)
static void hostmemWriteTest(Accelerator *acc, esi::services::HostMem::HostMemRegion ®ion, uint32_t width)
Test the hostmem write functionality.
static void aggregateHostmemBandwidthTest(AcceleratorConnection *, Accelerator *, uint32_t width, uint32_t xferCount, bool read, bool write)
static void dmaTest(AcceleratorConnection *, Accelerator *, const std::vector< uint32_t > &widths, bool read, bool write)
static void hostmemBandwidthTest(AcceleratorConnection *conn, Accelerator *acc, uint32_t xferCount, const std::vector< uint32_t > &widths, bool read, bool write)
static void callbackTest(AcceleratorConnection *, Accelerator *, uint32_t iterations)
static uint64_t enginePayloadFold(uint32_t index, size_t bitWidth)
static void serialCoordTranslateTest(AcceleratorConnection *, Accelerator *, uint32_t xTrans, uint32_t yTrans, uint32_t numCoords, size_t batchSizeLimit)
static void bandwidthTest(AcceleratorConnection *, Accelerator *, const std::vector< uint32_t > &widths, uint32_t xferCount, bool read, bool write, bool checkData)
static std::vector< uint8_t > enginePatternBytes(uint32_t index, size_t bitWidth)
static void hostmemReadBandwidthTest(AcceleratorConnection *conn, Accelerator *acc, esi::services::HostMem::HostMemRegion ®ion, uint32_t width, uint32_t xferCount)
static void channelTest(AcceleratorConnection *, Accelerator *, uint32_t iterations)
static std::string formatBandwidth(double bytesPerSec)
static void autoSerialCoordTranslateTest(AcceleratorConnection *, Accelerator *, uint32_t xTrans, uint32_t yTrans, uint32_t numCoords)
static void hostmemWriteBandwidthTest(AcceleratorConnection *conn, Accelerator *acc, esi::services::HostMem::HostMemRegion ®ion, uint32_t width, uint32_t xferCount)
static void alignedFreeCompat(void *ptr)
static void dmaWriteTest(AcceleratorConnection *conn, Accelerator *acc, size_t width)
static uint8_t esitesterHostmemByte(uint32_t index, size_t byte, uint32_t width)
static void bandwidthWriteTest(AcceleratorConnection *conn, Accelerator *acc, size_t width, size_t xferCount, bool checkData)
static size_t hostmemWireBytes(uint32_t width)
static std::string humanBytes(uint64_t bytes)
static void checkBurstCommandRegisters(services::MMIO::MMIORegion &mmio, uint64_t address, uint64_t flits)
static uint8_t esitesterDataByte(uint32_t index, size_t byte)
static uint64_t esitesterElemFold(uint32_t i, uint32_t width)
static void streamingAddTest(AcceleratorConnection *, Accelerator *, uint32_t addAmt, uint32_t numItems)
Test the StreamingAdder module.
static void loopbackAddTest(AcceleratorConnection *, Accelerator *, uint32_t iterations, bool pipeline)
static void dmaReadTest(AcceleratorConnection *conn, Accelerator *acc, size_t width)
static void streamingAddTranslatedTest(AcceleratorConnection *, Accelerator *, uint32_t addAmt, uint32_t numItems)
static void hostmemTest(AcceleratorConnection *, Accelerator *, const std::vector< uint32_t > &widths, bool write, bool read)
static std::string humanTimeUS(uint64_t us)
static void coordTranslateTest(AcceleratorConnection *, Accelerator *, uint32_t xTrans, uint32_t yTrans, uint32_t numCoords)
static void resetTest(AcceleratorConnection *, Accelerator *)
constexpr std::array< uint32_t, 8 > defaultWidths
static uint8_t enginePatternByte(uint32_t index, size_t byte, size_t bitWidth)
static size_t engineWireBytes(size_t bitWidth)
static std::string defaultWidthsStr()
static constexpr uint64_t kEsitesterSeqSeed
static void hostmemReadTest(Accelerator *acc, esi::services::HostMem::HostMemRegion ®ion, uint32_t width)
const MessageData & getMessageDataRef(const SegmentedMessageData &msg, MessageData &scratch)
std::string toString(const std::any &a)
'Stringify' a std::any. This is used to log std::any values by some loggers.
std::string toHex(void *val)
Translated argument struct for CoordTranslator.
std::span< const Coord > coordsSpan() const
const Coord * coords() const
static size_t allocSize(size_t numCoords)
Coord * coords()
Get pointer to trailing coords array.
std::span< Coord > coordsSpan()
Get span view of coords (requires coordsLength to be set first).
Translated result struct for CoordTranslator.
static size_t allocSize(size_t numCoords)
std::span< Coord > coordsSpan()
Get span view of coords (requires coordsLength to be set first).
const Coord * coords() const
Coord * coords()
Get pointer to trailing coords array.
std::span< const Coord > coordsSpan() const
Test the CoordTranslator module using message translation.
void yTranslation(uint32_t yTrans)
void appendCoord(uint32_t x, uint32_t y)
std::vector< SerialCoordData > coords
void xTranslation(uint32_t xTrans)
Segment segment(size_t idx) const override
Get a segment by index. Throws if the segment has been take()n.
size_t numSegments() const override
Number of segments in the message.
SerialCoordData(uint32_t x, uint32_t y)
Deserialized result batch from the serial coord translator.
std::vector< Coord > coords
Packed struct representing a parallel window argument for StreamingAdder.
Packed struct representing a parallel window result for StreamingAdder.
Test the StreamingAdder module using message translation.
uint32_t * inputData()
Get pointer to trailing input data array.
static size_t allocSize(size_t numItems)
std::span< uint32_t > inputDataSpan()
Get span view of input data (requires inputLength to be set first).
std::span< const uint32_t > inputDataSpan() const
const uint32_t * inputData() const
Translated result struct for StreamingAdder.
uint32_t * data()
Get pointer to trailing result data array.
std::span< uint32_t > dataSpan()
Get span view of result data (requires dataLength to be set first).
static size_t allocSize(size_t numItems)
std::span< const uint32_t > dataSpan() const
const uint32_t * data() const
A contiguous, non-owning view of bytes within a SegmentedMessageData.
virtual std::size_t getSize() const =0
virtual void * getPtr() const =0
Get a pointer to the host memory.
virtual void flush()
Flush the memory region to ensure that the device sees the latest contents.
virtual void * getDevicePtr() const
Sometimes the pointer the device sees is different from the pointer the host sees.
SerialCoordOutputData data
SerialCoordOutputHeader header