CIRCT  20.0.0git
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 
30 using namespace esi;
31 
33 static void dmaTest(AcceleratorConnection *, Accelerator *);
34 
35 int 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 
103  // Enable the host memory service.
104  auto hostmem = conn->getService<services::HostMem>();
105  hostmem->start();
106 
107  // Initiate a test read.
108  auto *readMem =
109  acc->getPorts().at(AppID("ReadMem")).getAs<services::MMIO::MMIORegion>();
110  uint64_t *dataPtr = new uint64_t;
111  *dataPtr = 0x12345678;
112  readMem->write(8, (uint64_t)dataPtr);
113 
114  // Wait for the accelerator to read the correct value. Timeout and fail after
115  // 10ms.
116  uint64_t val = 0;
117  for (int i = 0; i < 100; ++i) {
118  val = readMem->read(0);
119  if (val == *dataPtr)
120  break;
121  std::this_thread::sleep_for(std::chrono::microseconds(100));
122  }
123  if (val != *dataPtr)
124  throw std::runtime_error("DMA test failed");
125 }
Abstract class representing a connection to an accelerator.
Definition: Accelerator.h:78
Logger & getLogger() const
Definition: Accelerator.h:83
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
Definition: Accelerator.h:112
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
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
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: esitester.cpp:102
Definition: esi.py:1