CIRCT  20.0.0git
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/Manifest.h"
27 #include "esi/Ports.h"
28 #include "esi/Services.h"
29 
30 #include <functional>
31 #include <map>
32 #include <memory>
33 #include <string>
34 #include <typeinfo>
35 
36 namespace esi {
37 // Forward declarations.
38 class AcceleratorServiceThread;
39 
40 //===----------------------------------------------------------------------===//
41 // Constants used by low-level APIs.
42 //===----------------------------------------------------------------------===//
43 
44 constexpr uint32_t MetadataOffset = 8;
45 constexpr uint64_t MagicNumberLo = 0xE5100E51;
46 constexpr uint64_t MagicNumberHi = 0x207D98E5;
47 constexpr uint64_t MagicNumber = MagicNumberLo | (MagicNumberHi << 32);
48 constexpr uint32_t ExpectedVersionNumber = 0;
49 
50 //===----------------------------------------------------------------------===//
51 // Accelerator design hierarchy root.
52 //===----------------------------------------------------------------------===//
53 
54 /// Top level accelerator class. Maintains a shared pointer to the manifest,
55 /// which owns objects used in the design hierarchy owned by this class. Since
56 /// this class owns the entire design hierarchy, when it gets destroyed the
57 /// entire design hierarchy gets destroyed so all of the instances, ports, etc.
58 /// are no longer valid pointers.
59 class Accelerator : public HWModule {
60 public:
61  Accelerator() = delete;
62  Accelerator(const Accelerator &) = delete;
63  ~Accelerator() = default;
64  Accelerator(std::optional<ModuleInfo> info,
65  std::vector<std::unique_ptr<Instance>> children,
66  std::vector<services::Service *> services,
67  std::vector<std::unique_ptr<BundlePort>> &ports)
68  : HWModule(info, std::move(children), services, ports) {}
69 };
70 
71 //===----------------------------------------------------------------------===//
72 // Connection to the accelerator and its services.
73 //===----------------------------------------------------------------------===//
74 
75 /// Abstract class representing a connection to an accelerator. Actual
76 /// connections (e.g. to a co-simulation or actual device) are implemented by
77 /// subclasses. No methods in here are thread safe.
79 public:
81  virtual ~AcceleratorConnection();
82  Context &getCtxt() const { return ctxt; }
83  Logger &getLogger() const { return ctxt.getLogger(); }
84 
85  /// Disconnect from the accelerator cleanly.
86  virtual void disconnect();
87 
88  // While building the design, keep around a std::map of active services
89  // indexed by the service name. When a new service is encountered during
90  // descent, add it to the table (perhaps overwriting one). Modifications to
91  // the table only apply to the current branch, so copy this and update it at
92  // each level of the tree.
93  using ServiceTable = std::map<std::string, services::Service *>;
94 
95  /// Request the host side channel ports for a particular instance (identified
96  /// by the AppID path). For convenience, provide the bundle type.
97  virtual std::map<std::string, ChannelPort &>
99 
100  /// Return a pointer to the accelerator 'service' thread (or threads). If the
101  /// thread(s) are not running, they will be started when this method is
102  /// called. `std::thread` is used. If users don't want the runtime to spin up
103  /// threads, don't call this method. `AcceleratorServiceThread` is owned by
104  /// AcceleratorConnection and governed by the lifetime of the this object.
106 
108  /// Get a typed reference to a particular service type. Caller does *not* take
109  /// ownership of the returned pointer -- the Accelerator object owns it.
110  /// Pointer lifetime ends with the Accelerator lifetime.
111  template <typename ServiceClass>
112  ServiceClass *getService(AppIDPath id = {}, std::string implName = {},
113  ServiceImplDetails details = {},
114  HWClientDetails clients = {}) {
115  return dynamic_cast<ServiceClass *>(
116  getService(typeid(ServiceClass), id, implName, details, clients));
117  }
118  /// Calls `createService` and caches the result. Subclasses can override if
119  /// they want to use their own caching mechanism.
120  virtual Service *getService(Service::Type service, AppIDPath id = {},
121  std::string implName = {},
122  ServiceImplDetails details = {},
123  HWClientDetails clients = {});
124 
125  /// Assume ownership of an accelerator object. Ties the lifetime of the
126  /// accelerator to this connection. Returns a raw pointer to the object.
127  Accelerator *takeOwnership(std::unique_ptr<Accelerator> accel);
128 
129 protected:
130  /// Called by `getServiceImpl` exclusively. It wraps the pointer returned by
131  /// this in a unique_ptr and caches it. Separate this from the
132  /// wrapping/caching since wrapping/caching is an implementation detail.
133  virtual Service *createService(Service::Type service, AppIDPath idPath,
134  std::string implName,
135  const ServiceImplDetails &details,
136  const HWClientDetails &clients) = 0;
137 
138 private:
139  /// ESI accelerator context.
141 
142  /// Cache services via a unique_ptr so they get free'd automatically when
143  /// Accelerator objects get deconstructed.
144  using ServiceCacheKey = std::tuple<const std::type_info *, AppIDPath>;
145  std::map<ServiceCacheKey, std::unique_ptr<Service>> serviceCache;
146 
147  std::unique_ptr<AcceleratorServiceThread> serviceThread;
148 
149  /// List of accelerator objects owned by this connection. These are destroyed
150  /// when the connection dies or is shutdown.
151  std::vector<std::unique_ptr<Accelerator>> ownedAccelerators;
152 };
153 
154 namespace registry {
155 
156 // Connect to an ESI accelerator given a backend name and connection specifier.
157 // Alternatively, instantiate the backend directly (if you're using C++).
158 std::unique_ptr<AcceleratorConnection> connect(Context &ctxt,
159  const std::string &backend,
160  const std::string &connection);
161 
162 namespace internal {
163 
164 /// Backends can register themselves to be connected via a connection string.
165 using BackendCreate = std::function<std::unique_ptr<AcceleratorConnection>(
166  Context &, std::string)>;
167 void registerBackend(const std::string &name, BackendCreate create);
168 
169 // Helper struct to
170 template <typename TAccelerator>
172  RegisterAccelerator(const char *name) {
174  }
175 };
176 
177 #define REGISTER_ACCELERATOR(Name, TAccelerator) \
178  static ::esi::registry::internal::RegisterAccelerator<TAccelerator> \
179  __register_accel____LINE__(Name)
180 
181 } // namespace internal
182 } // namespace registry
183 
184 /// Background thread which services various requests. Currently, it listens on
185 /// ports and calls callbacks for incoming messages on said ports.
187 public:
190 
191  /// When there's data on any of the listenPorts, call the callback. Callable
192  /// from any thread.
193  void
194  addListener(std::initializer_list<ReadChannelPort *> listenPorts,
195  std::function<void(ReadChannelPort *, MessageData)> callback);
196 
197  /// Poll this module.
198  void addPoll(HWModule &module);
199 
200  /// Instruct the service thread to stop running.
201  void stop();
202 
203 private:
204  struct Impl;
205  std::unique_ptr<Impl> impl;
206 };
207 } // namespace esi
208 
209 #endif // ESI_ACCELERATOR_H
Abstract class representing a connection to an accelerator.
Definition: Accelerator.h:78
Context & getCtxt() const
Definition: Accelerator.h:82
virtual void disconnect()
Disconnect from the accelerator cleanly.
Logger & getLogger() const
Definition: Accelerator.h:83
services::Service Service
Definition: Accelerator.h:107
virtual std::map< std::string, ChannelPort & > requestChannelsFor(AppIDPath, const BundleType *, const ServiceTable &)=0
Request the host side channel ports for a particular instance (identified by the AppID path).
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
Definition: Accelerator.h:112
std::map< std::string, services::Service * > ServiceTable
Definition: Accelerator.h:93
Context & ctxt
ESI accelerator context.
Definition: Accelerator.h:140
std::map< ServiceCacheKey, std::unique_ptr< Service > > serviceCache
Definition: Accelerator.h:145
std::tuple< const std::type_info *, AppIDPath > ServiceCacheKey
Cache services via a unique_ptr so they get free'd automatically when Accelerator objects get deconst...
Definition: Accelerator.h:144
std::unique_ptr< AcceleratorServiceThread > serviceThread
Definition: Accelerator.h:147
virtual Service * createService(Service::Type service, AppIDPath idPath, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients)=0
Called by getServiceImpl exclusively.
std::vector< std::unique_ptr< Accelerator > > ownedAccelerators
List of accelerator objects owned by this connection.
Definition: Accelerator.h:151
AcceleratorServiceThread * getServiceThread()
Return a pointer to the accelerator 'service' thread (or threads).
Definition: Accelerator.cpp:40
AcceleratorConnection(Context &ctxt)
Definition: Accelerator.cpp:36
Accelerator * takeOwnership(std::unique_ptr< Accelerator > accel)
Assume ownership of an accelerator object.
Definition: Accelerator.cpp:65
Background thread which services various requests.
Definition: Accelerator.h:186
void stop()
Instruct the service thread to stop running.
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::unique_ptr< Impl > impl
Definition: Accelerator.h:204
void addPoll(HWModule &module)
Poll this module.
Top level accelerator class.
Definition: Accelerator.h:59
~Accelerator()=default
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:64
Accelerator()=delete
Accelerator(const Accelerator &)=delete
Bundles represent a collection of channels.
Definition: Types.h:44
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Definition: Context.h:31
Logger & getLogger()
Definition: Context.h:62
Represents either the top level or an instance of a hardware module.
Definition: Design.h:47
const std::optional< ModuleInfo > info
Definition: Design.h:90
const std::vector< std::unique_ptr< BundlePort > > ports
Definition: Design.h:94
const std::vector< std::unique_ptr< Instance > > children
Definition: Design.h:91
const std::vector< services::Service * > services
Definition: Design.h:93
A logical chunk of data representing serialized data.
Definition: Common.h:103
A ChannelPort which reads data from the accelerator.
Definition: Ports.h:103
Parent class of all APIs modeled as 'services'.
Definition: Services.h:45
const std::type_info & Type
Definition: Services.h:47
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: Accelerator.h:166
std::unique_ptr< AcceleratorConnection > connect(Context &ctxt, const std::string &backend, const std::string &connection)
Definition: esi.py:1
constexpr uint64_t MagicNumber
Definition: Accelerator.h:47
std::map< std::string, std::any > ServiceImplDetails
Definition: Common.h:98
constexpr uint64_t MagicNumberHi
Definition: Accelerator.h:46
constexpr uint32_t ExpectedVersionNumber
Definition: Accelerator.h:48
constexpr uint32_t MetadataOffset
Definition: Accelerator.h:44
constexpr uint64_t MagicNumberLo
Definition: Accelerator.h:45
std::vector< HWClientDetail > HWClientDetails
Definition: Common.h:97