CIRCT  19.0.0git
Ports.h
Go to the documentation of this file.
1 //===- Ports.h - ESI communication channels ---------------------*- 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 // DO NOT EDIT!
10 // This file is distributed as part of an ESI package. The source for this file
11 // should always be modified within CIRCT.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 // NOLINTNEXTLINE(llvm-header-guard)
16 #ifndef ESI_PORTS_H
17 #define ESI_PORTS_H
18 
19 #include "esi/Common.h"
20 #include "esi/Types.h"
21 #include "esi/Utils.h"
22 
23 #include <cassert>
24 #include <future>
25 
26 namespace esi {
27 
28 /// Unidirectional channels are the basic communication primitive between the
29 /// host and accelerator. A 'ChannelPort' is the host side of a channel. It can
30 /// be either read or write but not both. At this level, channels are untyped --
31 /// just streams of bytes. They are not intended to be used directly by users
32 /// but used by higher level APIs which add types.
33 class ChannelPort {
34 public:
35  ChannelPort(const Type *type) : type(type) {}
36  virtual ~ChannelPort() { disconnect(); }
37 
38  virtual void connect() { connectImpl(); }
39  virtual void disconnect() {}
40 
41  const Type *getType() const { return type; }
42 
43 private:
44  const Type *type;
45 
46  /// Called by all connect methods to let backends initiate the underlying
47  /// connections.
48  virtual void connectImpl() {}
49 };
50 
51 /// A ChannelPort which sends data to the accelerator.
52 class WriteChannelPort : public ChannelPort {
53 public:
55 
56  /// A very basic write API. Will likely change for performance reasons.
57  virtual void write(const MessageData &) = 0;
58 };
59 
60 /// A ChannelPort which reads data from the accelerator. It has two modes:
61 /// Callback and Polling which cannot be used at the same time. The mode is set
62 /// at connect() time. To change the mode, disconnect() and then connect()
63 /// again.
64 class ReadChannelPort : public ChannelPort {
65 
66 public:
69  virtual void disconnect() override { mode = Mode::Disconnected; }
70 
71  //===--------------------------------------------------------------------===//
72  // Callback mode: To use a callback, connect with a callback function which
73  // will get called with incoming data. This function can be called from any
74  // thread. It shall return true to indicate that the data was consumed. False
75  // if it could not accept the data and should be tried again at some point in
76  // the future. Callback is not allowed to block and needs to execute quickly.
77  //
78  // TODO: Have the callback return something upon which the caller can check,
79  // wait, and be notified.
80  //===--------------------------------------------------------------------===//
81 
82  virtual void connect(std::function<bool(MessageData)> callback);
83 
84  //===--------------------------------------------------------------------===//
85  // Polling mode methods: To use futures or blocking reads, connect without any
86  // arguments. You will then be able to use readAsync() or read().
87  //===--------------------------------------------------------------------===//
88 
89  /// Default max data queue size set at connect time.
90  static constexpr uint64_t DefaultMaxDataQueueMsgs = 32;
91 
92  /// Connect to the channel in polling mode.
93  virtual void connect() override;
94 
95  /// Asynchronous read.
96  virtual std::future<MessageData> readAsync();
97 
98  /// Specify a buffer to read into. Blocking. Basic API, will likely change
99  /// for performance and functionality reasons.
100  virtual void read(MessageData &outData) {
101  std::future<MessageData> f = readAsync();
102  f.wait();
103  outData = std::move(f.get());
104  }
105 
106  /// Set maximum number of messages to store in the dataQueue. 0 means no
107  /// limit. This is only used in polling mode and is set to default of 32 upon
108  /// connect.
109  void setMaxDataQueueMsgs(uint64_t maxMsgs) { maxDataQueueMsgs = maxMsgs; }
110 
111 protected:
112  /// Indicates the current mode of the channel.
115 
116  /// Backends call this callback when new data is available.
117  std::function<bool(MessageData)> callback;
118 
119  //===--------------------------------------------------------------------===//
120  // Polling mode members.
121  //===--------------------------------------------------------------------===//
122 
123  /// Mutex to protect the two queues used for polling.
124  std::mutex pollingM;
125  /// Store incoming data here if there are no outstanding promises to be
126  /// fulfilled.
127  std::queue<MessageData> dataQueue;
128  /// Maximum number of messages to store in dataQueue. 0 means no limit.
130  /// Promises to be fulfilled when data is available.
131  std::queue<std::promise<MessageData>> promiseQueue;
132 };
133 
134 /// Services provide connections to 'bundles' -- collections of named,
135 /// unidirectional communication channels. This class provides access to those
136 /// ChannelPorts.
137 class BundlePort {
138 public:
139  /// Compute the direction of a channel given the bundle direction and the
140  /// bundle port's direction.
141  static bool isWrite(BundleType::Direction bundleDir) {
142  return bundleDir == BundleType::Direction::To;
143  }
144 
145  /// Construct a port.
146  BundlePort(AppID id, std::map<std::string, ChannelPort &> channels);
147  virtual ~BundlePort() = default;
148 
149  /// Get the ID of the port.
150  AppID getID() const { return id; }
151 
152  /// Get access to the raw byte streams of a channel. Intended for internal
153  /// usage and binding to other languages (e.g. Python) which have their own
154  /// message serialization code. Exposed publicly as an escape hatch, but
155  /// ordinary users should not use. You have been warned.
156  WriteChannelPort &getRawWrite(const std::string &name) const;
157  ReadChannelPort &getRawRead(const std::string &name) const;
158  const std::map<std::string, ChannelPort &> &getChannels() const {
159  return channels;
160  }
161 
162  /// Cast this Bundle port to a subclass which is actually useful. Returns
163  /// nullptr if the cast fails.
164  // TODO: this probably shouldn't be 'const', but bundle ports' user access are
165  // const. Change that.
166  template <typename T>
167  T *getAs() const {
168  return const_cast<T *>(dynamic_cast<const T *>(this));
169  }
170 
171 private:
173  std::map<std::string, ChannelPort &> channels;
174 };
175 
176 } // namespace esi
177 
178 #endif // ESI_PORTS_H
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
Definition: Ports.h:137
virtual ~BundlePort()=default
std::map< std::string, ChannelPort & > channels
Definition: Ports.h:173
ReadChannelPort & getRawRead(const std::string &name) const
Definition: Ports.cpp:35
WriteChannelPort & getRawWrite(const std::string &name) const
Get access to the raw byte streams of a channel.
Definition: Ports.cpp:25
AppID id
Definition: Ports.h:172
const std::map< std::string, ChannelPort & > & getChannels() const
Definition: Ports.h:158
T * getAs() const
Cast this Bundle port to a subclass which is actually useful.
Definition: Ports.h:167
static bool isWrite(BundleType::Direction bundleDir)
Compute the direction of a channel given the bundle direction and the bundle port's direction.
Definition: Ports.h:141
BundlePort(AppID id, std::map< std::string, ChannelPort & > channels)
Construct a port.
Definition: Ports.cpp:22
AppID getID() const
Get the ID of the port.
Definition: Ports.h:150
Unidirectional channels are the basic communication primitive between the host and accelerator.
Definition: Ports.h:33
virtual void disconnect()
Definition: Ports.h:39
ChannelPort(const Type *type)
Definition: Ports.h:35
virtual void connectImpl()
Called by all connect methods to let backends initiate the underlying connections.
Definition: Ports.h:48
const Type * type
Definition: Ports.h:44
virtual void connect()
Definition: Ports.h:38
const Type * getType() const
Definition: Ports.h:41
virtual ~ChannelPort()
Definition: Ports.h:36
A logical chunk of data representing serialized data.
Definition: Common.h:86
A ChannelPort which reads data from the accelerator.
Definition: Ports.h:64
virtual std::future< MessageData > readAsync()
Asynchronous read.
Definition: Ports.cpp:76
std::mutex pollingM
Mutex to protect the two queues used for polling.
Definition: Ports.h:124
std::function< bool(MessageData)> callback
Backends call this callback when new data is available.
Definition: Ports.h:117
Mode
Indicates the current mode of the channel.
Definition: Ports.h:113
std::queue< MessageData > dataQueue
Store incoming data here if there are no outstanding promises to be fulfilled.
Definition: Ports.h:127
static constexpr uint64_t DefaultMaxDataQueueMsgs
Default max data queue size set at connect time.
Definition: Ports.h:90
std::queue< std::promise< MessageData > > promiseQueue
Promises to be fulfilled when data is available.
Definition: Ports.h:131
void setMaxDataQueueMsgs(uint64_t maxMsgs)
Set maximum number of messages to store in the dataQueue.
Definition: Ports.h:109
uint64_t maxDataQueueMsgs
Maximum number of messages to store in dataQueue. 0 means no limit.
Definition: Ports.h:129
virtual void disconnect() override
Definition: Ports.h:69
virtual void connect() override
Connect to the channel in polling mode.
Definition: Ports.cpp:52
virtual void read(MessageData &outData)
Specify a buffer to read into.
Definition: Ports.h:100
ReadChannelPort(const Type *type)
Definition: Ports.h:67
Root class of the ESI type system.
Definition: Types.h:27
A ChannelPort which sends data to the accelerator.
Definition: Ports.h:52
virtual void write(const MessageData &)=0
A very basic write API. Will likely change for performance reasons.
Definition: esi.py:1