31class TraceChannelPort;
43 throw std::runtime_error(
"manifest file '" +
manifestJson.string() +
50 throw std::runtime_error(
"failed to open trace file '" +
55 assert(
false &&
"not implemented");
72 void write(
const AppIDPath &
id,
const std::string &portName,
const void *data,
73 size_t size,
const std::string &prefix =
"");
74 std::ostream &
write(std::string service) {
85 std::vector<std::unique_ptr<ChannelPort>>
channels;
88void TraceAccelerator::Impl::write(
const AppIDPath &
id,
89 const std::string &portName,
90 const void *data,
size_t size,
91 const std::string &prefix) {
97 *
traceWrite << prefix << (prefix.empty() ?
"w" :
"W") <<
"rite " <<
id <<
'.'
98 << portName <<
": " << b64data << std::endl;
101std::unique_ptr<AcceleratorConnection>
103 std::string manifestPath;
104 std::string traceFile =
"trace.log";
112 constexpr char SEP =
';';
114 constexpr char SEP =
':';
117 if (connectionString.size() < 2 || connectionString[1] != SEP)
118 throw std::runtime_error(
119 std::string(
"connection string must be of the form ") +
"'<mode>" +
120 SEP +
"<manifest path>[" + SEP +
"<traceFile>]'");
122 char modeChar = connectionString[0];
123 std::string rest = connectionString.substr(2);
126 size_t lastSep = rest.rfind(SEP);
127 if (lastSep != std::string::npos) {
128 manifestPath = rest.substr(0, lastSep);
129 traceFile = rest.substr(lastSep + 1);
132 if (traceFile.empty())
133 throw std::runtime_error(
134 std::string(
"connection string must be of the form ") +
"'<mode>" +
135 SEP +
"<manifest path>[" + SEP +
137 "trace file name cannot be empty");
143 if (manifestPath.empty())
144 throw std::runtime_error(
145 std::string(
"connection string must be of the form ") +
"'<mode>" +
146 SEP +
"<manifest path>[" + SEP +
148 "manifest path cannot be empty");
154 else if (modeChar ==
'-')
157 throw std::runtime_error(
"unknown mode '" + std::string(1, modeChar) +
"'");
159 return std::make_unique<TraceAccelerator>(
ctxt, mode,
160 std::filesystem::path(manifestPath),
161 std::filesystem::path(traceFile));
165 std::filesystem::path manifestJson,
166 std::filesystem::path traceFile)
168 impl = std::make_unique<Impl>(mode, manifestJson, traceFile);
173class TraceSysInfo :
public SysInfo {
176 :
SysInfo(conn), manifestJson(manifestJson) {}
178 uint32_t getEsiVersion()
const override {
182 std::string getJsonManifest()
const override {
184 std::ifstream manifest(manifestJson);
185 if (!manifest.is_open())
186 throw std::runtime_error(
"failed to open manifest file '" +
187 manifestJson.string() +
"'");
188 std::stringstream buffer;
189 buffer << manifest.rdbuf();
194 std::vector<uint8_t> getCompressedManifest()
const override {
195 throw std::runtime_error(
196 "compressed manifest not supported by trace backend");
200 std::filesystem::path manifestJson;
208 const AppIDPath &
id,
const std::string &portName)
213 impl.write(
id, portName,
data.getBytes(),
data.getSize());
216 bool tryWriteImpl(
const MessageData &data)
override {
217 impl.write(
id, portName,
data.getBytes(),
data.getSize(),
"try");
223 std::string portName;
232 ~ReadTraceChannelPort() { disconnect(); }
236 std::ptrdiff_t numBits = getType()->getBitWidth();
239 throw std::runtime_error(
"unsupported type for read: " +
242 std::ptrdiff_t size = (numBits + 7) / 8;
246 std::vector<uint8_t> bytes(size);
247 for (std::ptrdiff_t i = 0; i < size; ++i)
248 bytes[i] = rand() % 256;
252 bool pollImpl()
override {
254 pendingMessage = std::make_unique<MessageData>(genMessage());
255 if (!invokeCallback(pendingMessage))
257 pendingMessage.reset();
261 std::unique_ptr<SegmentedMessageData> pendingMessage;
266class TraceEngine :
public Engine {
271 std::unique_ptr<ChannelPort> createPort(
AppIDPath idPath,
272 const std::string &channelName,
274 const Type *type)
override {
275 std::unique_ptr<ChannelPort> port;
276 if (BundlePort::isWrite(dir))
277 port = std::make_unique<WriteTraceChannelPort>(impl, type, idPath,
280 port = std::make_unique<ReadTraceChannelPort>(impl, type);
301 :
MMIO(conn, idPath, clients), impl(conn.getImpl()) {}
303 virtual uint64_t
read(uint32_t addr)
const override {
304 uint64_t data = rand();
305 if (impl.isWriteable())
306 impl.write(
"MMIO") <<
"[" << std::hex << addr <<
"] -> " << data
310 virtual void write(uint32_t addr, uint64_t data)
override {
311 if (!impl.isWriteable())
313 impl.write(
"MMIO") <<
"[" << std::hex << addr <<
"] <- " << data
332 if (impl.isWriteable())
333 impl.write(
"HostMem") <<
"free " << ptr << std::endl;
336 virtual void *
getPtr()
const override {
return ptr; }
337 virtual std::size_t
getSize()
const override {
return size; }
345 virtual std::unique_ptr<HostMemRegion>
349 if (impl.isWriteable())
350 impl.write(
"HostMem 0x")
351 << ret->getPtr() <<
" allocate " << size
352 <<
" bytes. Writeable: " << opts.
writeable
359 if (impl.isWriteable())
360 impl.write(
"HostMem")
361 <<
"map 0x" << ptr <<
" size " << size
362 <<
" bytes. Writeable: " << opts.
writeable
367 if (impl.isWriteable())
368 impl.write(
"HostMem") <<
"unmap 0x" << ptr << std::endl;
379 if (svcType ==
typeid(
SysInfo))
380 return new TraceSysInfo(*
this,
getImpl().manifestJson);
381 if (svcType ==
typeid(
MMIO))
382 return new TraceMMIO(*
this, idPath, clients);
383 if (svcType ==
typeid(
HostMem))
#define REGISTER_ACCELERATOR(Name, TAccelerator)
assert(baseType &&"element must be base type")
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.
TraceHostMem(TraceAccelerator &conn)
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.
virtual void unmapMemory(void *ptr) const override
Unmap memory which was previously mapped with 'mapMemory'.
TraceAccelerator::Impl & impl
TraceMMIO(TraceAccelerator &conn, const AppIDPath &idPath, const HWClientDetails &clients)
virtual uint64_t read(uint32_t addr) const override
Read a 64-bit value from the global MMIO space.
virtual void write(uint32_t addr, uint64_t data) override
Write a 64-bit value to the global MMIO space.
TraceAccelerator::Impl & impl
Abstract class representing a connection to an accelerator.
Context & ctxt
ESI accelerator context.
void registerEngine(AppIDPath idPath, std::unique_ptr< Engine > engine, const HWClientDetails &clients)
If createEngine is overridden, this method should be called to register the engine and all of the cha...
virtual void disconnect()
Disconnect from the accelerator cleanly.
Unidirectional channels are the basic communication primitive between the host and accelerator.
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Engines implement the actual channel communication between the host and the accelerator.
Class to parse a manifest.
uint32_t getApiVersion() const
A concrete flat message backed by a single vector of bytes.
A ChannelPort which reads data from the accelerator.
Root class of the ESI type system.
A ChannelPort which sends data to the accelerator.
Connect to an ESI simulation.
std::unique_ptr< Impl > impl
TraceAccelerator(Context &, Mode mode, std::filesystem::path manifestJson, std::filesystem::path traceFile)
Create a trace-based accelerator backend.
void createEngine(const std::string &engineTypeName, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients) override
Create a new engine for channel communication with the accelerator.
~TraceAccelerator() override
virtual Service * createService(Service::Type service, AppIDPath idPath, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients) override
Called by getServiceImpl exclusively.
static std::unique_ptr< AcceleratorConnection > connect(Context &, std::string connectionString)
Parse the connection string and instantiate the accelerator.
Parent class of all APIs modeled as 'services'.
const std::type_info & Type
Information about the Accelerator system.
void encodeBase64(const void *data, size_t size, std::string &out)
std::map< std::string, std::any > ServiceImplDetails
std::vector< HWClientDetail > HWClientDetails
virtual std::size_t getSize() const override
TraceHostMemRegion(std::size_t size, TraceAccelerator::Impl &impl)
virtual ~TraceHostMemRegion()
virtual void * getPtr() const override
Get a pointer to the host memory.
TraceAccelerator::Impl & impl
std::ofstream * traceWrite
void write(const AppIDPath &id, const std::string &portName, const void *data, size_t size, const std::string &prefix="")
std::vector< std::unique_ptr< ChannelPort > > channels
std::filesystem::path manifestJson
std::ostream & write(std::string service)
void adoptChannelPort(ChannelPort *port)
Service * createService(TraceAccelerator &conn, Service::Type svcType, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients)
std::filesystem::path traceFile
Impl(Mode mode, std::filesystem::path manifestJson, std::filesystem::path traceFile)
RAII memory region for host memory.
Options for allocating host memory.