CIRCT 23.0.0git
Loading...
Searching...
No Matches
ModelInstance.cpp
Go to the documentation of this file.
1//===- ModelInstance.cpp - Instance of a model in the ArcRuntime ----------===//
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// This implements the context for a model instance in the ArcRuntime library.
10//
11//===----------------------------------------------------------------------===//
12
14
17#ifdef CIRCT_LIBFST_ENABLED
19#endif
20
21#include <cassert>
22#include <cctype>
23#include <iostream>
24#include <string_view>
25#include <system_error>
26#include <vector>
27
28using namespace circt::arc::runtime;
29
31
32// Global counter for instances
33static uint64_t instanceIDsGlobal = 0;
34
36 const char *args, ArcState *mutableState)
37 : instanceID(instanceIDsGlobal++), modelInfo(modelInfo),
38 state(mutableState) {
39 bool hasTraceInstrumentation = !!modelInfo->traceInfo;
41 parseArgs(args);
42
43 if (verbose) {
44 std::cout << "[ArcRuntime] "
45 << "Created instance"
46 << " of model \"" << getModelName() << "\""
47 << " with ID " << instanceID << std::endl;
48 std::cout << "[ArcRuntime] Model \"" << getModelName() << "\"";
49 if (hasTraceInstrumentation)
50 std::cout << " has trace instrumentation." << std::endl;
51 else
52 std::cout << " does not have trace instrumentation." << std::endl;
53 }
54
55 if (!hasTraceInstrumentation && traceMode != TraceMode::DUMMY)
56 std::cerr
57 << "[ArcRuntime] WARNING: "
58 << "Tracing has been requested but model \"" << getModelName()
59 << "\" contains no instrumentation."
60 << " No trace will be produced.\n\t\tMake sure to compile the model"
61 " with tracing enabled and that it contains observed signals."
62 << std::endl;
63
64 if (hasTraceInstrumentation) {
65 switch (traceMode) {
68 std::make_unique<DummyTraceEncoder>(modelInfo, mutableState);
69 break;
70 case TraceMode::VCD:
71 traceEncoder = std::make_unique<VCDTraceEncoder>(
72 modelInfo, mutableState, getTraceFilePath(".vcd"), verbose);
73 break;
74 case TraceMode::FST:
75#ifdef CIRCT_LIBFST_ENABLED
76 traceEncoder = std::make_unique<FSTTraceEncoder>(
77 modelInfo, mutableState, getTraceFilePath(".fst"), verbose);
78#else
79 std::cerr << "[ArcRuntime] ERROR: FST tracing was requested but CIRCT "
80 "was not built with FST support (CIRCT_LIBFST_ENABLED=OFF)."
81 << std::endl;
83 std::make_unique<DummyTraceEncoder>(modelInfo, mutableState);
84#endif
85 break;
86 }
87 } else {
88 traceEncoder = {};
89 }
90}
91
93 if (verbose) {
94 std::cout << "[ArcRuntime] "
95 << "Deleting instance"
96 << " of model \"" << getModelName() << "\""
97 << " with ID " << instanceID << " after " << stepCounter
98 << " step(s)" << std::endl;
99 }
100 assert(state->impl == static_cast<void *>(this) && "Inconsistent ArcState");
101 if (traceEncoder)
102 traceEncoder->finish(state);
103}
104
105std::filesystem::path
106ModelInstance::getTraceFilePath(const std::string &suffix) {
107 auto it = arguments.find(kArgKeyTraceFile);
108 if (it != arguments.end() && it->second.has_value())
109 return workDir / std::filesystem::path(*it->second);
110
111 std::string saneName;
112 if (modelInfo->modelName)
113 saneName = std::string(modelInfo->modelName);
114 for (auto &c : saneName) {
115 if (c == ' ' || c == '/' || c == '\\')
116 c = '_';
117 }
118 saneName += '_';
119 saneName += std::to_string(instanceID);
120 saneName += suffix;
121 return workDir / std::filesystem::path(saneName);
122}
123
124void ModelInstance::onEval(ArcState *mutableState) {
125 assert(mutableState == state);
126 ++stepCounter;
127 if (traceEncoder)
128 traceEncoder->step(state);
129}
130
132 assert(mutableState == state);
133 if (traceEncoder)
134 traceEncoder->run(mutableState);
135
136 if (verbose) {
137 std::cout << "[ArcRuntime] "
138 << "Instance with ID " << instanceID << " initialized"
139 << std::endl;
140 }
141}
142
144 if (!traceEncoder)
146 "swapTraceBuffer called on model without trace instrumentation");
147 if (verbose)
148 std::cout << "[ArcRuntime] Consuming trace buffer of size "
149 << state->traceBufferSize << " for instance ID " << instanceID
150 << std::endl;
151 return traceEncoder->dispatch(state->traceBufferSize);
152}
153
154// Parse the argument string into a map of key to optional value.
155// Flags (bare keys without '=') map to std::nullopt. Keys occurring later
156// override identical earlier keys. Quoted values (key="...") may contain ';'
157// and support \" and \\ escape sequences. Malformed tokens are warned and
158// skipped.
159static std::map<std::string, std::optional<std::string>>
160parseArgsToMap(std::string_view argStr) {
161 std::map<std::string, std::optional<std::string>> result;
162
163 enum class State { Key, AfterEq, Unquoted, Quoted, Escape, AfterQuote, Skip };
164 State state = State::Key;
165
166 std::string key;
167 std::string value;
168 bool hasValue = false;
169
170 auto warn = [&](const char *msg) {
171 std::cerr << "[ArcRuntime] WARNING: Malformed runtime argument: " << msg;
172 if (!key.empty())
173 std::cerr << " for key \"" << key << "\"";
174 std::cerr << ", ignoring\n";
175 };
176
177 auto commit = [&] {
178 result[std::move(key)] =
179 hasValue ? std::optional(std::move(value)) : std::nullopt;
180 key.clear();
181 value.clear();
182 hasValue = false;
183 state = State::Key;
184 };
185
186 auto skipToNext = [&] {
187 key.clear();
188 value.clear();
189 hasValue = false;
190 state = State::Skip;
191 };
192
193 for (size_t i = 0; i <= argStr.size(); ++i) {
194 const bool atEnd = (i == argStr.size());
195 const char c = atEnd ? '\0' : argStr[i];
196
197 switch (state) {
198 case State::Key:
199 if (atEnd || c == ';') {
200 if (!key.empty())
201 commit();
202 } else if (std::isgraph(static_cast<unsigned char>(c)) && c != '"' &&
203 c != '=') {
204 key += c;
205 } else if (c == '=' && !key.empty()) {
206 hasValue = true;
207 state = State::AfterEq;
208 } else {
209 warn("Invalid key");
210 skipToNext();
211 }
212 break;
213
214 case State::AfterEq:
215 if (c == '"' && !atEnd) {
216 state = State::Quoted;
217 } else if (atEnd || c == ';') {
218 commit(); // empty value
219 } else {
220 value += c;
221 state = State::Unquoted;
222 }
223 break;
224
225 case State::Unquoted:
226 if (atEnd || c == ';') {
227 commit();
228 } else if (c == '"') {
229 warn("Unquoted value contains forbidden character '\"'");
230 skipToNext();
231 } else {
232 value += c;
233 }
234 break;
235
236 case State::Quoted:
237 if (atEnd) {
238 warn("Unterminated quoted value");
239 skipToNext();
240 } else if (c == '"') {
241 state = State::AfterQuote;
242 } else if (c == '\\') {
243 state = State::Escape;
244 } else {
245 value += c;
246 }
247 break;
248
249 case State::Escape:
250 if (atEnd) {
251 warn("Truncated escape sequence in quoted value");
252 skipToNext();
253 } else if (c == '"' || c == '\\') {
254 value += c;
255 state = State::Quoted;
256 } else {
257 warn("Invalid escape sequence in quoted value");
258 skipToNext();
259 }
260 break;
261
262 case State::AfterQuote:
263 if (atEnd || c == ';') {
264 commit();
265 } else {
266 warn("Unexpected content after closing quote");
267 skipToNext();
268 }
269 break;
270
271 case State::Skip:
272 if (!atEnd && c == ';')
273 state = State::Key;
274 break;
275 }
276 }
277
278 return result;
279}
280
281void ModelInstance::parseArgs(const char *args) {
282 if (!args)
283 return;
284 auto argStr = std::string_view(args);
285 arguments = parseArgsToMap(argStr);
286 if (arguments.count(kArgKeyDebug))
287 verbose = true;
288
289 // Dump arguments
290 if (verbose) {
291 std::cout << "[ArcRuntime] Argument string for instance ID " << instanceID
292 << ": " << argStr << std::endl;
293 std::cout << "[ArcRuntime] Parsed argument(s):" << std::endl;
294 for (const auto &[key, value] : arguments) {
295 std::cout << "[ArcRuntime] " << key;
296 if (value.has_value())
297 std::cout << " = \"" << *value << "\"";
298 std::cout << std::endl;
299 }
300 }
301
302 // Initialize workDir. A relative argument is resolved against the process
303 // working directory; an absolute argument replaces it entirely.
304 std::error_code ec;
305 workDir = std::filesystem::current_path(ec);
306 if (ec) {
307 std::cerr << "[ArcRuntime] WARNING: Could not determine current working "
308 "directory: "
309 << ec.message() << std::endl;
310 workDir.clear();
311 }
312 auto workDirIt = arguments.find(kArgKeyWorkDir);
313 if (workDirIt != arguments.end() && workDirIt->second.has_value()) {
314 workDir /= *workDirIt->second;
315 workDir = workDir.lexically_normal();
316
317 // Create the working directory if it does not exist yet.
318 std::filesystem::create_directories(workDir, ec);
319 if (ec)
320 std::cerr << "[ArcRuntime] WARNING: Could not create working directory \""
321 << workDir.string() << "\": " << ec.message() << std::endl;
322 }
323
324 if (verbose)
325 std::cout << "[ArcRuntime] Working directory for instance ID " << instanceID
326 << ": " << workDir.string() << std::endl;
327
328 // Select Trace Mode
329 if (arguments.count(kArgKeyVcd))
331 if (arguments.count(kArgKeyFst))
333}
334
335} // namespace circt::arc::runtime::impl
assert(baseType &&"element must be base type")
std::filesystem::path getTraceFilePath(const std::string &suffix)
Get the path to the output trace file.
static const std::string kArgKeyTraceFile
Workdir-relative or absolute path to trace file.
void onEval(ArcState *mutableState)
void parseArgs(const char *args)
Parse and initialize the instance settings from the given argument string.
static const std::string kArgKeyDebug
Enable verbose debug output.
static const std::string kArgKeyVcd
Select VCD trace mode.
std::unique_ptr< TraceEncoder > traceEncoder
std::map< std::string, std::optional< std::string > > arguments
std::filesystem::path workDir
The path to the instance's working directory.
static const std::string kArgKeyFst
Select FST trace mode.
void onInitialized(ArcState *mutableState)
static const std::string kArgKeyWorkDir
Instance's working directory. Absolute or relative to process workdir.
const ArcRuntimeModelInfo *const modelInfo
static std::map< std::string, std::optional< std::string > > parseArgsToMap(std::string_view argStr)
static void fatalError(const char *message)
Raise an irrecoverable error.
Definition Internal.h:23
static uint64_t instanceIDsGlobal
Static information for a compiled hardware model, generated by the MLIR lowering.
Definition Common.h:70
struct ArcModelTraceInfo * traceInfo
Signal tracing information. NULL iff the model is not trace instrumented.
Definition Common.h:78
const char * modelName
Name of the compiled model.
Definition Common.h:76
Combined runtime and model state for a hardware model instance.
Definition Common.h:44
void * impl
Runtime implementation specific data. Usually points to a custom struct.
Definition Common.h:46
uint32_t traceBufferSize
Number of valid elements in the active trace buffer.
Definition Common.h:52