CIRCT  20.0.0git
Trace.cpp
Go to the documentation of this file.
1 //===- Trace.cpp - Implementation of trace backend -----------------------===//
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 package. The source for this file
11 // should always be modified within CIRCT (lib/dialect/ESI/runtime/cpp/lib/).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "esi/backends/Trace.h"
16 
17 #include "esi/Accelerator.h"
18 #include "esi/Services.h"
19 #include "esi/Utils.h"
20 
21 #include <cassert>
22 #include <fstream>
23 #include <iostream>
24 #include <regex>
25 #include <sstream>
26 
27 using namespace esi;
28 using namespace esi::services;
29 using namespace esi::backends::trace;
30 
31 // We only support v0.
32 constexpr uint32_t ESIVersion = 0;
33 
34 namespace {
35 class TraceChannelPort;
36 }
37 
39  Impl(Mode mode, std::filesystem::path manifestJson,
40  std::filesystem::path traceFile)
41  : manifestJson(manifestJson), traceFile(traceFile) {
42  if (!std::filesystem::exists(manifestJson))
43  throw std::runtime_error("manifest file '" + manifestJson.string() +
44  "' does not exist");
45 
46  if (mode == Write) {
47  // Open the trace file for writing.
48  traceWrite = new std::ofstream(traceFile);
49  if (!traceWrite->is_open())
50  throw std::runtime_error("failed to open trace file '" +
51  traceFile.string() + "'");
52  } else if (mode == Discard) {
53  traceWrite = nullptr;
54  } else {
55  assert(false && "not implemented");
56  }
57  }
58 
59  ~Impl() {
60  if (traceWrite) {
61  traceWrite->close();
62  delete traceWrite;
63  }
64  }
65 
66  Service *createService(Service::Type svcType, AppIDPath idPath,
67  const ServiceImplDetails &details,
68  const HWClientDetails &clients);
69 
70  /// Request the host side channel ports for a particular instance (identified
71  /// by the AppID path). For convenience, provide the bundle type and direction
72  /// of the bundle port.
73  std::map<std::string, ChannelPort &> requestChannelsFor(AppIDPath,
74  const BundleType *);
75 
76  void adoptChannelPort(ChannelPort *port) { channels.emplace_back(port); }
77 
78  void write(const AppIDPath &id, const std::string &portName, const void *data,
79  size_t size, const std::string &prefix = "");
80  std::ostream &write(std::string service) {
81  assert(traceWrite && "traceWrite is null");
82  *traceWrite << "[" << service << "] ";
83  return *traceWrite;
84  }
85  bool isWriteable() { return traceWrite; }
86 
87 private:
88  std::ofstream *traceWrite;
89  std::filesystem::path manifestJson;
90  std::filesystem::path traceFile;
91  std::vector<std::unique_ptr<ChannelPort>> channels;
92 };
93 
94 void TraceAccelerator::Impl::write(const AppIDPath &id,
95  const std::string &portName,
96  const void *data, size_t size,
97  const std::string &prefix) {
98  if (!isWriteable())
99  return;
100  std::string b64data;
101  utils::encodeBase64(data, size, b64data);
102 
103  *traceWrite << prefix << (prefix.empty() ? "w" : "W") << "rite " << id << '.'
104  << portName << ": " << b64data << std::endl;
105 }
106 
107 std::unique_ptr<AcceleratorConnection>
108 TraceAccelerator::connect(Context &ctxt, std::string connectionString) {
109  std::string modeStr;
110  std::string manifestPath;
111  std::string traceFile = "trace.log";
112 
113  // Parse the connection std::string.
114  // <mode>:<manifest path>[:<traceFile>]
115  std::regex connPattern("([\\w-]):([^:]+)(:(\\w+))?");
116  std::smatch match;
117  if (regex_search(connectionString, match, connPattern)) {
118  modeStr = match[1];
119  manifestPath = match[2];
120  if (match[3].matched)
121  traceFile = match[3];
122  } else {
123  throw std::runtime_error("connection std::string must be of the form "
124  "'<mode>:<manifest path>[:<traceFile>]'");
125  }
126 
127  // Parse the mode.
128  Mode mode;
129  if (modeStr == "w")
130  mode = Write;
131  else if (modeStr == "-")
132  mode = Discard;
133  else
134  throw std::runtime_error("unknown mode '" + modeStr + "'");
135 
136  return std::make_unique<TraceAccelerator>(ctxt, mode,
137  std::filesystem::path(manifestPath),
138  std::filesystem::path(traceFile));
139 }
140 
141 TraceAccelerator::TraceAccelerator(Context &ctxt, Mode mode,
142  std::filesystem::path manifestJson,
143  std::filesystem::path traceFile)
145  impl = std::make_unique<Impl>(mode, manifestJson, traceFile);
146 }
148 
150  AppIDPath idPath, std::string implName,
151  const ServiceImplDetails &details,
152  const HWClientDetails &clients) {
153  return impl->createService(svcType, idPath, details, clients);
154 }
155 namespace {
156 class TraceSysInfo : public SysInfo {
157 public:
158  TraceSysInfo(std::filesystem::path manifestJson)
159  : manifestJson(manifestJson) {}
160 
161  uint32_t getEsiVersion() const override { return ESIVersion; }
162 
163  std::string getJsonManifest() const override {
164  // Read in the whole json file and return it.
165  std::ifstream manifest(manifestJson);
166  if (!manifest.is_open())
167  throw std::runtime_error("failed to open manifest file '" +
168  manifestJson.string() + "'");
169  std::stringstream buffer;
170  buffer << manifest.rdbuf();
171  manifest.close();
172  return buffer.str();
173  }
174 
175  std::vector<uint8_t> getCompressedManifest() const override {
176  throw std::runtime_error(
177  "compressed manifest not supported by trace backend");
178  }
179 
180 private:
181  std::filesystem::path manifestJson;
182 };
183 } // namespace
184 
185 namespace {
186 class WriteTraceChannelPort : public WriteChannelPort {
187 public:
188  WriteTraceChannelPort(TraceAccelerator::Impl &impl, const Type *type,
189  const AppIDPath &id, const std::string &portName)
190  : WriteChannelPort(type), impl(impl), id(id), portName(portName) {}
191 
192  virtual void write(const MessageData &data) override {
193  impl.write(id, portName, data.getBytes(), data.getSize());
194  }
195 
196  bool tryWrite(const MessageData &data) override {
197  impl.write(id, portName, data.getBytes(), data.getSize(), "try");
198  return true;
199  }
200 
201 protected:
203  AppIDPath id;
204  std::string portName;
205 };
206 } // namespace
207 
208 namespace {
209 class ReadTraceChannelPort : public ReadChannelPort {
210 public:
211  ReadTraceChannelPort(TraceAccelerator::Impl &impl, const Type *type)
212  : ReadChannelPort(type) {}
213  ~ReadTraceChannelPort() { disconnect(); }
214 
215 private:
216  MessageData genMessage() {
217  std::ptrdiff_t numBits = getType()->getBitWidth();
218  if (numBits < 0)
219  // TODO: support other types.
220  throw std::runtime_error("unsupported type for read: " +
221  getType()->getID());
222 
223  std::ptrdiff_t size = (numBits + 7) / 8;
224  std::vector<uint8_t> bytes(size);
225  for (std::ptrdiff_t i = 0; i < size; ++i)
226  bytes[i] = rand() % 256;
227  return MessageData(bytes);
228  }
229 
230  bool pollImpl() override { return callback(genMessage()); }
231 };
232 } // namespace
233 
234 namespace {
235 class TraceCustomService : public CustomService {
236 public:
237  TraceCustomService(TraceAccelerator::Impl &impl, AppIDPath idPath,
238  const ServiceImplDetails &details,
239  const HWClientDetails &clients)
240  : CustomService(idPath, details, clients) {}
241 };
242 } // namespace
243 
244 std::map<std::string, ChannelPort &>
246  const BundleType *bundleType) {
247  std::map<std::string, ChannelPort &> channels;
248  for (auto [name, dir, type] : bundleType->getChannels()) {
249  ChannelPort *port;
250  if (BundlePort::isWrite(dir))
251  port = new WriteTraceChannelPort(*this, type, idPath, name);
252  else
253  port = new ReadTraceChannelPort(*this, type);
254  channels.emplace(name, *port);
255  adoptChannelPort(port);
256  }
257  return channels;
258 }
259 
260 std::map<std::string, ChannelPort &> TraceAccelerator::requestChannelsFor(
261  AppIDPath idPath, const BundleType *bundleType, const ServiceTable &) {
262  return impl->requestChannelsFor(idPath, bundleType);
263 }
264 
265 class TraceMMIO : public MMIO {
266 public:
268 
269  virtual uint64_t read(uint32_t addr) const override {
270  uint64_t data = rand();
271  if (impl.isWriteable())
272  impl.write("MMIO") << "[" << std::hex << addr << "] -> " << data
273  << std::endl;
274  return data;
275  }
276  virtual void write(uint32_t addr, uint64_t data) override {
277  if (!impl.isWriteable())
278  return;
279  impl.write("MMIO") << "[" << std::hex << addr << "] <- " << data
280  << std::endl;
281  }
282 
283 private:
285 };
286 
287 class TraceHostMem : public HostMem {
288 public:
290 
293  : impl(impl) {
294  ptr = malloc(size);
295  this->size = size;
296  }
298  if (impl.isWriteable())
299  impl.write("HostMem") << "free " << ptr << std::endl;
300  free(ptr);
301  }
302  virtual void *getPtr() const override { return ptr; }
303  virtual std::size_t getSize() const override { return size; }
304 
305  private:
306  void *ptr;
307  std::size_t size;
309  };
310 
311  virtual std::unique_ptr<HostMemRegion>
312  allocate(std::size_t size, HostMem::Options opts) const override {
313  auto ret =
314  std::unique_ptr<HostMemRegion>(new TraceHostMemRegion(size, impl));
315  if (impl.isWriteable())
316  impl.write("HostMem 0x")
317  << ret->getPtr() << " allocate " << size
318  << " bytes. Writeable: " << opts.writeable
319  << ", useLargePages: " << opts.useLargePages << std::endl;
320  return ret;
321  }
322  virtual bool mapMemory(void *ptr, std::size_t size,
323  HostMem::Options opts) const override {
324 
325  if (impl.isWriteable())
326  impl.write("HostMem")
327  << "map 0x" << ptr << " size " << size
328  << " bytes. Writeable: " << opts.writeable
329  << ", useLargePages: " << opts.useLargePages << std::endl;
330  return true;
331  }
332  virtual void unmapMemory(void *ptr) const override {
333  if (impl.isWriteable())
334  impl.write("HostMem") << "unmap 0x" << ptr << std::endl;
335  }
336 
337 private:
339 };
340 
341 Service *
343  const ServiceImplDetails &details,
344  const HWClientDetails &clients) {
345  if (svcType == typeid(SysInfo))
346  return new TraceSysInfo(manifestJson);
347  if (svcType == typeid(MMIO))
348  return new TraceMMIO(*this);
349  if (svcType == typeid(HostMem))
350  return new TraceHostMem(*this);
351  if (svcType == typeid(CustomService))
352  return new TraceCustomService(*this, idPath, details, clients);
353  return nullptr;
354 }
355 
assert(baseType &&"element must be base type")
constexpr uint32_t ESIVersion
Definition: Trace.cpp:32
REGISTER_ACCELERATOR("trace", TraceAccelerator)
virtual std::unique_ptr< HostMemRegion > allocate(std::size_t size, HostMem::Options opts) const override
Allocate a region of host memory in accelerator accessible address space.
Definition: Trace.cpp:312
TraceHostMem(TraceAccelerator::Impl &impl)
Definition: Trace.cpp:289
virtual bool mapMemory(void *ptr, std::size_t size, HostMem::Options opts) const override
Try to make a region of host memory accessible to the accelerator.
Definition: Trace.cpp:322
virtual void unmapMemory(void *ptr) const override
Unmap memory which was previously mapped with 'mapMemory'.
Definition: Trace.cpp:332
TraceAccelerator::Impl & impl
Definition: Trace.cpp:338
virtual uint64_t read(uint32_t addr) const override
Read a 64-bit value from the global MMIO space.
Definition: Trace.cpp:269
virtual void write(uint32_t addr, uint64_t data) override
Write a 64-bit value to the global MMIO space.
Definition: Trace.cpp:276
TraceAccelerator::Impl & impl
Definition: Trace.cpp:284
TraceMMIO(TraceAccelerator::Impl &impl)
Definition: Trace.cpp:267
Abstract class representing a connection to an accelerator.
Definition: Accelerator.h:78
virtual void disconnect()
Disconnect from the accelerator cleanly.
std::map< std::string, services::Service * > ServiceTable
Definition: Accelerator.h:93
static bool isWrite(BundleType::Direction bundleDir)
Compute the direction of a channel given the bundle direction and the bundle port's direction.
Definition: Ports.h:188
Bundles represent a collection of channels.
Definition: Types.h:44
const ChannelVector & getChannels() const
Definition: Types.h:54
Unidirectional channels are the basic communication primitive between the host and accelerator.
Definition: Ports.h:33
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Definition: Context.h:31
A logical chunk of data representing serialized data.
Definition: Common.h:103
A ChannelPort which reads data from the accelerator.
Definition: Ports.h:103
Root class of the ESI type system.
Definition: Types.h:27
A ChannelPort which sends data to the accelerator.
Definition: Ports.h:74
Connect to an ESI simulation.
Definition: Trace.h:35
std::unique_ptr< Impl > impl
Definition: Trace.h:81
std::map< std::string, ChannelPort & > requestChannelsFor(AppIDPath, const BundleType *, const ServiceTable &) override
Request the host side channel ports for a particular instance (identified by the AppID path).
Definition: Trace.cpp:260
virtual Service * createService(Service::Type service, AppIDPath idPath, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients) override
Called by getServiceImpl exclusively.
Definition: Trace.cpp:149
A service for which there are no standard services registered.
Definition: Services.h:77
Parent class of all APIs modeled as 'services'.
Definition: Services.h:45
const std::type_info & Type
Definition: Services.h:47
Information about the Accelerator system.
Definition: Services.h:93
def connect(destination, source)
Definition: support.py:39
void encodeBase64(const void *data, size_t size, std::string &out)
Definition: Utils.cpp:23
Definition: esi.py:1
std::map< std::string, std::any > ServiceImplDetails
Definition: Common.h:98
std::vector< HWClientDetail > HWClientDetails
Definition: Common.h:97
virtual void * getPtr() const override
Definition: Trace.cpp:302
virtual std::size_t getSize() const override
Definition: Trace.cpp:303
TraceHostMemRegion(std::size_t size, TraceAccelerator::Impl &impl)
Definition: Trace.cpp:292
TraceAccelerator::Impl & impl
Definition: Trace.cpp:308
Service * createService(Service::Type svcType, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients)
Definition: Trace.cpp:342
std::vector< std::unique_ptr< ChannelPort > > channels
Definition: Trace.cpp:91
std::map< std::string, ChannelPort & > requestChannelsFor(AppIDPath, const BundleType *)
Request the host side channel ports for a particular instance (identified by the AppID path).
Definition: Trace.cpp:245
std::ostream & write(std::string service)
Definition: Trace.cpp:80
void adoptChannelPort(ChannelPort *port)
Definition: Trace.cpp:76
Impl(Mode mode, std::filesystem::path manifestJson, std::filesystem::path traceFile)
Definition: Trace.cpp:39
RAII memory region for host memory.
Definition: Services.h:201
Options for allocating host memory.
Definition: Services.h:209