CIRCT 23.0.0git
Loading...
Searching...
No Matches
esiquery.cpp
Go to the documentation of this file.
1//===- esiquery.cpp - ESI accelerator system query tool -------------------===//
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// (lib/dialect/ESI/runtime/cpp/lib/backends/Cosim.cpp).
13//
14//===----------------------------------------------------------------------===//
15
16#include "esi/Accelerator.h"
17#include "esi/CLI.h"
18#include "esi/Manifest.h"
19#include "esi/Services.h"
20
21#include <algorithm>
22#include <iostream>
23#include <map>
24#if defined(__GNUC__)
25#pragma GCC diagnostic push
26#pragma GCC diagnostic ignored "-Wcovered-switch-default"
27#endif
28#include <nlohmann/json.hpp>
29#if defined(__GNUC__)
30#pragma GCC diagnostic pop
31#endif
32#include <stdexcept>
33#include <string>
34
35using namespace esi;
36
37void printInfo(std::ostream &os, AcceleratorConnection &acc, bool details);
38void printHier(std::ostream &os, AcceleratorConnection &acc, bool details);
39void printTelemetry(std::ostream &os, AcceleratorConnection &acc);
40void printTelemetryJson(std::ostream &os, AcceleratorConnection &acc);
41void resetDesign(std::ostream &os, AcceleratorConnection &acc);
42
43int main(int argc, const char *argv[]) {
44 CliParser cli("esiquery");
45 cli.description("Query an ESI system for information from the manifest.");
46
47 CLI::App *versionSub =
48 cli.add_subcommand("version", "Print ESI system version");
49 bool infoDetails = false;
50 CLI::App *infoSub =
51 cli.add_subcommand("info", "Print ESI system information");
52 infoSub->add_flag("--details", infoDetails,
53 "Print detailed information about the system");
54 bool hierDetails = false;
55 CLI::App *hierSub = cli.add_subcommand("hier", "Print ESI system hierarchy");
56 hierSub->add_flag("--details", hierDetails,
57 "Print detailed information about the system");
58 bool telemetryJson = false;
59 CLI::App *telemetrySub =
60 cli.add_subcommand("telemetry", "Print ESI system telemetry information");
61 telemetrySub->add_flag("--json", telemetryJson,
62 "Dump telemetry information as JSON");
63 CLI::App *resetSub =
64 cli.add_subcommand("reset", "Reset the ESI system design");
65
66 if (int rc = cli.esiParse(argc, argv))
67 return rc;
68 if (!cli.get_help_ptr()->empty())
69 return 0;
70
71 Context &ctxt = cli.getContext();
72 try {
73 AcceleratorConnection *acc = cli.connect();
74 const auto &info = *acc->getService<services::SysInfo>();
75
76 if (*versionSub)
77 std::cout << info.getEsiVersion() << std::endl;
78 else if (*infoSub)
79 printInfo(std::cout, *acc, infoDetails);
80 else if (*hierSub)
81 printHier(std::cout, *acc, hierDetails);
82 else if (*telemetrySub) {
83 if (telemetryJson)
84 printTelemetryJson(std::cout, *acc);
85 else
86 printTelemetry(std::cout, *acc);
87 } else if (*resetSub) {
88 resetDesign(std::cout, *acc);
89 }
90 return 0;
91 } catch (std::exception &e) {
92 ctxt.getLogger().error("esiquery", e.what());
93 return -1;
94 }
95}
96
97void printInfo(std::ostream &os, AcceleratorConnection &acc, bool details) {
98 std::string jsonManifest =
99 acc.getService<services::SysInfo>()->getJsonManifest();
100 Manifest m(acc.getCtxt(), jsonManifest);
101 os << "API version: " << m.getApiVersion() << std::endl << std::endl;
102 os << "********************************" << std::endl;
103 os << "* Module information" << std::endl;
104 os << "********************************" << std::endl;
105 os << std::endl;
106 for (ModuleInfo mod : m.getModuleInfos())
107 os << "- " << mod;
108
109 if (!details)
110 return;
111
112 os << std::endl;
113 os << "********************************" << std::endl;
114 os << "* Type table" << std::endl;
115 os << "********************************" << std::endl;
116 os << std::endl;
117 size_t i = 0;
118 for (const Type *t : m.getTypeTable())
119 os << " " << i++ << ": " << t->getID() << std::endl;
120}
121
122static bool showPort(const BundlePort &port, bool details) {
123 return details ||
124 (!port.getID().name.starts_with("__") && !port.getChannels().empty());
125}
126
127void printPort(std::ostream &os, const BundlePort &port, std::string indent,
128 bool details) {
129 if (!showPort(port, details))
130 return;
131 os << indent << " " << port.getID() << ":";
132 if (auto svcPort = dynamic_cast<const services::ServicePort *>(&port))
133 if (auto svcPortStr = svcPort->toString(true)) {
134 os << " " << *svcPortStr << std::endl;
135 return;
136 }
137 os << std::endl;
138 for (const auto &[name, chan] : port.getChannels())
139 os << indent << " " << name << ": " << chan.getType()->toString(true)
140 << std::endl;
141}
142
143void printInstance(std::ostream &os, const HWModule *d, std::string indent,
144 bool details) {
145 bool hasPorts =
146 std::any_of(d->getPorts().begin(), d->getPorts().end(),
147 [&](const std::pair<const AppID, BundlePort &> port) {
148 return showPort(port.second, details);
149 });
150 if (!details && !hasPorts && d->getChildren().empty())
151 return;
152 os << indent << "* Instance: ";
153 if (auto inst = dynamic_cast<const Instance *>(d)) {
154 os << inst->getID() << std::endl;
155 if (inst->getInfo() && inst->getInfo()->name)
156 os << indent << "* Module: " << *inst->getInfo()->name << std::endl;
157 } else {
158 os << "top" << std::endl;
159 }
160
161 os << indent << "* Ports:" << std::endl;
162 for (const BundlePort &port : d->getPortsOrdered())
163 printPort(os, port, indent + " ", details);
164 std::vector<const Instance *> children = d->getChildrenOrdered();
165 if (!children.empty()) {
166 os << indent << "* Children:" << std::endl;
167 for (const Instance *child : d->getChildrenOrdered())
168 printInstance(os, child, indent + " ", details);
169 }
170 os << std::endl;
171}
172
173void printHier(std::ostream &os, AcceleratorConnection &acc, bool details) {
174 Manifest manifest(acc.getCtxt(),
175 acc.getService<services::SysInfo>()->getJsonManifest());
176 Accelerator *design = manifest.buildAccelerator(acc);
177 os << "********************************" << std::endl;
178 os << "* Design hierarchy" << std::endl;
179 os << "********************************" << std::endl;
180 os << std::endl;
181 printInstance(os, design, /*indent=*/"", details);
182}
183
184// Recursively collect telemetry metrics into a hierarchical JSON structure.
185static bool collectTelemetryJson(const HWModule &module, nlohmann::json &node) {
186 bool hasData = false;
187
188 for (const auto &portRef : module.getPortsOrdered()) {
189 BundlePort &port = portRef.get();
190 if (auto *metric =
191 dynamic_cast<services::TelemetryService::Metric *>(&port)) {
192 metric->connect();
193 node[metric->getID().toString()] = metric->readInt();
194 hasData = true;
195 }
196 }
197
198 for (const Instance *child : module.getChildrenOrdered()) {
199 nlohmann::json childNode = nlohmann::json::object();
200 if (collectTelemetryJson(*child, childNode)) {
201 node[child->getID().toString()] = childNode;
202 hasData = true;
203 }
204 }
205
206 return hasData;
207}
208
209void printTelemetryJson(std::ostream &os, AcceleratorConnection &acc) {
210 Manifest manifest(acc.getCtxt(),
211 acc.getService<services::SysInfo>()->getJsonManifest());
212 auto accel = manifest.buildAccelerator(acc);
213 acc.getServiceThread()->addPoll(*accel);
214
215 nlohmann::json root = nlohmann::json::object();
216 if (!collectTelemetryJson(*accel, root))
217 root = nlohmann::json{{"error", "No telemetry metrics found"}};
218
219 os << root.dump(2) << std::endl;
220}
221
222void printTelemetry(std::ostream &os, AcceleratorConnection &acc) {
223 Manifest manifest(acc.getCtxt(),
224 acc.getService<services::SysInfo>()->getJsonManifest());
225 auto accel = manifest.buildAccelerator(acc);
226 acc.getServiceThread()->addPoll(*accel);
227
228 auto *telemetry = acc.getService<services::TelemetryService>();
229 if (!telemetry) {
230 os << "No telemetry service found" << std::endl;
231 return;
232 }
233 os << "********************************" << std::endl;
234 os << "* Telemetry" << std::endl;
235 os << "********************************" << std::endl;
236 os << std::endl;
237
238 const std::map<AppIDPath, services::TelemetryService::Metric *>
239 &telemetryPorts = telemetry->getTelemetryPorts();
240 for (const auto &[id, port] : telemetryPorts) {
241 port->connect();
242 os << id << ": ";
243 os.flush();
244 uint64_t value = port->readInt();
245 os << value << std::endl;
246 }
247}
248
249void resetDesign(std::ostream &os, AcceleratorConnection &acc) {
250 os << "Resetting design..." << std::endl;
251 acc.reset();
252}
Abstract class representing a connection to an accelerator.
Definition Accelerator.h:96
Top level accelerator class.
Definition Accelerator.h:77
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
Definition Ports.h:611
const PortMap & getChannels() const
Definition Ports.h:632
AppID getID() const
Get the ID of the port.
Definition Ports.h:624
Common options and code for ESI runtime tools.
Definition CLI.h:29
Context & getContext()
Get the context.
Definition CLI.h:69
AcceleratorConnection * connect()
Connect to the accelerator using the specified backend and connection.
Definition CLI.h:66
int esiParse(int argc, const char **argv)
Run the parser.
Definition CLI.h:52
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
Subclass of HWModule which represents a submodule instance.
Definition Design.h:111
virtual void error(const std::string &subsystem, const std::string &msg, const std::map< std::string, std::any > *details=nullptr)
Report an error.
Definition Logging.h:64
Class to parse a manifest.
Definition Manifest.h:39
uint32_t getApiVersion() const
Accelerator * buildAccelerator(AcceleratorConnection &acc) const
const std::vector< const Type * > & getTypeTable() const
The Type Table is an ordered list of types.
std::vector< ModuleInfo > getModuleInfos() const
Root class of the ESI type system.
Definition Types.h:36
Add a custom interface to a service client at a particular point in the design hierarchy.
Definition Services.h:47
Information about the Accelerator system.
Definition Services.h:113
virtual std::string getJsonManifest() const
Return the JSON-formatted system manifest.
Definition Services.cpp:40
A telemetry port which gets attached to a service port.
Definition Services.h:470
Service for retrieving telemetry data from the accelerator.
Definition Services.h:453
std::map< AppIDPath, Metric * > getTelemetryPorts()
Definition Services.h:495
int main()
void printHier(std::ostream &os, AcceleratorConnection &acc, bool details)
Definition esiquery.cpp:173
void printInstance(std::ostream &os, const HWModule *d, std::string indent, bool details)
Definition esiquery.cpp:143
void printPort(std::ostream &os, const BundlePort &port, std::string indent, bool details)
Definition esiquery.cpp:127
void printInfo(std::ostream &os, AcceleratorConnection &acc, bool details)
Definition esiquery.cpp:97
void printTelemetry(std::ostream &os, AcceleratorConnection &acc)
Definition esiquery.cpp:222
static bool showPort(const BundlePort &port, bool details)
Definition esiquery.cpp:122
static bool collectTelemetryJson(const HWModule &module, nlohmann::json &node)
Definition esiquery.cpp:185
void printTelemetryJson(std::ostream &os, AcceleratorConnection &acc)
Definition esiquery.cpp:209
void resetDesign(std::ostream &os, AcceleratorConnection &acc)
Definition esiquery.cpp:249
Definition esi.py:1
std::string name
Definition Common.h:36
std::string toString() const
Definition Common.h:48