CIRCT 24.0.0git
Loading...
Searching...
No Matches
Accelerator.h
Go to the documentation of this file.
1//===- Accelerator.h - Base ESI runtime API ---------------------*- C++ -*-===//
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// Basic ESI APIs. The 'Accelerator' class is the superclass for all accelerator
10// backends. It should (usually) provide enough functionality such that users do
11// not have to interact with the platform-specific backend implementation with
12// the exception of connecting to the accelerator.
13//
14// DO NOT EDIT!
15// This file is distributed as part of an ESI package. The source for this file
16// should always be modified within CIRCT.
17//
18//===----------------------------------------------------------------------===//
19
20// NOLINTNEXTLINE(llvm-header-guard)
21#ifndef ESI_ACCELERATOR_H
22#define ESI_ACCELERATOR_H
23
24#include "esi/Context.h"
25#include "esi/Design.h"
26#include "esi/Engines.h"
27#include "esi/Manifest.h"
28#include "esi/Ports.h"
29#include "esi/Services.h"
30
31#include <atomic>
32#include <functional>
33#include <future>
34#include <map>
35#include <memory>
36#include <mutex>
37#include <string>
38#include <thread>
39#include <tuple>
40#include <typeinfo>
41#include <utility>
42#include <vector>
43
44namespace esi {
45// Forward declarations.
46class AcceleratorServiceThread;
47
48//===----------------------------------------------------------------------===//
49// Metadata constants which may or may not be used by various backends. Provided
50// here since they are intended to be somewhat standard.
51//===----------------------------------------------------------------------===//
52
53constexpr uint32_t MetadataOffset = 8;
54
55constexpr uint64_t MagicNumberLo = 0xE5100E51;
56constexpr uint64_t MagicNumberHi = 0x207D98E5;
57constexpr uint64_t MagicNumber = MagicNumberLo | (MagicNumberHi << 32);
58constexpr uint64_t MagicNumberOffset = 0;
59
60/// Keep in sync with circt::esi::esiApiVersion and the PyCDE BSP.
61constexpr uint32_t ExpectedVersionNumber = 1;
62constexpr uint64_t VersionNumberOffset = 8;
63
64constexpr uint32_t ManifestPtrOffset = 0x10;
65
66constexpr uint32_t CycleCountOffset = 0x20;
67constexpr uint32_t CoreFreqOffset = 0x28;
68
69/// Magic value which, when written to MMIO offset `ResetRequestOffset`,
70/// requests a design reset. Keep in sync with 'ResetMagicNumber' in the PyCDE
71/// BSP (python/esiaccel/bsp/common.py).
72constexpr uint64_t ResetMagicNumber = 0x00000E510000B007;
73/// Offset into the (global) MMIO space at which to request a design reset.
74constexpr uint32_t ResetRequestOffset = 0x38;
75
76//===----------------------------------------------------------------------===//
77// Accelerator design hierarchy root.
78//===----------------------------------------------------------------------===//
79
80/// Top level accelerator class. Maintains a shared pointer to the manifest,
81/// which owns objects used in the design hierarchy owned by this class. Since
82/// this class owns the entire design hierarchy, when it gets destroyed the
83/// entire design hierarchy gets destroyed so all of the instances, ports, etc.
84/// are no longer valid pointers.
85class Accelerator : public HWModule {
86public:
87 Accelerator() = delete;
88 Accelerator(const Accelerator &) = delete;
89 ~Accelerator() = default;
90 Accelerator(std::optional<ModuleInfo> info,
91 std::vector<std::unique_ptr<Instance>> children,
92 std::vector<services::Service *> services,
93 std::vector<std::unique_ptr<BundlePort>> &&ports)
94 : HWModule(info, std::move(children), services, std::move(ports)) {}
95};
96
97//===----------------------------------------------------------------------===//
98// Connection to the accelerator and its services.
99//===----------------------------------------------------------------------===//
100
101/// Abstract class representing a connection to an accelerator. Actual
102/// connections (e.g. to a co-simulation or actual device) are implemented by
103/// subclasses. No methods in here are thread safe.
105public:
107 virtual ~AcceleratorConnection();
108 Context &getCtxt() const { return ctxt; }
109 Logger &getLogger() const { return ctxt.getLogger(); }
110
111 /// Disconnect from the accelerator cleanly. Drains owned engines before the
112 /// accelerator is released. Backends _must_ call this from their destructor
113 /// while still fully constructed (their vtable/resources alive), since engine
114 /// teardown may reference accelerator-owned objects. Must be idempotent.
115 virtual void disconnect();
116
117 /// Request a reset of the accelerator design. Returns true if the reset was
118 /// successfully requested, false if it could not be performed for any reason
119 /// -- most commonly because the backend (BSP) does not support resets.
120 virtual bool reset();
121
122 /// Return a pointer to the accelerator 'service' thread (or threads). If the
123 /// thread(s) are not running, they will be started when this method is
124 /// called. `std::thread` is used. If users don't want the runtime to spin up
125 /// threads, don't call this method. `AcceleratorServiceThread` is owned by
126 /// AcceleratorConnection and governed by the lifetime of the this object.
128
130 /// Get a typed reference to a particular service type. Caller does *not* take
131 /// ownership of the returned pointer -- the Accelerator object owns it.
132 /// Pointer lifetime ends with the Accelerator lifetime.
133 template <typename ServiceClass>
134 ServiceClass *getService(AppIDPath id = {}, std::string implName = {},
135 ServiceImplDetails details = {},
136 HWClientDetails clients = {}) {
137 return dynamic_cast<ServiceClass *>(
138 getService(typeid(ServiceClass), id, implName, details, clients));
139 }
140 /// Calls `createService` and caches the result. Subclasses can override if
141 /// they want to use their own caching mechanism.
142 virtual Service *getService(Service::Type service, AppIDPath id = {},
143 std::string implName = {},
144 ServiceImplDetails details = {},
145 HWClientDetails clients = {});
146
147 /// Assume ownership of an accelerator object. Ties the lifetime of the
148 /// accelerator to this connection. Returns a raw pointer to the object.
149 Accelerator *takeOwnership(std::unique_ptr<Accelerator> accel);
150
151 /// Create a new engine for channel communication with the accelerator. The
152 /// default is to call the global `createEngine` to get an engine which has
153 /// registered itself. Individual accelerator connection backends can override
154 /// this to customize behavior.
155 virtual void createEngine(const std::string &engineTypeName, AppIDPath idPath,
156 const ServiceImplDetails &details,
157 const HWClientDetails &clients);
159 return clientEngines[id];
160 }
161
163 if (!ownedAccelerator)
164 throw std::runtime_error(
165 "AcceleratorConnection does not own an accelerator");
166 return *ownedAccelerator;
167 }
168
169protected:
170 /// If `createEngine` is overridden, this method should be called to register
171 /// the engine and all of the channels it services.
172 void registerEngine(AppIDPath idPath, std::unique_ptr<Engine> engine,
173 const HWClientDetails &clients);
174
175 /// Drop accelerator-owned objects before a derived backend destroys resources
176 /// that those objects may reference.
177 void clearOwnedObjects();
178
179 /// Called by `getServiceImpl` exclusively. It wraps the pointer returned by
180 /// this in a unique_ptr and caches it. Separate this from the
181 /// wrapping/caching since wrapping/caching is an implementation detail.
183 std::string implName,
184 const ServiceImplDetails &details,
185 const HWClientDetails &clients) = 0;
186
187 /// Collection of owned engines.
188 std::map<AppIDPath, std::unique_ptr<Engine>> ownedEngines;
189 /// Mapping of clients to their servicing engines.
190 std::map<AppIDPath, BundleEngineMap> clientEngines;
191
192private:
193 /// ESI accelerator context.
195
196 /// Cache services via a unique_ptr so they get free'd automatically when
197 /// Accelerator objects get deconstructed.
198 using ServiceCacheKey = std::tuple<std::string, AppIDPath>;
199 std::map<ServiceCacheKey, std::unique_ptr<Service>> serviceCache;
200
201 std::unique_ptr<AcceleratorServiceThread> serviceThread;
202
203 /// Accelerator object owned by this connection.
204 std::unique_ptr<Accelerator> ownedAccelerator;
205};
206
207namespace registry {
208
209namespace internal {
210
211/// Backends can register themselves to be connected via a connection string.
212using BackendCreate = std::function<std::unique_ptr<AcceleratorConnection>(
213 Context &, std::string)>;
214void registerBackend(const std::string &name, BackendCreate create);
215
216// Helper struct to
217template <typename TAccelerator>
219 RegisterAccelerator(const char *name) {
220 registerBackend(name, &TAccelerator::connect);
221 }
222};
223
224#define REGISTER_ACCELERATOR(Name, TAccelerator) \
225 static ::esi::registry::internal::RegisterAccelerator<TAccelerator> \
226 __register_accel____LINE__(Name)
227
228} // namespace internal
229} // namespace registry
230
231/// Background thread which services various requests. Currently, it listens on
232/// ports and calls callbacks for incoming messages on said ports.
233///
234/// All methods are virtual so that users may provide their own service thread
235/// implementation. Overriders can reuse the default implementation piecemeal by
236/// invoking the base-class methods -- typically overriding `poll()` (to change
237/// what a single iteration does) or `loop()` (to change how iterations are
238/// scheduled). Subclasses that need to run their own `loop()` from the outset
239/// should use the protected `DeferStart` constructor to prevent the base class
240/// from starting the thread, then call `start()` themselves.
242public:
245
246 /// When there's data on any of the listenPorts, call the callback. Callable
247 /// from any thread.
248 virtual void
249 addListener(std::initializer_list<ReadChannelPort *> listenPorts,
250 std::function<void(ReadChannelPort *, MessageData)> callback);
251
252 /// Poll this module.
253 virtual void addPoll(HWModule &module);
254
255 /// Add a task to be invoked on every service iteration. Callable from any
256 /// thread.
257 virtual void addTask(std::function<void(void)> task);
258
259 /// Instruct the service thread to stop running.
260 virtual void stop();
261
262protected:
263 /// Tag type used to construct the base class without starting the service
264 /// thread. Intended for subclasses that need to run their own loop from the
265 /// start.
266 struct DeferStart {};
268
269 /// Start the service thread. Called by the default constructor. Spawns a
270 /// std::thread which invokes `loop()` via virtual dispatch.
271 virtual void start();
272
273 /// The main service loop. Runs until `shutdown` is set to true. The default
274 /// implementation yields and then calls `poll()` on every iteration.
275 virtual void loop();
276
277 /// Perform a single iteration of servicing: drain any ready listener
278 /// futures, invoke their callbacks, and run all registered tasks.
279 /// Overriders can invoke this from a custom loop to reuse the default
280 /// servicing behavior.
281 virtual void poll();
282
283 /// Set to true to request the service loop to exit.
284 std::atomic<bool> shutdown{false};
285 /// The thread running `loop()`.
286 std::thread me;
287
288 /// Protects `listeners` and `taskList`.
289 std::mutex m;
290
291 /// Map of read ports to callbacks and their in-flight async reads.
292 std::map<ReadChannelPort *,
293 std::pair<std::function<void(ReadChannelPort *, MessageData)>,
294 std::future<MessageData>>>
296
297 /// Tasks which should be called on every loop iteration.
298 std::vector<std::function<void(void)>> taskList;
299};
300} // namespace esi
301
302#endif // ESI_ACCELERATOR_H
Abstract class representing a connection to an accelerator.
std::tuple< std::string, AppIDPath > ServiceCacheKey
Cache services via a unique_ptr so they get free'd automatically when Accelerator objects get deconst...
virtual Service * createService(Service::Type service, AppIDPath idPath, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients)=0
Called by getServiceImpl exclusively.
services::Service Service
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
Context & getCtxt() const
virtual bool reset()
Request a reset of the accelerator design.
void clearOwnedObjects()
Drop accelerator-owned objects before a derived backend destroys resources that those objects may ref...
std::map< AppIDPath, BundleEngineMap > clientEngines
Mapping of clients to their servicing engines.
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...
std::map< ServiceCacheKey, std::unique_ptr< Service > > serviceCache
std::unique_ptr< AcceleratorServiceThread > serviceThread
std::unique_ptr< Accelerator > ownedAccelerator
Accelerator object owned by this connection.
virtual void disconnect()
Disconnect from the accelerator cleanly.
std::map< AppIDPath, std::unique_ptr< Engine > > ownedEngines
Collection of owned engines.
Accelerator & getAccelerator()
virtual void createEngine(const std::string &engineTypeName, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients)
Create a new engine for channel communication with the accelerator.
virtual const BundleEngineMap & getEngineMapFor(AppIDPath id)
Logger & getLogger() const
virtual AcceleratorServiceThread * getServiceThread()
Return a pointer to the accelerator 'service' thread (or threads).
Accelerator * takeOwnership(std::unique_ptr< Accelerator > accel)
Assume ownership of an accelerator object.
Background thread which services various requests.
virtual void stop()
Instruct the service thread to stop running.
virtual void poll()
Perform a single iteration of servicing: drain any ready listener futures, invoke their callbacks,...
virtual void addPoll(HWModule &module)
Poll this module.
virtual void start()
Start the service thread.
std::map< ReadChannelPort *, std::pair< std::function< void(ReadChannelPort *, MessageData)>, std::future< MessageData > > > listeners
Map of read ports to callbacks and their in-flight async reads.
virtual void addListener(std::initializer_list< ReadChannelPort * > listenPorts, std::function< void(ReadChannelPort *, MessageData)> callback)
When there's data on any of the listenPorts, call the callback.
std::mutex m
Protects listeners and taskList.
std::atomic< bool > shutdown
Set to true to request the service loop to exit.
std::thread me
The thread running loop().
virtual void addTask(std::function< void(void)> task)
Add a task to be invoked on every service iteration.
virtual void loop()
The main service loop.
std::vector< std::function< void(void)> > taskList
Tasks which should be called on every loop iteration.
Top level accelerator class.
Definition Accelerator.h:85
Accelerator(std::optional< ModuleInfo > info, std::vector< std::unique_ptr< Instance > > children, std::vector< services::Service * > services, std::vector< std::unique_ptr< BundlePort > > &&ports)
Definition Accelerator.h:90
~Accelerator()=default
Accelerator()=delete
Accelerator(const Accelerator &)=delete
Since engines can support multiple channels BUT not necessarily all of the channels in a bundle,...
Definition Engines.h:76
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Definition Context.h:34
Logger & getLogger()
Definition Context.h:69
Represents either the top level or an instance of a hardware module.
Definition Design.h:47
const std::optional< ModuleInfo > info
Definition Design.h:101
const std::vector< std::unique_ptr< BundlePort > > ports
Definition Design.h:105
const std::vector< std::unique_ptr< Instance > > children
Definition Design.h:102
const std::vector< services::Service * > services
Definition Design.h:104
A concrete flat message backed by a single vector of bytes.
Definition Common.h:155
A ChannelPort which reads data from the accelerator.
Definition Ports.h:453
Parent class of all APIs modeled as 'services'.
Definition Services.h:59
const std::type_info & Type
Definition Services.h:61
void registerBackend(const std::string &name, BackendCreate create)
std::function< std::unique_ptr< AcceleratorConnection >(Context &, std::string)> BackendCreate
Backends can register themselves to be connected via a connection string.
Definition esi.py:1
constexpr uint32_t CoreFreqOffset
Definition Accelerator.h:67
constexpr uint64_t MagicNumber
Definition Accelerator.h:57
std::map< std::string, std::any > ServiceImplDetails
Definition Common.h:108
constexpr uint64_t MagicNumberHi
Definition Accelerator.h:56
constexpr uint64_t ResetMagicNumber
Magic value which, when written to MMIO offset ResetRequestOffset, requests a design reset.
Definition Accelerator.h:72
constexpr uint32_t ExpectedVersionNumber
Keep in sync with circt::esi::esiApiVersion and the PyCDE BSP.
Definition Accelerator.h:61
constexpr uint64_t MagicNumberOffset
Definition Accelerator.h:58
constexpr uint32_t MetadataOffset
Definition Accelerator.h:53
constexpr uint32_t CycleCountOffset
Definition Accelerator.h:66
constexpr uint32_t ManifestPtrOffset
Definition Accelerator.h:64
constexpr uint32_t ResetRequestOffset
Offset into the (global) MMIO space at which to request a design reset.
Definition Accelerator.h:74
constexpr uint64_t MagicNumberLo
Definition Accelerator.h:55
constexpr uint64_t VersionNumberOffset
Definition Accelerator.h:62
std::vector< HWClientDetail > HWClientDetails
Definition Common.h:107
Tag type used to construct the base class without starting the service thread.