34class TraceChannelPort;
46 throw std::runtime_error(
"manifest file '" +
manifestJson.string() +
53 throw std::runtime_error(
"failed to open trace file '" +
58 assert(
false &&
"not implemented");
75 void write(
const AppIDPath &
id,
const std::string &portName,
const void *data,
76 size_t size,
const std::string &prefix =
"");
77 std::ostream &
write(std::string service) {
88 std::vector<std::unique_ptr<ChannelPort>>
channels;
91void TraceAccelerator::Impl::write(
const AppIDPath &
id,
92 const std::string &portName,
93 const void *data,
size_t size,
94 const std::string &prefix) {
100 *
traceWrite << prefix << (prefix.empty() ?
"w" :
"W") <<
"rite " <<
id <<
'.'
101 << portName <<
": " << b64data << std::endl;
104std::unique_ptr<AcceleratorConnection>
106 std::string manifestPath;
107 std::string traceFile =
"trace.log";
115 constexpr char SEP =
';';
117 constexpr char SEP =
':';
120 if (connectionString.size() < 2 || connectionString[1] != SEP)
121 throw std::runtime_error(
122 std::string(
"connection string must be of the form ") +
"'<mode>" +
123 SEP +
"<manifest path>[" + SEP +
"<traceFile>]'");
125 char modeChar = connectionString[0];
126 std::string rest = connectionString.substr(2);
129 size_t lastSep = rest.rfind(SEP);
130 if (lastSep != std::string::npos) {
131 manifestPath = rest.substr(0, lastSep);
132 traceFile = rest.substr(lastSep + 1);
135 if (traceFile.empty())
136 throw std::runtime_error(
137 std::string(
"connection string must be of the form ") +
"'<mode>" +
138 SEP +
"<manifest path>[" + SEP +
140 "trace file name cannot be empty");
146 if (manifestPath.empty())
147 throw std::runtime_error(
148 std::string(
"connection string must be of the form ") +
"'<mode>" +
149 SEP +
"<manifest path>[" + SEP +
151 "manifest path cannot be empty");
157 else if (modeChar ==
'-')
160 throw std::runtime_error(
"unknown mode '" + std::string(1, modeChar) +
"'");
162 return std::make_unique<TraceAccelerator>(
ctxt, mode,
163 std::filesystem::path(manifestPath),
164 std::filesystem::path(traceFile));
168 std::filesystem::path manifestJson,
169 std::filesystem::path traceFile)
171 impl = std::make_unique<Impl>(mode, manifestJson, traceFile);
176class TraceSysInfo :
public SysInfo {
179 :
SysInfo(conn), manifestJson(manifestJson) {}
181 uint32_t getEsiVersion()
const override {
return ESIVersion; }
183 std::string getJsonManifest()
const override {
185 std::ifstream manifest(manifestJson);
186 if (!manifest.is_open())
187 throw std::runtime_error(
"failed to open manifest file '" +
188 manifestJson.string() +
"'");
189 std::stringstream buffer;
190 buffer << manifest.rdbuf();
195 std::vector<uint8_t> getCompressedManifest()
const override {
196 throw std::runtime_error(
197 "compressed manifest not supported by trace backend");
201 std::filesystem::path manifestJson;
209 const AppIDPath &
id,
const std::string &portName)
214 impl.write(
id, portName,
data.getBytes(),
data.getSize());
217 bool tryWriteImpl(
const MessageData &data)
override {
218 impl.write(
id, portName,
data.getBytes(),
data.getSize(),
"try");
224 std::string portName;
233 ~ReadTraceChannelPort() { disconnect(); }
237 std::ptrdiff_t numBits = getType()->getBitWidth();
240 throw std::runtime_error(
"unsupported type for read: " +
243 std::ptrdiff_t size = (numBits + 7) / 8;
247 std::vector<uint8_t> bytes(size);
248 for (std::ptrdiff_t i = 0; i < size; ++i)
249 bytes[i] = rand() % 256;
253 bool pollImpl()
override {
255 pendingMessage = std::make_unique<MessageData>(genMessage());
256 if (!invokeCallback(pendingMessage))
258 pendingMessage.reset();
262 std::unique_ptr<SegmentedMessageData> pendingMessage;
267class TraceEngine :
public Engine {
272 std::unique_ptr<ChannelPort> createPort(
AppIDPath idPath,
273 const std::string &channelName,
275 const Type *type)
override {
276 std::unique_ptr<ChannelPort> port;
277 if (BundlePort::isWrite(dir))
278 port = std::make_unique<WriteTraceChannelPort>(impl, type, idPath,
281 port = std::make_unique<ReadTraceChannelPort>(impl, type);
302 :
MMIO(conn, idPath, clients), impl(conn.getImpl()) {}
304 virtual uint64_t
read(uint32_t addr)
const override {
305 uint64_t data = rand();
306 if (impl.isWriteable())
307 impl.write(
"MMIO") <<
"[" << std::hex << addr <<
"] -> " << data
311 virtual void write(uint32_t addr, uint64_t data)
override {
312 if (!impl.isWriteable())
314 impl.write(
"MMIO") <<
"[" << std::hex << addr <<
"] <- " << data
333 if (impl.isWriteable())
334 impl.write(
"HostMem") <<
"free " << ptr << std::endl;
337 virtual void *
getPtr()
const override {
return ptr; }
338 virtual std::size_t
getSize()
const override {
return size; }
346 virtual std::unique_ptr<HostMemRegion>
350 if (impl.isWriteable())
351 impl.write(
"HostMem 0x")
352 << ret->getPtr() <<
" allocate " << size
353 <<
" bytes. Writeable: " << opts.
writeable
360 if (impl.isWriteable())
361 impl.write(
"HostMem")
362 <<
"map 0x" << ptr <<
" size " << size
363 <<
" bytes. Writeable: " << opts.
writeable
368 if (impl.isWriteable())
369 impl.write(
"HostMem") <<
"unmap 0x" << ptr << std::endl;
380 if (svcType ==
typeid(
SysInfo))
381 return new TraceSysInfo(*
this,
getImpl().manifestJson);
382 if (svcType ==
typeid(
MMIO))
383 return new TraceMMIO(*
this, idPath, clients);
384 if (svcType ==
typeid(
HostMem))
#define REGISTER_ACCELERATOR(Name, TAccelerator)
assert(baseType &&"element must be base type")
constexpr uint32_t ESIVersion
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.
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.