P4C
The P4 Compiler
Loading...
Searching...
No Matches
table_dependency_graph.h
1
19#ifndef BF_P4C_MAU_TABLE_DEPENDENCY_GRAPH_H_
20#define BF_P4C_MAU_TABLE_DEPENDENCY_GRAPH_H_
21
22#include <map>
23#include <optional>
24#include <set>
25
26#include <boost/graph/adjacency_list.hpp>
27#include <boost/graph/transitive_closure.hpp>
28
29#include "backends/tofino/bf-p4c/common/asm_output.h"
30#include "backends/tofino/bf-p4c/device.h"
31#include "backends/tofino/bf-p4c/ir/control_flow_visitor.h"
32#include "backends/tofino/bf-p4c/logging/pass_manager.h"
33#include "backends/tofino/bf-p4c/mau/mau_visitor.h"
34#include "backends/tofino/bf-p4c/mau/reduction_or.h"
35#include "backends/tofino/bf-p4c/mau/table_flow_graph.h"
36#include "backends/tofino/bf-p4c/mau/table_mutex.h"
37#include "backends/tofino/bf-p4c/phv/phv_fields.h"
38
39using namespace P4;
40
41/* The DependencyGraph data structure is a directed graph in which tables are
42 * vertices and edges are dependencies. An edge from t1 to t2 means that t2
43 * depends on t1.
44 *
45 * Edges are annotated with the kind of dependency that exists between tables.
46 * Note that there may be more than one edge from one table to another, each
47 * representing a different dependency.
48 *
49 */
50class TableGraphNode;
51class TableSummary;
53 typedef enum {
54 MAU_DEP_MATCH = 2, // Field written is read at match input crossbar.
55 MAU_DEP_ACTION = 1, // Field written is read and/or written at PHV ALU.
56 MAU_DEP_CONCURRENT = 0 // No dependency.
57 } mau_dependencies_t;
58 typedef enum {
59 NONE = 1, // No dependence label.
60 CONTROL_ACTION = (1 << 1), // Control dependence due to action.
61 CONTROL_COND_TRUE = (1 << 2), // Control dependence due to gateway
62 // true condition.
63 CONTROL_COND_FALSE = (1 << 3), // Control dependence due to gateway
64 // false condition.
65 CONTROL_TABLE_HIT = (1 << 4), // Control dependence due to a table hit.
66 CONTROL_TABLE_MISS = (1 << 5), // Control dependence due to a table miss.
67 CONTROL_DEFAULT_NEXT_TABLE = (1 << 6), // Control dependence due to default next table.
68 CONTROL_EXIT = (1 << 19), // Control dependence due to tables needing to
69 // run last, before exit. (Tofino only!)
70 IXBAR_READ = (1 << 7), // Read-after-write (data) dependence.
71 ACTION_READ = (1 << 8), // Read-after-write dependence.
72 // Different from IXBAR_READ for power analysis.
73 OUTPUT = (1 << 9), // Write-after-write (output) dependence.(ACTION?)
74 REDUCTION_OR_READ = (1 << 10), // Read-after-write dependence,
75 // Not a true dependency as hardware supports
76 // OR'n on action data bus.
77 REDUCTION_OR_OUTPUT = (1 << 11), // Write-after-write dependece,
78 // Not a true dependency as hardware supports
79 // OR'n on action data bus.
80 CONT_CONFLICT = (1 << 12), // Container Conflict between 2 tables sharing
81 // the same container
82 ANTI_EXIT = (1 << 13), // Dependency due to an action with exit
83 ANTI_TABLE_READ = (1 << 14), // Action Write to a field read as
84 // a previous table key
85 ANTI_ACTION_READ = (1 << 15), // Action Write to a field read as
86 // a previous table action
87 ANTI_NEXT_TABLE_DATA = (1 << 16), // Data dependency between tables in
88 // separate blocks
89 ANTI_NEXT_TABLE_CONTROL = (1 << 17), // Injected Control Dependency due to next
90 // table control flow
91 ANTI_NEXT_TABLE_METADATA = (1 << 18), // Injected Data Dep due to a metadata field
92 CONCURRENT = 0 // No dependency.
93 } dependencies_t;
94 static const unsigned ANTI = ANTI_EXIT | ANTI_TABLE_READ | ANTI_ACTION_READ |
95 ANTI_NEXT_TABLE_DATA | ANTI_NEXT_TABLE_METADATA;
96 static const unsigned CONTROL =
97 CONTROL_ACTION | CONTROL_COND_TRUE | CONTROL_COND_FALSE | CONTROL_TABLE_HIT |
98 CONTROL_TABLE_MISS | CONTROL_DEFAULT_NEXT_TABLE | CONTROL_EXIT | ANTI_NEXT_TABLE_CONTROL;
99 static const unsigned CONTROL_AND_ANTI = CONTROL | ANTI;
100 typedef boost::adjacency_list<
101 boost::vecS, boost::vecS,
102 boost::bidirectionalS, // Directed edges.
103 boost::property<boost::vertex_table_t, const IR::MAU::Table *>, // Vertex labels
104 dependencies_t // Edge labels.
105 >
106 Graph;
107 ReductionOrInfo red_info;
108
147
153
154 Graph g; // Dependency graph.
155
156 // True once the graph has been fully constructed.
157 bool finalized;
158
159 private:
160 void check_finalized() const {
161 if (!finalized) BUG("Dependency graph used before being fully constructed.");
162 }
163
164 void check_stage_info_exist(const IR::MAU::Table *t) const {
165 if (!stage_info.count(t)) {
166 BUG("table not exists in Dependency graph: %1%", cstring::to_cstring(t));
167 }
168 }
169
170 typedef DependencyGraph::Graph::edge_descriptor GraphEdge;
171 struct cycle_detector : public boost::dfs_visitor<> {
172 cycle_detector(DependencyGraph &dg, bool &has_cycle) : _dg(dg), _has_cycle(has_cycle) {}
173
174 void back_edge(const GraphEdge e, const DependencyGraph::Graph &g) {
175 auto source = _dg.get_vertex(boost::source(e, g));
176 auto target = _dg.get_vertex(boost::target(e, g));
177 LOG6(" Found back-edge : " << source->name << " ==> " << target->name);
178 _has_cycle = true;
179 }
180
181 protected:
182 DependencyGraph &_dg;
183 bool &_has_cycle;
184 };
185
186 // For GTests Only
187 public:
189
190 // NOTE: These maps are reverse named -- happens_after_map[t] is the set of tables that that are
191 // before t, while happens_before_map[t] is the set of tables that are after t... This naming
192 // comes from the idea that t must happen after anything in the set given by
193 // happens_after_map[t] ("t happens after what is in happens_after_map[t]")
194
195 // NOTE: happens_after/before_map are "work lists," used by functions in this file to calculate
196 // other happens.*_maps. As such, it is much more prefereable to NOT use them externally. Use
197 // the appropriately named map for your situation, which is better for readability
198 // anyhow. Currently, happens_after/before_map ends up being the same as
199 // happens_phys_after/before_map, although this could change.
200
201 // Work happens after map
203
204 // Work happens before map
206 happens_before_work_map;
207
208 // For a given table t, happens_phys_after_map[t] is the set of tables that must be placed in an
209 // earlier stage than t---i.e. there is a data dependence between t and any table in the
210 // set. This is the default result of the calc_topological_stage function.
212
213 // Analagous to above, but for the tables that must be placed in a later stage than t
215 happens_phys_before_map;
216
217 // Same as happens_phys_before_map, with the additional inclusion of control dependences when
218 // calculating the happens_before relationship.
220 happens_before_control_map;
221
222 // Same as happens_phys_after_map, with the additional inclusion of control and anti dependences
223 // when calculating the happens_after relationship, which corresponds to an ordering on logical
224 // IDs.
226
227 // Analagous to above, but for tables that must be placed into a later logical ID than t. New
228 // name for happens_before_control_anti_map
230 happens_logi_before_map;
231
233 dep_type_map;
234
236
237 // Map from <t1, t2> to its dependency type
238 // e.g. <tbl1, tbl2> = MATCH means that tbl1 has a match dependency on tbl2
240 DependencyGraph::dependencies_t>
241 dependency_map;
242
243 ordered_map<typename Graph::edge_descriptor,
246 data_annotations;
247
249 data_annotations_exit;
253
254 // Note: these maps only make sense if there is a PHV allocation.
255 // Map from table to PHV containers written.
256 std::map<const IR::MAU::Table *, std::map<const PHV::Container, bool>> containers_write_ = {};
257 // Map from table to PHV containers read at the match input crossbar.
258 std::map<const IR::MAU::Table *, std::map<const PHV::Container, bool>> containers_read_xbar_ =
259 {};
260 // Map from table to PHV containers read at the PHV ALUs.
261 std::map<const IR::MAU::Table *, std::map<const PHV::Container, bool>> containers_read_alu_ =
262 {};
263 // Map to memoize results of calls to "find_mau_dependency"
264 // This map uses the hardware terminology for MAU stage dependencies,
265 // so dependencies_t is not used.
266 std::map<std::pair<const IR::MAU::Table *, const IR::MAU::Table *>,
267 DependencyGraph::mau_dependencies_t>
268 table_dep_ = {};
269
270 struct StageInfo {
271 int min_stage, // Minimum stage at which a table can be placed.
272 max_stage, // Maximum stage at which a table must be placed (inclusive).
273 dep_stages, // Number of tables that depend on this table and
274 // must be placed in a stage after it.
275 dep_stages_control, dep_stages_control_anti, dep_stages_control_anti_split,
276 dep_stages_dom_frontier;
277 };
278
280
281 using MinEdgeInfo = std::pair<const IR::MAU::Table *, dependencies_t>;
282 bool display_min_edges = false;
284
288 int max_min_stage_per_gress[3] = {-1, -1, -1};
289 int max_min_stage = -1;
290
291 std::vector<ordered_set<DependencyGraph::Graph::vertex_descriptor>> vertex_rst;
292
293 // Json variables
294 cstring passContext;
295 bool placed = false;
296
297 DependencyGraph(void) { finalized = false; }
298
299 void clear() {
300 container_conflicts.clear();
301 g.clear();
302 finalized = false;
303 max_min_stage = -1;
304 name_to_table.clear();
305 happens_after_work_map.clear();
306 happens_before_work_map.clear();
307 happens_phys_after_map.clear();
308 happens_before_control_map.clear();
309 happens_logi_after_map.clear();
310 happens_logi_before_map.clear();
311 dep_type_map.clear();
312 labelToVertex.clear();
313 dependency_map.clear();
314 data_annotations.clear();
315 data_annotations_exit.clear();
316 data_annotations_conflicts.clear();
317 data_annotations_metadata.clear();
318 ctrl_annotations.clear();
319 stage_info.clear();
320 min_stage_edges.clear();
321 for (unsigned i = 0; i < 3; i++) max_min_stage_per_gress[i] = -1;
322 display_min_edges = false;
323 vertex_rst.clear();
324 passContext = ""_cs;
325 placed = false;
326 containers_write_.clear();
327 containers_read_xbar_.clear();
328 containers_read_alu_.clear();
329 table_dep_.clear();
330 }
331
336 bool include_stages, const TableSummary *summary);
337
339 bool is_anti_edge(DependencyGraph::dependencies_t dep) const;
340
342 bool is_ctrl_edge(DependencyGraph::dependencies_t dep) const;
343
346 bool is_non_directional_edge(DependencyGraph::dependencies_t dep) const;
347
350 bool is_edge_critical(typename Graph::edge_descriptor e) const;
351
353 int critical_path_length() const { return (1 + max_min_stage); }
354
355 // For a src -> dst edge check if back edge dst -> src exists
356 bool has_back_edge(const IR::MAU::Table *src, const IR::MAU::Table *dst) {
357 bool backEdgePresent = false;
358 DependencyGraph::Graph::edge_descriptor backEdge;
359
360 auto src_v = labelToVertex.at(dst);
361 auto dst_v = labelToVertex.at(src);
362 boost::tie(backEdge, backEdgePresent) = boost::edge(src_v, dst_v, g);
363
364 return backEdgePresent;
365 }
366
367 // Check for cycle in the graph
368 bool has_cycle() {
369 bool has_cycle = false;
370 cycle_detector vis(*this, has_cycle);
371 boost::depth_first_search(g, visitor(vis));
372 return has_cycle;
373 }
374
375 /* @returns the table pointer corresponding to a vertex in the dependency graph
376 */
377 const IR::MAU::Table *get_vertex(typename Graph::vertex_descriptor v) const {
378 return boost::get(boost::vertex_table, g)[v];
379 }
380
381 /* If a vertex with this label already exists, return it. Otherwise,
382 * create a new vertex with this label. */
383 typename Graph::vertex_descriptor add_vertex(const IR::MAU::Table *label) {
384 if (labelToVertex.count(label)) {
385 return labelToVertex.at(label);
386 } else {
387 auto v = boost::add_vertex(label, g);
388 labelToVertex[label] = v;
389 stage_info[label] = {0, 0, 0, 0, 0, 0, 0};
390 return v;
391 }
392 }
393
394 /* Return an edge descriptor. If bool is true, then this is a
395 * newly-created edge. If false, then the edge descriptor points to the
396 * edge from src to dst with edge_label that already existed. */
397 std::pair<typename Graph::edge_descriptor *, bool> add_edge(const IR::MAU::Table *src,
398 const IR::MAU::Table *dst,
399 dependencies_t edge_label);
400
401 bool container_conflict(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
402 if (container_conflicts.find(t1) == container_conflicts.end()) return false;
403 if (container_conflicts.at(t1).find(t2) == container_conflicts.at(t1).end()) return false;
404 return true;
405 }
406
407 bool unavoidable_container_conflict(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
409 return false;
410 if (unavoidable_container_conflicts.at(t1).find(t2) ==
412 return false;
413 return true;
414 }
415
416 bool happens_phys_before(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
417 check_finalized();
418 if (happens_phys_before_map.count(t1)) {
419 return happens_phys_before_map.at(t1).count(t2);
420 } else {
421 return false;
422 }
423 }
424
425 bool happens_phys_after(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
426 check_finalized();
427 if (happens_phys_after_map.count(t1)) {
428 return happens_phys_after_map.at(t1).count(t2);
429 } else {
430 return false;
431 }
432 }
433
434 // returns true if any table in s or control dependent on a table in s is
435 // data dependent on t1
436 bool happens_phys_before_recursive(const IR::MAU::Table *t1, const IR::MAU::TableSeq *s) const {
437 check_finalized();
438 if (happens_phys_before_map.count(t1))
439 for (auto *t2 : s->tables)
440 if (happens_phys_before_recursive(t1, t2)) return true;
441 return false;
442 }
443
444 // returns true if t2 or any table control dependent on it is data dependent on t1
445 bool happens_phys_before_recursive(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
446 check_finalized();
447 if (happens_phys_before_map.count(t1)) {
448 if (t2 != t1 && happens_phys_before_map.at(t1).count(t2)) return true;
449 for (auto *next : Values(t2->next))
450 if (happens_phys_before_recursive(t1, next)) return true;
451 }
452 return false;
453 }
454
455 bool happens_before_control(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
456 check_finalized();
457 if (happens_before_control_map.count(t1))
458 return happens_before_control_map.at(t1).count(t2);
459 else
460 return false;
461 }
462
463 bool happens_logi_before(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
464 check_finalized();
465 if (happens_logi_before_map.count(t1))
466 return happens_logi_before_map.at(t1).count(t2);
467 else
468 return false;
469 }
470
471 bool happens_logi_after(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const {
472 check_finalized();
473 if (happens_logi_after_map.count(t1))
474 return happens_logi_after_map.at(t1).count(t2);
475 else
476 return false;
477 }
478
479 std::optional<ordered_map<const PHV::Field *, std::pair<ordered_set<const IR::MAU::Action *>,
481 get_data_dependency_info(typename Graph::edge_descriptor edge) const {
482 if (!data_annotations.count(edge)) {
483 LOG4("Data dependency edge not found");
484 return std::nullopt;
485 }
486 return data_annotations.at(edge);
487 }
488
489 std::optional<std::string> get_ctrl_dependency_info(
490 typename Graph::edge_descriptor edge) const {
491 if (!ctrl_annotations.count(edge)) {
492 LOG4("Control dependency edge not found");
493 return std::nullopt;
494 }
495 return ctrl_annotations.at(edge);
496 }
497
498 /* Gets table dependency annotations for data dependency edges (IXBAR_READ, ACTION_READ,
499 OUTPUT, REDUCTION_OR_READ, REDUCTION_OR_OUTPUT, ANTI).
500 Parameters: Upstream table, downstream table connected by data dependency edge.
501 Returns: Data annotations map structured as follows:
502 Key -- {PHV field causing dependence, Dependence type}
503 Value -- {UpstreamActionSet, DownstreamActionSet}, where each ActionSet
504 contains all actions in which the relevant PHV field is accessed in either
505 the upstream or the downstream table involved in the dependence. If the
506 element is not accessed in any actions (i.e. an input crossbar read),
507 that particular ActionSet will be empty.
508 */
509 std::optional<ordered_map<
510 std::pair<const PHV::Field *, DependencyGraph::dependencies_t>,
511 std::pair<ordered_set<const IR::MAU::Action *>, ordered_set<const IR::MAU::Action *>>>>
512 get_data_dependency_info(const IR::MAU::Table *upstream,
513 const IR::MAU::Table *downstream) const;
514
515 void print_dep_type_map(std::ostream &out) const;
516 void print_container_access(std::ostream &out) const;
517
527 DependencyGraph::mau_dependencies_t find_mau_dependency(const IR::MAU::Table *from,
528 const IR::MAU::Table *to);
529
534 DependencyGraph::dependencies_t get_dependency(const IR::MAU::Table *t1,
535 const IR::MAU::Table *t2) const {
536 if (!finalized) BUG("Dependence graph used before being fully constructed.");
537
538 auto p = std::make_pair(t1, t2);
539 if (dependency_map.find(p) != dependency_map.end()) {
540 return dependency_map.at(p);
541 }
542 // No dependency between tables
543 return DependencyGraph::CONCURRENT;
544 }
545
546 int dependence_tail_size(const IR::MAU::Table *t) const {
547 check_finalized();
548 check_stage_info_exist(t);
549 return stage_info.at(t).dep_stages;
550 }
551
552 int dependence_tail_size_control(const IR::MAU::Table *t) const {
553 check_finalized();
554 check_stage_info_exist(t);
555 return stage_info.at(t).dep_stages_control;
556 }
557
558 int dependence_tail_size_control_anti(const IR::MAU::Table *t) const {
559 check_finalized();
560 check_stage_info_exist(t);
561 return stage_info.at(t).dep_stages_control_anti;
562 }
563
564 int dependence_tail_size_control_anti_split(const IR::MAU::Table *t) const {
565 check_finalized();
566 check_stage_info_exist(t);
567 return stage_info.at(t).dep_stages_control_anti_split;
568 }
569
570 int min_stage(const IR::MAU::Table *t) const {
571 check_finalized();
572 check_stage_info_exist(t);
573 return stage_info.at(t).min_stage;
574 }
575
576 int max_stage(const IR::MAU::Table *t) const {
577 check_finalized();
578 check_stage_info_exist(t);
579 return stage_info.at(t).max_stage;
580 }
581
582 const std::vector<const IR::MAU::Table *> &happens_before_dependences(
583 const IR::MAU::Table *t) const {
584 check_finalized();
585 return happens_before_work_map.at(t);
586 }
587
588 friend std::ostream &operator<<(std::ostream &, const DependencyGraph &);
589 static cstring dep_to_name(dependencies_t dep);
590 static void dump_viz(std::ostream &out, const DependencyGraph &dg);
591 void to_json(Util::JsonObject *dgJson, const FlowGraph &fg, cstring passContext, bool placed);
592 static dependencies_t get_control_edge_type(cstring annot);
593
594 TableGraphNode create_node(const int id, const IR::MAU::Table *tbl) const;
595};
596
598 public:
599 cstring gress;
600 cstring name;
601 int lo = -1;
602 int hi = -1;
603};
604
606 public:
607 int id = -1;
608 int source = -1;
609 int target = -1;
610 int phv_number = -1;
611 cstring action_name = ""_cs;
612 cstring exit_action_name = ""_cs;
613 bool is_critical = false;
614
615 std::vector<TableGraphField> dep_fields;
616 std::vector<cstring> tags;
617 bool condition_value;
618 DependencyGraph::dependencies_t label;
619
620 // Static maps
625
626 bool add_dep_field(const PHV::Field *s) {
627 if (!s) return false;
628
630 f.name = cstring::to_cstring(canon_name(s->name));
631 f.gress = toString(s->gress);
632 f.lo = 0;
633 f.hi = s->size - 1;
634 dep_fields.push_back(f);
635 LOG5(" Adding Dep Field: " << f.name << "[" << f.hi << ":" << f.lo << "] (" << f.gress
636 << ")");
637 return true;
638 }
639
640 void add_dep_fields_json(Util::JsonObject *edgeMdJson) {
641 Util::JsonArray *edgeMdDepFields = new Util::JsonArray();
642 if (dep_fields.size() > 0) {
643 for (auto field : dep_fields) {
644 Util::JsonObject *edgeMdDepField = new Util::JsonObject();
645 edgeMdDepField->emplace("gress"_cs, field.gress);
646 edgeMdDepField->emplace("field_name"_cs, field.name);
647 edgeMdDepField->emplace("start_bit"_cs, field.lo);
648 edgeMdDepField->emplace("width"_cs, field.hi - field.lo + 1);
649 edgeMdDepFields->append(edgeMdDepField);
650 }
651 }
652 edgeMdJson->emplace("dep_fields"_cs, edgeMdDepFields);
653 }
654
655 void add_action_name_json(Util::JsonObject *edgeMdJson) {
656 auto act_name = cstring::to_cstring(canon_name(action_name));
657 edgeMdJson->emplace("action_name"_cs, act_name);
658 }
659
660 void add_exit_action_name_json(Util::JsonObject *edgeMdJson) {
661 auto act_name = cstring::to_cstring(canon_name(exit_action_name));
662 edgeMdJson->emplace("action_name"_cs, act_name);
663 }
664
665 void add_phv_number_json(Util::JsonObject *edgeMdJson) {
666 edgeMdJson->emplace("phv_number"_cs, phv_number);
667 }
668
669 void add_condition_value_json(Util::JsonObject *edgeMdJson) {
670 if (labels_to_conds.count(label) == 0)
671 BUG("Invalid edge type. Cannot determine condition value");
672 bool condition_value = labels_to_conds[label];
673 edgeMdJson->emplace("condition_value"_cs, condition_value);
674 }
675
676 void add_anti_type_json(Util::JsonObject *edgeMdJson) {
677 if (labels_to_anti_types.count(label) == 0)
678 BUG("Invalid edge type. Cannot determine anti type");
679
680 auto anti_type = labels_to_anti_types[label];
681 edgeMdJson->emplace("anti_type"_cs, anti_type);
682 }
683
684 void add_type_json(Util::JsonObject *edgeMdJson) {
685 if (labels_to_types.count(label) == 0) BUG("Invalid edge type");
686
687 auto type = labels_to_types[label];
688 edgeMdJson->emplace("type"_cs, type);
689 }
690
691 void add_sub_type_json(Util::JsonObject *edgeMdJson) {
692 if (labels_to_sub_types.count(label) == 0)
693 BUG("Invalid edge type. Cannot determine sub type.");
694
695 auto sub_type = labels_to_sub_types[label];
696 edgeMdJson->emplace("sub_type"_cs, sub_type);
697 }
698
699 Util::JsonObject *create_edge_md_json() {
700 Util::JsonObject *edgeMdJson = new Util::JsonObject();
701
702 add_type_json(edgeMdJson);
703 add_sub_type_json(edgeMdJson);
704
705 switch (label) {
706 case DependencyGraph::IXBAR_READ:
707 add_dep_fields_json(edgeMdJson);
708 break;
709
710 case DependencyGraph::ACTION_READ:
711 add_dep_fields_json(edgeMdJson);
712 add_action_name_json(edgeMdJson);
713 break;
714
715 case DependencyGraph::OUTPUT:
716 add_dep_fields_json(edgeMdJson);
717 break;
718
719 case DependencyGraph::CONT_CONFLICT:
720 add_phv_number_json(edgeMdJson);
721 break;
722
723 case DependencyGraph::REDUCTION_OR_READ:
724 case DependencyGraph::REDUCTION_OR_OUTPUT:
725 add_dep_fields_json(edgeMdJson);
726 break;
727
728 case DependencyGraph::ANTI_TABLE_READ:
729 case DependencyGraph::ANTI_ACTION_READ:
730 case DependencyGraph::ANTI_NEXT_TABLE_DATA:
731 case DependencyGraph::ANTI_NEXT_TABLE_CONTROL:
732 case DependencyGraph::ANTI_NEXT_TABLE_METADATA:
733 add_anti_type_json(edgeMdJson);
734 add_dep_fields_json(edgeMdJson);
735 break;
736
737 case DependencyGraph::ANTI_EXIT:
738 add_exit_action_name_json(edgeMdJson);
739 break;
740
741 case DependencyGraph::CONTROL_ACTION:
742 add_action_name_json(edgeMdJson);
743 break;
744
745 case DependencyGraph::CONTROL_COND_TRUE:
746 case DependencyGraph::CONTROL_COND_FALSE:
747 add_condition_value_json(edgeMdJson);
748 break;
749
750 case DependencyGraph::CONTROL_TABLE_HIT:
751 case DependencyGraph::CONTROL_TABLE_MISS:
752 case DependencyGraph::CONTROL_DEFAULT_NEXT_TABLE:
753 case DependencyGraph::CONTROL_EXIT:
754 break;
755
756 /* Should never reach here */
757 default:
758 BUG("Invalid dependency graph edge type");
759 }
760
761 if (is_critical) edgeMdJson->emplace("is_critical"_cs, is_critical);
762
763 if (tags.size() > 0) {
764 Util::JsonArray *edgeMdTags = new Util::JsonArray();
765 for (auto t : tags) edgeMdTags->append(t);
766 edgeMdJson->emplace("tags"_cs, edgeMdTags);
767 }
768
769 return edgeMdJson;
770 }
771
772 Util::JsonObject *create_edge_json() {
773 Util::JsonObject *edgeJson = new Util::JsonObject();
774 edgeJson->emplace("id"_cs, new Util::JsonValue(std::to_string(id)));
775 edgeJson->emplace("source"_cs, new Util::JsonValue(std::to_string(source)));
776 edgeJson->emplace("target"_cs, new Util::JsonValue(std::to_string(target)));
777 edgeJson->emplace("metadata"_cs, create_edge_md_json());
778 return edgeJson;
779 }
780};
781
783 public:
784 int id = -1;
785 int logical_id = -1;
786 int stage_number = -1;
787 int min_stage = -1;
788 int dep_chain = -1;
789
791 public:
792 cstring name = ""_cs;
793 cstring table_type = ""_cs;
794 cstring match_type = ""_cs;
795 cstring condition = ""_cs;
796 };
797 std::vector<TableGraphNodeTable> nodeTables;
798
799 static cstring get_node_match_type(const IR::MAU::Table *tbl) {
800 auto match_type = tbl->get_table_type_string();
801 if (match_type == "exact_match")
802 return "exact"_cs;
803 else if (match_type == "ternary_match")
804 return "ternary"_cs;
805 else if (match_type == "proxy_hash")
806 return "proxy_hash"_cs;
807 else if (match_type == "hash_action")
808 return "hash_action"_cs;
809 else if (tbl->layout.pre_classifier || tbl->layout.alpm)
810 return "algorithmic_lpm"_cs;
811 else if (match_type == "atcam_match")
812 return "algorithmic_tcam"_cs;
813 return "none"_cs;
814 }
815
816 static cstring get_attached_table_type(const IR::MAU::AttachedMemory *att) {
817 if (att->to<IR::MAU::Counter>())
818 return "statistics"_cs;
819 else if (att->to<IR::MAU::Meter>())
820 return "meter"_cs;
821 else if (att->to<IR::MAU::StatefulAlu>())
822 return "stateful"_cs;
823 else if (att->to<IR::MAU::Selector>())
824 return "selection"_cs;
825 else if (att->to<IR::MAU::ActionData>())
826 return "action"_cs;
827 else if (att->to<IR::MAU::TernaryIndirect>())
828 return "ternary_indirect"_cs;
829 else if (att->to<IR::MAU::IdleTime>())
830 return "idletime"_cs;
831 return "none"_cs;
832 }
833
834 Util::JsonObject *create_node_md_json() {
835 Util::JsonObject *nodeMdJson = new Util::JsonObject();
836
837 if (logical_id >= 0 && stage_number >= 0) {
838 Util::JsonObject *placement = new Util::JsonObject();
839 placement->emplace("logical_table_id"_cs, new Util::JsonValue(logical_id));
840 placement->emplace("stage_number"_cs, new Util::JsonValue(stage_number));
841 nodeMdJson->emplace("placement"_cs, placement);
842 }
843
844 Util::JsonArray *nodesTJsons = new Util::JsonArray();
845 for (auto n : nodeTables) {
846 Util::JsonObject *nodeTJson = new Util::JsonObject();
847 nodeTJson->emplace("name"_cs, new Util::JsonValue(n.name));
848 nodeTJson->emplace("table_type"_cs, new Util::JsonValue(n.table_type));
849 if (n.table_type == "match")
850 nodeTJson->emplace("match_type"_cs, new Util::JsonValue(n.match_type));
851 if (n.table_type == "condition")
852 nodeTJson->emplace("condition"_cs, new Util::JsonValue(n.condition));
853 nodesTJsons->append(nodeTJson);
854 }
855 nodeMdJson->emplace("tables"_cs, nodesTJsons);
856 nodeMdJson->emplace("min_stage"_cs, min_stage);
857 nodeMdJson->emplace("dep_chain"_cs, dep_chain);
858 return nodeMdJson;
859 }
860
861 Util::JsonObject *create_node_json() {
862 Util::JsonObject *nodeJson = new Util::JsonObject();
863 nodeJson->emplace("id"_cs, std::to_string(id));
864 nodeJson->emplace("metadata"_cs, create_node_md_json());
865 return nodeJson;
866 }
867};
868
870 DependencyGraph &dg;
871 bool preorder(const IR::MAU::Table *tbl) override;
872
873 public:
874 explicit NameToTableMapBuilder(DependencyGraph &d) : dg(d) {}
875};
876
878 public:
879 using write_op_t = std::pair<PHV::FieldSlice, bitvec>;
888
889 private:
890 const PhvInfo &phv;
891 DependencyGraph &dg;
892 const TablesMutuallyExclusive &mutex;
893 const IgnoreTableDeps &ignore;
897
898 bool preorder(const IR::MAU::TableSeq *) override;
899 bool preorder(const IR::MAU::Table *) override;
900 bool preorder(const IR::MAU::Action *) override;
901 bool preorder(const IR::MAU::TableKey *) override;
902
903 Visitor::profile_t init_apply(const IR::Node *node) override {
904 auto rv = Inspector::init_apply(node);
905 access.clear();
906 cont_write.clear();
907 red_or_use.clear();
908
910 LOG4("Printing alias map");
911 for (auto kv : aliasMap)
912 LOG4(" " << kv.first->name << " aliases with " << kv.second->name);
913
914 return rv;
915 }
916
917 std::set<cstring> getFieldNameSlice(const PHV::Field *field, le_bitrange range) const;
918 void flow_merge(Visitor &v) override;
919 void flow_copy(::ControlFlowVisitor &v) override;
920 // Filter out the table sequence and revisit them again.
921 bool filter_join_point(const IR::Node *n) override { return !n->is<IR::BFN::ParserState>(); }
922
923 // void all_bfs(boost::default_bfs_visitor* vis);
924 FindDataDependencyGraph *clone() const override { return new FindDataDependencyGraph(*this); }
925
926 class AddDependencies;
927 class UpdateAccess;
928 class UpdateAttached;
929
930 public:
932 const TablesMutuallyExclusive &m, const IgnoreTableDeps &ig)
933 : phv(phv), dg(out), mutex(m), ignore(ig) {
934 joinFlows = true;
935 }
936};
937
939 using NextTableLeaves =
943
944 public:
949
953
954 private:
955 void postorder(const IR::MAU::Table *) override;
956 Visitor::profile_t init_apply(const IR::Node *node) override {
957 auto rv = MauInspector::init_apply(node);
958 next_table_leaves.clear();
959 control_dom_set.clear();
960 name_to_table.clear();
961 return rv;
962 }
963
964 public:
965 const IR::MAU::Table *get_table(cstring name) const {
966 if (name_to_table.count(name)) return name_to_table.at(name);
967 return nullptr;
968 }
969 CalculateNextTableProp() { visitDagOnce = false; }
970};
971
973 public:
977
981
982 private:
983 Visitor::profile_t init_apply(const IR::Node *node) override {
984 auto rv = MauInspector::init_apply(node);
985 table_pathways.clear();
986 return rv;
987 }
988
989 bool equiv(const Path &a, const Path &b) const;
990 bool equiv_seqs(const IR::MAU::TableSeq *a, const IR::MAU::TableSeq *b) const;
991 bool preorder(const IR::MAU::Table *) override;
992 Path common_reverse_path(const Path &a, const Path &b, bool check_diff_if_seq = false) const;
993
994 public:
995 void print_paths(safe_vector<Path> &paths) const;
996 const IR::MAU::Table *find_dominator(const IR::MAU::Table *init) const;
997 InjectPoints get_inject_points(const IR::MAU::Table *a, const IR::MAU::Table *b,
998 bool tbls_only = true) const;
999 ControlPathwaysToTable() { visitDagOnce = false; }
1000};
1001
1003
1005 const CalculateNextTableProp &ntp;
1006 DependencyGraph &dg;
1007 FindDependencyGraph &self;
1008 const TableSummary *summary;
1009
1010 void postorder(const IR::MAU::Table *) override;
1011
1012 public:
1014 FindDependencyGraph &s, const TableSummary *ts)
1015 : ntp(n), dg(d), self(s), summary(ts) {}
1016};
1017
1018class PrintPipe : public MauInspector {
1019 bool preorder(const IR::BFN::Pipe *p) override;
1020
1021 public:
1022 PrintPipe() {}
1023};
1024
1026 DependencyGraph &dg;
1027 bool preorder(const IR::MAU::Table *t);
1028
1029 public:
1030 explicit FindCtrlDependencyGraph(DependencyGraph &out) : dg(out) {}
1031};
1032
1036 void verify_dependence_graph(void);
1037 void finalize_dependence_graph(void);
1038 void calc_max_min_stage();
1039
1040 Visitor::profile_t init_apply(const IR::Node *node) override;
1042 DependencyGraph &dg;
1043 const BFN_Options *options;
1044 FlowGraph fg;
1045 ControlPathwaysToTable con_paths;
1047 IgnoreTableDeps ignore;
1048 cstring dotFile;
1049 cstring passContext;
1050 const TableSummary *summary;
1051
1052 void end_apply(const IR::Node *root) override;
1053 void add_logical_deps_from_control_deps();
1054
1055 public:
1056 std::vector<ordered_set<DependencyGraph::Graph::vertex_descriptor>> calc_topological_stage(
1057 unsigned deps_flag = 0, DependencyGraph *dg_p = nullptr);
1058 FindDependencyGraph(const PhvInfo &, DependencyGraph &out, const BFN_Options *o = nullptr,
1059 cstring dotFileName = ""_cs, cstring passContext = ""_cs,
1060 const TableSummary *s = nullptr);
1061};
1062
1064 int min_path_len = 0;
1065 cstring pipe_name;
1066 const DependencyGraph &dg;
1067 std::map<DependencyGraph::Graph::vertex_descriptor, cstring> vertex_names;
1068 std::map<DependencyGraph::Graph::edge_descriptor, cstring> edge_names;
1069 std::map<bitvec, char> bitvec_to_char;
1070 std::map<char, bitvec> char_to_bitvec;
1071 bool preorder(const IR::BFN::Pipe *t) override;
1072 void end_apply(const IR::Node *root) override;
1073 char encode_dependencies(const DependencyGraph::Graph::vertex_descriptor &src_v,
1074 const DependencyGraph::Graph::vertex_descriptor &dst_v);
1075 std::string print_dependencies(bitvec deps);
1076
1077 public:
1078 explicit PrintDependencyGraph(const DependencyGraph &out) : dg(out) {}
1079 std::stringstream print_graph(const DependencyGraph &g);
1080
1081 // DFS traversal of table dependency graph but starting from the
1082 // last min_stage tables toward min_stage 0.
1083 void reverse_dfs(const IR::MAU::Table *tbl, std::stack<const IR::MAU::Table *> &chain,
1084 std::vector<std::vector<const IR::MAU::Table *>> &crit_chains,
1085 std::map<const IR::MAU::Table *, bool> &visited_tbls, int last_stage);
1086
1087 // Print critical table dependency chains that cross at least
1088 // 70% of the device stages (e.g. for Tofino: chains >= floor(12 * 0.7) = 8 stages
1089 void print_critical_chains(const DependencyGraph &g);
1090};
1091
1092// Print a summary of the dependency graph in ascii
1094 const DependencyGraph &dg;
1095
1096 public:
1098 : Logging::PassManager("table_dependency_summary"_cs, Logging::Mode::AUTO), dg(d) {
1099 passes.push_back(new PrintDependencyGraph(dg));
1100 }
1101};
1102
1103std::ostream &operator<<(std::ostream &, DependencyGraph::dependencies_t);
1104
1105#endif /* BF_P4C_MAU_TABLE_DEPENDENCY_GRAPH_H_ */
Definition bf-p4c-options.h:28
Definition table_dependency_graph.h:938
ControlDominatingSet control_dom_set
Definition table_dependency_graph.h:952
NextTableLeaves next_table_leaves
Definition table_dependency_graph.h:948
Definition table_dependency_graph.h:972
const IR::MAU::Table * find_dominator(const IR::MAU::Table *init) const
Definition mau/table_dependency_graph.cpp:1914
TablePathways table_pathways
Definition table_dependency_graph.h:980
InjectPoints get_inject_points(const IR::MAU::Table *a, const IR::MAU::Table *b, bool tbls_only=true) const
Definition mau/table_dependency_graph.cpp:1790
Definition table_dependency_graph.h:1004
Definition table_dependency_graph.h:1025
Definition table_dependency_graph.h:877
Definition table_dependency_graph.h:881
Definition table_dependency_graph.h:1033
std::vector< ordered_set< DependencyGraph::Graph::vertex_descriptor > > calc_topological_stage(unsigned deps_flag=0, DependencyGraph *dg_p=nullptr)
Definition mau/table_dependency_graph.cpp:1528
Definition mau/table_mutex.h:36
Definition backends/tofino/bf-p4c/logging/pass_manager.h:36
Definition mau_visitor.h:29
Definition table_dependency_graph.h:869
Definition visitor.h:463
Definition node.h:94
Definition visitor.h:400
Definition json.h:115
Definition json.h:164
Definition json.h:50
Definition visitor.h:78
Definition visitor.h:75
Definition bitvec.h:120
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition phv_fields.h:154
int size
Total size of Field in bits.
Definition phv_fields.h:194
cstring name
Definition phv_fields.h:161
gress_t gress
Whether the Field is ingress or egress.
Definition phv_fields.h:167
Definition phv_fields.h:1095
const ordered_map< const PHV::Field *, const PHV::Field * > & getAliasMap() const
Definition phv_fields.h:1646
Definition table_dependency_graph.h:1063
Definition table_dependency_graph.h:1018
Definition table_dependency_graph.h:1093
Definition table_dependency_graph.h:605
Definition table_dependency_graph.h:597
Definition table_dependency_graph.h:782
Definition table_dependency_graph.h:790
Definition table_summary.h:158
Definition mau/table_mutex.h:110
Definition assoc.h:403
Definition common/asm_output.h:35
@ AUTO
Creates if this is the first time writing to the log; otherwise, appends.
Definition filelog.h:43
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition table_dependency_graph.h:52
ordered_map< const IR::MAU::Table *, ordered_set< const IR::MAU::Table * > > unavoidable_container_conflicts
Definition table_dependency_graph.h:152
ordered_map< const IR::MAU::Table *, ordered_set< const IR::MAU::Table * > > container_conflicts
Definition table_dependency_graph.h:146
DependencyGraph::dependencies_t get_dependency(const IR::MAU::Table *t1, const IR::MAU::Table *t2) const
Definition table_dependency_graph.h:534
bool is_edge_critical(typename Graph::edge_descriptor e) const
Definition mau/table_dependency_graph.cpp:1369
int critical_path_length() const
Definition table_dependency_graph.h:353
bool is_ctrl_edge(DependencyGraph::dependencies_t dep) const
Definition mau/table_dependency_graph.cpp:1356
bool is_non_directional_edge(DependencyGraph::dependencies_t dep) const
Definition mau/table_dependency_graph.cpp:1364
DependencyGraph::mau_dependencies_t find_mau_dependency(const IR::MAU::Table *from, const IR::MAU::Table *to)
Definition mau/table_dependency_graph.cpp:1422
bool is_anti_edge(DependencyGraph::dependencies_t dep) const
Definition mau/table_dependency_graph.cpp:1348
int max_min_stage_per_gress[3]
Definition table_dependency_graph.h:288
void fill_dep_stages_from_topo(const std::vector< ordered_set< DependencyGraph::Graph::vertex_descriptor > > &topo, bool include_stages, const TableSummary *summary)
Definition mau/table_dependency_graph.cpp:1309
Definition table_dependency_graph.h:270
Definition table_flow_graph.h:45
bool is() const noexcept
Definition rtti.h:216
Definition reduction_or.h:47