15 #include "fletchgen/profiler.h"
17 #include <cerata/api.h>
18 #include <cerata/vhdl/vhdl.h>
24 #include "fletchgen/basic_types.h"
25 #include "fletchgen/nucleus.h"
29 using cerata::component;
30 using cerata::parameter;
36 using cerata::integer;
39 static constexpr uint32_t COUNT_WIDTH = 32;
43 static constexpr
char e[] =
"Element count. Accumulates the number of elements transferred on the stream. "
44 "Writing to the register subtracts the written value.";
45 static constexpr
char v[] =
"Valid count. Increments each cycle that the stream is valid. "
46 "Writing to the register subtracts the written value.";
47 static constexpr
char r[] =
"Ready count. Increments each cycle that the stream is ready. "
48 "Writing to the register subtracts the written value.";
49 static constexpr
char t[] =
"Transfer count. "
50 "Increments for each transfer on the stream, i.e. when it is handshaked. "
51 "Writing to the register subtracts the written value.";
52 static constexpr
char p[] =
"Packet count. Increments each time the last signal is set during a handshake "
53 "Writing to the register subtracts the written value.";
54 static constexpr
char c[] =
"Cycle count. Increments each clock cycle while profiler is enabled.";
58 static constexpr
char e[] =
"elements";
59 static constexpr
char v[] =
"valids";
60 static constexpr
char r[] =
"readies";
61 static constexpr
char t[] =
"transfers";
62 static constexpr
char p[] =
"packets";
63 static constexpr
char c[] =
"cycles";
66 std::vector<MmioReg>
GetProfilingRegs(
const std::vector<std::shared_ptr<RecordBatch>> &recordbatches) {
67 std::vector<MmioReg> profile_regs;
71 profile_regs.emplace_back(MF::PROFILE,
74 "Activates profiler counting when this bit is high.",
77 profile_regs.emplace_back(MF::PROFILE,
80 "Resets profiler counters when this bit is asserted.",
83 for (
const auto &rb : recordbatches) {
84 auto fps = rb->GetFieldPorts();
85 for (
const auto &fp : fps) {
88 auto flattened = cerata::Flatten(fp->type());
90 for (
auto &fti : flattened) {
91 if (
dynamic_cast<cerata::Stream *
>(fti.type_) !=
nullptr) {
92 const auto pre =
"Profile_" + fti.name(cerata::NamePart(fp->name()));
93 const auto sis =
"_" + std::to_string(si) +
"_";
94 MmioReg e(MF::PROFILE, MB::STATUS, pre + sis + name::e, doc::e, COUNT_WIDTH);
95 MmioReg v(MF::PROFILE, MB::STATUS, pre + sis + name::v, doc::v, COUNT_WIDTH);
96 MmioReg r(MF::PROFILE, MB::STATUS, pre + sis + name::r, doc::r, COUNT_WIDTH);
97 MmioReg t(MF::PROFILE, MB::STATUS, pre + sis + name::t, doc::t, COUNT_WIDTH);
98 MmioReg p(MF::PROFILE, MB::STATUS, pre + sis + name::p, doc::p, COUNT_WIDTH);
99 MmioReg c(MF::PROFILE, MB::STATUS, pre + sis + name::c, doc::c, COUNT_WIDTH);
100 profile_regs.insert(profile_regs.end(), {e, v, r, t, p, c});
110 std::shared_ptr<cerata::Type>
stream_probe(
const std::shared_ptr<Node> &count_width) {
113 auto result = stream(
"probe",
114 "count", vector(count_width),
115 {field(cerata::Stream::valid()),
116 field(cerata::Stream::ready()),
121 static Component *profiler() {
123 auto opt_comp = cerata::default_component_pool()->Get(
"Profiler");
129 auto icw = parameter(
"PROBE_COUNT_WIDTH", integer(), cerata::intl(1));
130 auto ocw = parameter(
"OUT_COUNT_WIDTH", integer(), cerata::intl(32));
131 auto oct = vector(
"out_count_type", ocw);
133 auto pcr = port(
"pcd",
cr(), Port::Dir::IN);
134 auto probe = port(
"probe",
stream_probe(icw), Port::Dir::IN);
135 auto enable = port(
"enable", bit(), Port::Dir::IN);
136 auto clear = port(
"clear", bit(), Port::Dir::IN);
137 auto e = port(std::string(
"count_") + name::e, oct, Port::Dir::OUT);
138 auto v = port(std::string(
"count_") + name::v, oct, Port::Dir::OUT);
139 auto r = port(std::string(
"count_") + name::r, oct, Port::Dir::OUT);
140 auto t = port(std::string(
"count_") + name::t, oct, Port::Dir::OUT);
141 auto p = port(std::string(
"count_") + name::p, oct, Port::Dir::OUT);
142 auto c = port(std::string(
"count_") + name::c, oct, Port::Dir::OUT);
145 auto ret = component(
"Profiler", {icw, ocw, pcr, probe, enable, clear, e, v, r, t, p, c});
148 ret->SetMeta(cerata::vhdl::meta::PRIMITIVE,
"true");
149 ret->SetMeta(cerata::vhdl::meta::LIBRARY,
"work");
150 ret->SetMeta(cerata::vhdl::meta::PACKAGE,
"Profile_pkg");
156 const std::vector<cerata::Signal *> &profile_nodes) {
157 cerata::NodeMap rebinding;
160 for (
auto node : profile_nodes) {
162 auto flat_types = Flatten(node->type());
166 while (fti < flat_types.size()) {
167 if (flat_types[fti].type_->Is(Type::RECORD)) {
168 FLETCHER_LOG(DEBUG,
"Inserting profiler for stream node " + node->name()
169 +
", sub-stream " + std::to_string(s)
170 +
" of flattened type " + node->type()->name()
171 +
" index " + std::to_string(fti) +
".");
173 auto domain = *GetDomain(*node);
176 throw std::runtime_error(
"No clock/reset port present on component [" + comp->name()
177 +
"] for clock domain [" + domain->name()
178 +
"] of stream node [" + node->name() +
"].");
182 std::string name = flat_types[fti].name(cerata::NamePart(node->name(),
true));
183 auto profiler_inst = comp->Instantiate(profiler(), profiler()->name() +
"_" + name +
"_inst");
185 for (
auto &p : profiler_inst->GetAll<Port>()) {
186 p->SetDomain(domain);
190 auto p_probe = profiler_inst->prt(
"probe");
191 auto p_cr = profiler_inst->prt(
"pcd");
192 auto p_in_count_width = profiler_inst->par(
"PROBE_COUNT_WIDTH");
195 auto mapper = TypeMapper::Make(node->type(), p_probe->type());
196 auto matrix = mapper->map_matrix().Empty();
198 matrix(++fti, 1) = 1;
199 matrix(++fti, 2) = 1;
208 while (fti < flat_types.size()) {
209 auto ft = flat_types[fti];
211 auto width = std::strtol(flat_types[fti].type_->meta.at(
meta::COUNT).c_str(),
nullptr, 10);
212 p_in_count_width <<= intl(static_cast<int>(width));
222 mapper->SetMappingMatrix(matrix);
223 node->type()->AddMapper(mapper);
226 Connect(p_cr, *cr_node);
227 Connect(p_probe, node);
230 auto new_ports = std::vector<Port *>({profiler_inst->prt(std::string(
"count_") + name::e),
231 profiler_inst->prt(std::string(
"count_") + name::v),
232 profiler_inst->prt(std::string(
"count_") + name::r),
233 profiler_inst->prt(std::string(
"count_") + name::t),
234 profiler_inst->prt(std::string(
"count_") + name::p),
235 profiler_inst->prt(std::string(
"count_") + name::c)});
237 if (result.count(node) == 0) {
239 result[node] = {{profiler_inst}, new_ports};
242 result[node].first.push_back(profiler_inst);
243 auto vec = result[node].second;
244 vec.insert(vec.end(), new_ports.begin(), new_ports.end());
Contains all classes and functions related to Fletchgen.
std::shared_ptr< Type > cr()
Fletcher clock/reset;.
MmioBehavior
Register access behavior enumeration.
std::map< Node *, std::pair< std::vector< Instance * >, std::vector< Port * > >> NodeProfilerPorts
A mapping from nodes to profiler instances and ports.
MmioFunction
Register intended use enumeration.
std::shared_ptr< cerata::Type > stream_probe(const std::shared_ptr< Node > &count_width)
Returns a stream probe type based on a count width for multi-epc streams.
std::shared_ptr< Type > last(int width, bool on_primitive)
Fletcher last.
NodeProfilerPorts EnableStreamProfiling(cerata::Component *comp, const std::vector< cerata::Signal * > &profile_nodes)
Transforms a Cerata component graph to include stream profilers for selected nodes.
std::vector< MmioReg > GetProfilingRegs(const std::vector< std::shared_ptr< RecordBatch >> &recordbatches)
Obtain the registers that should be reserved in the mmio component for profiling.
std::optional< cerata::Port * > GetClockResetPort(cerata::Graph *graph, const ClockDomain &domain)
Return the clock/reset port of a graph for a specific clock domain, if it exists.
Structure to represent an MMIO register.