P4C
The P4 Compiler
Loading...
Searching...
No Matches
table_summary.h
1
19#ifndef BF_P4C_MAU_TABLE_SUMMARY_H_
20#define BF_P4C_MAU_TABLE_SUMMARY_H_
21
22#include <iostream>
23#include <map>
24
25#include "backends/tofino/bf-p4c/device.h"
26#include "backends/tofino/bf-p4c/mau/mau_visitor.h"
27#include "backends/tofino/bf-p4c/mau/resource.h"
28#include "backends/tofino/bf-p4c/mau/resource_estimate.h"
29#include "backends/tofino/bf-p4c/mau/table_dependency_graph.h"
30#include "backends/tofino/bf-p4c/mau/table_layout.h"
31
32namespace Logging {
33class FileLog;
34}
35
36using namespace P4;
37
38struct PHVTrigger {
39 // stopTableReplayFitting is only for alt-phv-alloc, if the heuristics for fixing problematic
40 // table during table replay creates impossible phv constraints, fall back to ALT_FINALIZE_TABLE
41 struct failure : public Backtrack::trigger {
43 ordered_map<cstring, ordered_set<int>> internalTableAlloc;
45 bool metaInitDisable;
46 bool ignorePackConflicts;
47 bool firstRoundFit;
48 bool stopTableReplayFitting;
50 ordered_map<cstring, ordered_set<int>> internalTables,
51 ordered_map<cstring, std::pair<cstring, cstring>> mergedGateways, bool fit,
52 bool pack = false, bool meta = false, bool stop = false)
53 : trigger(OTHER),
54 tableAlloc(tables),
55 internalTableAlloc(internalTables),
56 mergedGateways(mergedGateways),
57 metaInitDisable(meta),
58 ignorePackConflicts(pack),
59 firstRoundFit(fit),
60 stopTableReplayFitting(stop) {}
61
62 DECLARE_TYPEINFO(failure);
63 };
64};
65
67 struct failure : public Backtrack::trigger {
68 bool ignoreContainerConflicts = false;
69 explicit failure(bool ig) : trigger(OTHER), ignoreContainerConflicts(ig) {}
70
71 DECLARE_TYPEINFO(failure);
72 };
73};
74
75/************************
76 * Table Placement/PHV allocation backtracktracking and retries
77 *
78 * There are various possible reasons that PHV allocation and/or Table Placement can fail
79 * in a way that requires backtracking to redo things and try alternatives to get a working
80 * allocation and placement. We track this with a 'state' in the TableSummary object which
81 * tracks what we've tried so far, and will throw an appropriate Backtrack::trigger exception
82 * to try something else.
83 *
84 * If the first attempt at PHV allocation and table placement succeeds, great! we're done.
85 * If not, we redo table placement ignoring container conflicts. After that, we'll redo
86 * PHV allocation with flags based on whether the first round fit, the redo fit, and possibly
87 * without metadata init.
88 *
89 * If that redo worked, we're good; otherwise we redo table placement ignoring container
90 * conflicts (again) and then redo PHA allocation a third time.
91 *
92 * Final Placement is a special state we get into after table placement succeeded but needed
93 * to allocate more PHV, which requires rerunning PHV then rerunning table placement.
94 *
95 * INITIAL ---> NOCC_TRY1 ---> REDO_PHV1 ---> NOCC_TRY2 ---> REDO_PHV2 --> FAILURE
96 * | / | ^
97 * \-----------> SUCCESS <------+------------------------------/ |
98 * \ |
99 * FINAL_PLACEMENT---------------------------+
100 *
101 *
102 * In the alternative PHV allocation, AKA table placement first allocation, the workflow is
103 * different. ALT_INITIAL does the trivial phv allocation, this phv allocation assumes there are
104 * infinite numbers of phv containers. And every fieldslice is allocated to the smallest possible
105 * container. And then it runs default table placement. If default table placement fails, it then
106 * runs resource based table placement with backtracking. If table placement succeeds, it goes to
107 * ALT_FINALIZE_TABLE_SAME_ORDER stage. In this stage, phv allocation has the information about
108 * every fieldslice's live range based on previous table placement result. It redoes phv allocation
109 * with liverange information. After phv allocation is finished, compiler will try to replay the
110 * table placement result from the result round. If table replay fails, it goes to
111 * ALT_FINALIZE_TABLE_SAME_ORDER_TABLE_FIXED. This stage finds the problematic table during table
112 * replay and tries to fix them by adding pa_container_size pragma. And it can be done iteratively
113 * to make table replay progress. After a finite number of attempts, if it still fails, compiler
114 * goes to ALT_FINALIZE_TABLE with all added pa_container_size removed. During ALT_FINALIZE_TABLE,
115 * it uses resource-based table placement with backtracking.
116 * ALT_FINALIZE_TABLE_SAME_ORDER_TABLE_FIXED ------------------
117 * ^ | | |
118 * | | | |
119 * SUCCESS | V V |
120 * ALT_INITIAL ---------------------> ALT_FINALIZE_TABLE_SAME_ORDER ------------> SUCCESS |
121 * (Trivial alloc) ^ (with order suggested by previous round) |
122 * ( + Default TP) | | |
123 * | | | |
124 * | | (FAILURE) <------------------------------
125 * (FAILURE) (SUCCESS) |
126 * | | V
127 * | | ALT_FINALIZE_TABLE --> SUCCESS / FAILURE
128 * .------------> ALT_RETRY_ENHANCED_TP ( Default TP
129 * (Default TP + backtracki + backtracking
130 * ( + resource-based) + resource-based)
131 * |
132 * |
133 * .--> Go back to ALT_INITIAL and use physical stage instead of
134 * minstage in the smart packer. If that still end up in this
135 * state after that -> FAILURE
136 *
137 ******************************************************************************************/
138// move the compilation state out of table summary
139namespace State {
140enum state_t {
141 INITIAL,
142 NOCC_TRY1,
143 REDO_PHV1,
144 NOCC_TRY2,
145 REDO_PHV2,
146 FINAL_PLACEMENT,
147 FAILURE,
148 SUCCESS,
149 ALT_INITIAL,
150 ALT_RETRY_ENHANCED_TP,
151 ALT_FINALIZE_TABLE_SAME_ORDER,
152 ALT_FINALIZE_TABLE_SAME_ORDER_TABLE_FIXED,
153 ALT_FINALIZE_TABLE,
154 FINAL, // always keep as last state for bounds checking
155};
156}
157
159 public:
160 static constexpr int NUM_LOGICAL_TABLES_PER_STAGE = 16;
161 static constexpr int FIRST_ALT_RETRY_ENHANCED_TP_INVOCATION = 2;
162
163 // This struct represents a placed table and its relevant info as necessary
164 // for future table placement / phv allocation rounds. It can / should be
165 // extended to add more info as required
166 // TBD: Some of the info overlaps with other maps which should be eventually
167 // depecrated to use the consolidated struct below
168 struct PlacedTable {
169 cstring tableName;
170 cstring internalTableName;
171 cstring gatewayName;
172 cstring gatewayMergeCond;
173
174 unsigned logicalId;
175
176 int stage = -1;
177 int min_stage = -1;
178 int max_stage = -1;
179 int entries = -1;
180 int entries_req = -1;
181 int srams = -1;
182 int tcams = -1;
183 int maprams = -1;
184 int ways = -1;
185 int key_size = -1;
186
187 bool gateway_only = false;
188
189 LayoutOption layout;
190
191 ordered_map<cstring, int> attached_entries;
192
193 PlacedTable(const IR::MAU::Table *t, State::state_t state, const DependencyGraph &dg);
194 void add(const IR::MAU::Table *t, State::state_t state);
195 };
196 friend std::ostream &operator<<(std::ostream &out, const PlacedTable &pl);
197 typedef enum {
198 SUCC,
199 FAIL_ON_ADB, // failure due to action data bus allocation
200 FAIL_ON_MEM, // failure due to memory allocation
201 FAIL_ON_IXBAR, // failure due to input xbar allocation
202 FAIL // other failures
203 } PlacementResult;
204 friend std::ostream &operator<<(std::ostream &out, PlacementResult result) {
205 if (result == SUCC)
206 out << "SUCC";
207 else if (result == FAIL)
208 out << "FAIL";
209 else if (result == FAIL_ON_ADB)
210 out << "FAIL_ON_ADB";
211 else if (result == FAIL_ON_MEM)
212 out << "FAIL_ON_MEM";
213 else
214 out << "FAIL_ON_IXBAR";
215 return out;
216 }
217
218 private:
219 static constexpr int CRITICAL_PATH_THRESHOLD = 2;
220 static constexpr int ALT_PHV_ALLOC_TABLE_FIX_THRESHOLD = 3;
221 int numInvoked = 0;
223 bool firstRoundFit = false;
224 Logging::FileLog *tsLog = nullptr;
225 // Save the previous state in case we have to rollback to this one.
226 State::state_t prev_state = State::INITIAL;
228 int maxStage = -1;
229 int max_stages[3];
231 bool ingressDone = false;
232 bool egressDone = false;
234 // error messages to output if we can't backtrack, stored in an ordered_map to suppress
235 // duplicates. Flag is true if the error should be output as an error and false if it
236 // should just be a warning
237 ordered_map<cstring, bool> tablePlacementErrors;
239 bool no_errors_before_summary = true;
240
241 int alt_phv_alloc_table_fixed = 0;
242
243 int pipe_id;
244 const DependencyGraph &deps;
245 const PhvInfo &phv;
246 State::state_t &state;
247
254 ordered_map<cstring, ordered_set<int>> internalTableAlloc;
263
264 // Map of Global ID (Stage + Logical Id) -> Placed Table
265 std::map<int, PlacedTable *> placedTables;
266
267 // alt-phv-alloc ONLY
268 // trivial_tableAlloc, trivial_internalTableAlloc, trivial_mergedGateways and
269 // trival_placedTables are copies of tableAlloc, internalTableAlloc, mergedGateways and
270 // placedTables of table placement after trivial phv allocation. We save this information, so
271 // that if the heuristic for fixing problematic tables during table replay does not work, we can
272 // rollback to this checkpoint and table placement will go to ALT_FINALIZE_TABLE as normal.
273 ordered_map<cstring, ordered_set<int>> trivial_tableAlloc;
274 ordered_map<cstring, ordered_set<int>> trivial_internalTableAlloc;
276 std::map<int, PlacedTable *> trivial_placedTables;
277 // number of sram blocks allocated per table per stage in first round of table placement
278 ordered_map<int, ordered_map<cstring, int>> trivial_table_sram_alloc;
279
280 PlacementResult table_replay_result = FAIL;
281
283 // Map of Global ID -> Table
284 std::map<int, const IR::MAU::Table *> order;
285 // Map of Stage -> All Tables in stage
286 std::map<int, std::set<const IR::MAU::Table *>> tables;
287 // Map of Field Name -> Map of Field Slice -> Map of Stage -> No. of IXBar
288 // Bytes
289 // E.g.
290 // { hdr.ipv4.dstAddr, {
291 // { (0:31), { // For Slice 0..31
292 // { 1, 4 }, // Stage 1 has 4 bytes
293 // { 2, 4 } // Stage 2 has 4 bytes
294 // }
295 // }, { (32:47), { // For Slice 32..47
296 // { 1, 2 }, // Stage 1 has 2 bytes
297 // { 2, 4 } // Stage 2 has 4 bytes
298 // }
299 // }
300 // ...
301 // }
302 std::map<cstring, std::map<le_bitrange, std::map<int, int>>> ixbarBytes;
303 // For ixbar/memory/action_data_bus/imems: Tofino 1/2 share the pipe between
304 // ingress and egress, so every will be in the [0] element of these arrays.
305 // Array of Map of Stage -> Input Xbar
306 std::map<int, std::unique_ptr<IXBar>> ixbar[2];
307 // Map of Stage -> Memories
308 std::map<int, std::unique_ptr<Memories>> memory[2];
309 // Map of Stage -> ActionDataBus
310 std::map<int, std::unique_ptr<ActionDataBus>> action_data_bus[2];
311 // Map of Stage -> InstructionMemory
312 std::map<int, std::unique_ptr<InstructionMemory>> imems[2];
313 // Map of Table Name -> logical id
314 std::map<cstring, unsigned> logical_ids;
315
317 StageUseEstimate allStages;
318
319 // this is only used for alt-phv-alloc, it is a set of table candidates that can be the table
320 // to fix so that table replay can progress.
321 ordered_set<const IR::MAU::Table *> table_replay_fix_candidates;
322 const IR::MAU::Table *table_replay_problematic_table = nullptr;
323
324 profile_t init_apply(const IR::Node *root) override;
325 bool preorder(const IR::MAU::Table *t) override;
326 void postorder(const IR::BFN::Pipe *pipe) override;
327 void end_apply() override;
328
330 void printTablePlacement();
331
336 void generateIxbarBytesInfo();
337
338 // This function finds the problematic table during table replay. If table replay failed, it
339 // returns three different failure reason FAIL_ON_ADB, FAIL_ON_IXBAR and FAIL_ON_MEM. For
340 // different reasons, this function has different heuristics to select the problematic table.
341 bool find_problematic_table();
342
343 ordered_map<int, ordered_map<cstring, int>> collect_table_sram_alloc_info();
344
345 public:
346 explicit TableSummary(int pipe_id, const DependencyGraph &dg, const PhvInfo &phv,
347 State::state_t &state);
348
352 static cstring getTableIName(const IR::MAU::Table *tbl);
353
356 static cstring getTableName(const IR::MAU::Table *tbl);
357
359 static void clearTblName2IRptr() { TableSummary::tblName2IRptr.clear(); }
360
362 static std::set<const IR::MAU::Table *> getTablePtr(const cstring t_name);
363
365 static void addTablePtr(const IR::MAU::Table *ptr);
366
369 const ordered_set<int> stages(const IR::MAU::Table *tbl, bool internal = false) const;
370
372 int maxStages() const { return maxStage; }
373 int maxStages(gress_t gress) const { return max_stages[gress]; }
374
375 const ordered_map<cstring, ordered_set<int>> &getTableAlloc(void) const { return tableAlloc; }
376
377 // only called by TablePlacement
378 void addPlacementError(cstring msg) { tablePlacementErrors[msg] = true; }
379 void addPlacementWarnError(cstring msg) { tablePlacementErrors[msg] |= false; }
380 void clearPlacementErrors() { tablePlacementErrors.clear(); }
381 int placementErrorCount() { return tablePlacementErrors.size(); }
383 void FinalizePlacement();
384 const ordered_map<cstring, bool> &getPlacementError() { return tablePlacementErrors; }
385 void setPlacementError(const ordered_map<cstring, bool> &tpe) { tablePlacementErrors = tpe; }
387 void resetPlacement();
388 State::state_t getActualState() const { return state; }
389 void setPrevState() { state = prev_state; }
390 cstring getActualStateStr() const;
391 void setAllStagesResources(const StageUseEstimate &use) { allStages = use; }
392 StageUseEstimate getAllStagesResources() const { return allStages; }
393
394 std::map<int, PlacedTable *> &getPlacedTables() { return placedTables; }
395
396 const IR::MAU::Table *get_table_replay_problematic_table() const {
397 return table_replay_problematic_table;
398 }
399 int getNumInvoked() const { return numInvoked; }
400
401 // Returns a map of stage and bytes used on ixbar in that stage
402 // e.g. field f1 -
403 // Stage 1 -> 2 bytes (Normal)
404 // Stage 2 - 3 -> 1 byte (Dark)
405 // Stage 4 -> 3 byte (Normal)
406 // Map : {
407 // --------------------------
408 // Stage | No. of Ixbar Bytes
409 // --------------------------
410 // 1 | 2
411 // 2 | 1
412 // 3 | 1
413 // 4 | 3
414 // --------------------------
415 // }
416 std::map<int, int> findBytesOnIxbar(const PHV::FieldSlice &slice) const;
417 cstring ixbarUsagesStr(const PhvInfo *phv = nullptr) const;
418 void printPlacedTables() const;
419 void set_table_replay_result(PlacementResult result) { table_replay_result = result; }
420
421 PlacementResult get_table_replay_result() const { return table_replay_result; }
422
423 friend std::ostream &operator<<(std::ostream &out, const TableSummary &ts);
424 friend std::ostream &operator<<(std::ostream &out,
426 // this is only for alt-phv-alloc, if progressing table replay is impossible due to adding
427 // phv constraints, stop it and backtrack with stopTableReplayFitting = true.
428 void stop_table_replay_fitting() const {
429 BUG_CHECK(state == State::ALT_FINALIZE_TABLE_SAME_ORDER_TABLE_FIXED,
430 "state is not intened for table replay fitting");
431 throw PHVTrigger::failure(trivial_tableAlloc, trivial_internalTableAlloc,
432 trivial_mergedGateways, firstRoundFit, false, false, true);
433 }
434 // this is only for alt-phv-alloc, some table summary info need to be cleared before going
435 // through phv allocation and table allocation in ALT_FINALIZE_TABLE.
436 void clear_table_alloc_info() {
437 tableAlloc.clear();
438 internalTableAlloc.clear();
439 placedTables.clear();
440 }
441
442 bool is_table_replay() {
443 return state == State::ALT_FINALIZE_TABLE_SAME_ORDER ||
444 state == State::ALT_FINALIZE_TABLE_SAME_ORDER_TABLE_FIXED;
445 }
446};
447
448#endif /* BF_P4C_MAU_TABLE_SUMMARY_H_ */
Definition table_layout.h:34
A FileLog is used to redirect the logging output of a visitor pass to a file.
Definition filelog.h:48
Definition mau_visitor.h:29
Definition node.h:94
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition phv_fields.h:898
Definition phv_fields.h:1095
Definition table_summary.h:158
static void addTablePtr(const IR::MAU::Table *ptr)
Add table pointer into tblName2IRptr map.
Definition table_summary.cpp:285
static void clearTblName2IRptr()
Reset the the tblName2IRptr map.
Definition table_summary.h:359
static cstring getTableIName(const IR::MAU::Table *tbl)
Definition table_summary.cpp:262
static cstring getTableName(const IR::MAU::Table *tbl)
Definition table_summary.cpp:271
int maxStages() const
Definition table_summary.h:372
static std::set< const IR::MAU::Table * > getTablePtr(const cstring t_name)
Definition table_summary.cpp:296
void FinalizePlacement()
set state to FINAL_PLACEMENT, or ALT_FINALIZE_TABLE if alt-phv-alloc is enabled.
Definition table_summary.cpp:100
const ordered_set< int > stages(const IR::MAU::Table *tbl, bool internal=false) const
Definition table_summary.cpp:759
void resetPlacement()
set state to INITIAL, or ALT_INITIAL if alt-phv-alloc is enabled.
Definition table_summary.cpp:104
Definition filelog.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition table_dependency_graph.h:52
Definition visitor.h:768
Definition table_summary.h:41
Definition table_summary.h:38
Definition table_summary.h:67
Definition table_summary.h:66
Definition resource_estimate.h:29
Definition table_summary.h:168