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 {
185 std::string getJsonManifest()
const override {
187 std::ifstream manifest(manifestJson);
188 if (!manifest.is_open())
189 throw std::runtime_error(
"failed to open manifest file '" +
190 manifestJson.string() +
"'");
191 std::stringstream buffer;
192 buffer << manifest.rdbuf();
197 std::vector<uint8_t> getCompressedManifest()
const override {
198 throw std::runtime_error(
199 "compressed manifest not supported by trace backend");
203 std::filesystem::path manifestJson;
208class WriteTraceChannelPort :
public WriteChannelPort {
210 WriteTraceChannelPort(TraceAccelerator::Impl &impl,
const Type *type,
211 const AppIDPath &
id,
const std::string &portName)
212 : WriteChannelPort(type), impl(impl), id(id), portName(portName) {}
215 void writeImpl(
const MessageData &data)
override {
216 impl.write(
id, portName,
data.getBytes(),
data.getSize());
219 bool tryWriteImpl(
const MessageData &data)
override {
220 impl.write(
id, portName,
data.getBytes(),
data.getSize(),
"try");
224 TraceAccelerator::Impl &impl;
226 std::string portName;
231class ReadTraceChannelPort :
public ReadChannelPort {
233 ReadTraceChannelPort(TraceAccelerator::Impl &impl,
const Type *type)
234 : ReadChannelPort(type) {}
235 ~ReadTraceChannelPort() { disconnect(); }
238 MessageData genMessage() {
239 std::ptrdiff_t numBits = getType()->getBitWidth();
242 throw std::runtime_error(
"unsupported type for read: " +
245 std::ptrdiff_t size = (numBits + 7) / 8;
248 return MessageData({0});
249 std::vector<uint8_t> bytes(size);
250 for (std::ptrdiff_t i = 0; i < size; ++i)
251 bytes[i] = rand() % 256;
252 return MessageData(bytes);
255 bool pollImpl()
override {
257 pendingMessage = std::make_unique<MessageData>(genMessage());
258 if (!invokeCallback(pendingMessage))
260 pendingMessage.reset();
264 std::unique_ptr<SegmentedMessageData> pendingMessage;
269class TraceEngine :
public Engine {
271 TraceEngine(AcceleratorConnection &conn, TraceAccelerator::Impl &impl)
272 : Engine(
conn), impl(impl) {}
274 std::unique_ptr<ChannelPort> createPort(AppIDPath idPath,
275 const std::string &channelName,
276 BundleType::Direction dir,
277 const Type *type)
override {
278 std::unique_ptr<ChannelPort> port;
279 if (BundlePort::isWrite(dir))
280 port = std::make_unique<WriteTraceChannelPort>(impl, type, idPath,
283 port = std::make_unique<ReadTraceChannelPort>(impl, type);
288 TraceAccelerator::Impl &impl;
306 virtual uint64_t
read(uint32_t addr)
const override {
307 uint64_t data = rand();
308 if (
impl.isWriteable())
309 impl.write(
"MMIO") <<
"[" << std::hex << addr <<
"] -> " << data
313 virtual void write(uint32_t addr, uint64_t data)
override {
314 if (!
impl.isWriteable())
316 impl.write(
"MMIO") <<
"[" << std::hex << addr <<
"] <- " << data
333 impl.write(
"HostMem") <<
"free " <<
ptr << std::endl;
345 virtual std::unique_ptr<HostMemRegion>
349 std::unique_ptr<HostMemRegion> ret(
new (std::nothrow)
351 if (!ret || !ret->getPtr())
353 if (
impl.isWriteable())
354 impl.write(
"HostMem 0x")
355 << ret->getPtr() <<
" allocate " << size
356 <<
" bytes. Writeable: " << opts.
writeable
363 if (
impl.isWriteable())
364 impl.write(
"HostMem")
365 <<
"map 0x" << ptr <<
" size " << size
366 <<
" bytes. Writeable: " << opts.
writeable
371 if (
impl.isWriteable())
372 impl.write(
"HostMem") <<
"unmap 0x" << ptr << std::endl;
383 if (svcType ==
typeid(
SysInfo))
384 return new TraceSysInfo(*
this,
getImpl().manifestJson);
385 if (svcType ==
typeid(
MMIO))
386 return new TraceMMIO(*
this, idPath, clients);
387 if (svcType ==
typeid(
HostMem))
#define REGISTER_ACCELERATOR(Name, TAccelerator)
assert(baseType &&"element must be base type")
if(parseOptionalKeywordOrOptionalString(parser, result.rawName, found)) return failure()
virtual std::unique_ptr< HostMemRegion > allocate(std::size_t size, HostMem::Options opts) const override
TraceHostMem(TraceAccelerator &conn)
virtual bool mapMemory(void *ptr, std::size_t size, HostMem::Options opts) const override
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.
services::Service Service
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.
AcceleratorConnection(Context &ctxt)
Unidirectional channels are the basic communication primitive between the host and accelerator.
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Class to parse a manifest.
uint32_t getApiVersion() const
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.
services::HostMemRegion HostMemRegion
RAII memory region for host memory. See services::HostMemRegion.
MMIO(AcceleratorConnection &, const AppIDPath &idPath, const HWClientDetails &clients)
const std::type_info & Type
AcceleratorConnection & conn
Information about the Accelerator system.
void encodeBase64(const void *data, size_t size, std::string &out)
std::vector< HWClientDetail > HWClientDetails
std::map< std::string, std::any > ServiceImplDetails
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
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)
friend class TraceAccelerator
Options for allocating host memory.