CIRCT 20.0.0git
Loading...
Searching...
No Matches
esitester.cpp
Go to the documentation of this file.
1//===- esitester.cpp - ESI accelerator test/example tool ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// DO NOT EDIT!
10// This file is distributed as part of an ESI runtime package. The source for
11// this file should always be modified within CIRCT
12// (lib/dialect/ESI/runtime/cpp/tools/esitester.cpp).
13//
14//===----------------------------------------------------------------------===//
15//
16// This application isn't a utility so much as a test driver for an ESI system.
17// It is also useful as an example of how to use the ESI C++ API. esiquery.cpp
18// is also useful as an example.
19//
20//===----------------------------------------------------------------------===//
21
22#include "esi/Accelerator.h"
23#include "esi/Manifest.h"
24#include "esi/Services.h"
25
26#include <iostream>
27#include <map>
28#include <stdexcept>
29
30using namespace esi;
31
34
35int main(int argc, const char *argv[]) {
36 // TODO: find a command line parser library rather than doing this by hand.
37 if (argc < 3) {
38 std::cerr << "Expected usage: " << argv[0]
39 << " <backend> <connection specifier> [command]" << std::endl;
40 return -1;
41 }
42
43 const char *backend = argv[1];
44 const char *conn = argv[2];
45 std::string cmd;
46 if (argc > 3)
47 cmd = argv[3];
48
49 try {
50 Context ctxt = Context::withLogger<StreamLogger>(Logger::Level::Debug);
51 std::unique_ptr<AcceleratorConnection> acc = ctxt.connect(backend, conn);
52 const auto &info = *acc->getService<services::SysInfo>();
53 Manifest manifest(ctxt, info.getJsonManifest());
54 Accelerator *accel = manifest.buildAccelerator(*acc);
55 acc->getServiceThread()->addPoll(*accel);
56
57 registerCallbacks(acc.get(), accel);
58
59 if (cmd == "loop") {
60 while (true) {
61 std::this_thread::sleep_for(std::chrono::milliseconds(100));
62 }
63 } else if (cmd == "wait") {
64 std::this_thread::sleep_for(std::chrono::seconds(1));
65 } else if (cmd == "dmatest") {
66 dmaTest(acc.get(), accel);
67 }
68
69 acc->disconnect();
70 std::cerr << "Exiting successfully\n";
71 return 0;
72
73 } catch (std::exception &e) {
74 std::cerr << "Error: " << e.what() << std::endl;
75 return -1;
76 }
77}
78
80 auto ports = accel->getPorts();
81 auto f = ports.find(AppID("PrintfExample"));
82 if (f != ports.end()) {
83 auto callPort = f->second.getAs<services::CallService::Callback>();
84 if (callPort)
85 callPort->connect(
86 [conn](const MessageData &data) -> MessageData {
87 conn->getLogger().debug(
88 [&](std::string &subsystem, std::string &msg,
89 std::unique_ptr<std::map<std::string, std::any>> &details) {
90 subsystem = "ESITESTER";
91 msg = "Received PrintfExample message";
92 details = std::make_unique<std::map<std::string, std::any>>();
93 details->emplace("data", data);
94 });
95 std::cout << "PrintfExample: " << *data.as<uint32_t>() << std::endl;
96 return MessageData();
97 },
98 true);
99 }
100}
101
102void dmaTest(Accelerator *acc, uint64_t *dataPtr, uint32_t width) {
103 std::cout << "Running DMA test with width " << width << std::endl;
104
105 // Initiate a test read.
106 auto *readMem = acc->getChildren()
107 .at(AppID("readmem", width))
108 ->getPorts()
109 .at(AppID("ReadMem"))
111
112 for (size_t i = 0; i < 8; ++i) {
113 dataPtr[0] = 0x12345678 << i;
114 dataPtr[1] = 0xDEADBEEF << i;
115 readMem->write(8, (uint64_t)dataPtr);
116
117 // Wait for the accelerator to read the correct value. Timeout and fail
118 // after 10ms.
119 uint64_t val = 0;
120 uint64_t expected = dataPtr[0];
121 if (width < 64)
122 expected &= ((1ull << width) - 1);
123 for (int i = 0; i < 100; ++i) {
124 val = readMem->read(0);
125 if (val == expected)
126 break;
127 std::this_thread::sleep_for(std::chrono::microseconds(100));
128 }
129
130 if (val != expected)
131 throw std::runtime_error("DMA read test failed. Expected " +
132 std::to_string(expected) + ", got " +
133 std::to_string(val));
134 }
135
136 // Initiate a test write.
137 auto *writeMem =
138 acc->getPorts().at(AppID("WriteMem")).getAs<services::MMIO::MMIORegion>();
139 *dataPtr = 0;
140 writeMem->write(0, (uint64_t)dataPtr);
141 // Wait for the accelerator to write. Timeout and fail after 10ms.
142 for (int i = 0; i < 100; ++i) {
143 if (*dataPtr != 0)
144 break;
145 std::this_thread::sleep_for(std::chrono::microseconds(100));
146 }
147 if (*dataPtr == 0)
148 throw std::runtime_error("DMA write test failed");
149}
150
152 // Enable the host memory service.
153 auto hostmem = conn->getService<services::HostMem>();
154 hostmem->start();
155 auto scratchRegion = hostmem->allocate(/*size(bytes)=*/32, /*memOpts=*/{});
156 uint64_t *dataPtr = static_cast<uint64_t *>(scratchRegion->getPtr());
157
158 dmaTest(acc, dataPtr, 32);
159 dmaTest(acc, dataPtr, 64);
160 dmaTest(acc, dataPtr, 96);
161}
Abstract class representing a connection to an accelerator.
Definition Accelerator.h:78
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
Logger & getLogger() const
Definition Accelerator.h:83
Top level accelerator class.
Definition Accelerator.h:59
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Definition Context.h:31
const std::map< AppID, const BundlePort & > & getPorts() const
Access the module's ports by ID.
Definition Design.h:76
const std::map< AppID, Instance * > & getChildren() const
Access the module's children by ID.
Definition Design.h:67
void debug(const std::string &subsystem, const std::string &msg, const std::map< std::string, std::any > *details=nullptr)
Report a debug message.
Definition Logging.h:79
Class to parse a manifest.
Definition Manifest.h:39
A logical chunk of data representing serialized data.
Definition Common.h:103
A function call which gets attached to a service port.
Definition Services.h:288
void connect(std::function< MessageData(const MessageData &)> callback, bool quick=false)
Connect a callback to code which will be executed when the accelerator invokes the callback.
Definition Services.cpp:271
virtual void start()
In cases where necessary, enable host memory services.
Definition Services.h:215
A "slice" of some parent MMIO space.
Definition Services.h:155
virtual void write(uint32_t addr, uint64_t data)
Write a 64-bit value to this region, not the global address space.
Definition Services.cpp:131
Information about the Accelerator system.
Definition Services.h:93
static void registerCallbacks(AcceleratorConnection *, Accelerator *)
Definition esitester.cpp:79
int main(int argc, const char *argv[])
Definition esitester.cpp:35
static void dmaTest(AcceleratorConnection *, Accelerator *)
Definition esi.py:1