Skip to content

Commit d1beac0

Browse files
committed
Added wildcard(*) support in the rule name and added a new *__flow__warnings__count:* rule
Signed-off-by: Jaehyun Kim <[email protected]>
1 parent 98ea540 commit d1beac0

File tree

1 file changed

+137
-114
lines changed

1 file changed

+137
-114
lines changed

flow/util/genRuleFile.py

Lines changed: 137 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from os.path import isfile
66
from re import sub
77
import argparse
8+
import fnmatch
89
import json
910
import operator
1011
import os
@@ -60,6 +61,13 @@ def gen_rule_file(
6061
# }
6162

6263
rules_dict = {
64+
# all stages
65+
"*__flow__warnings__count:*": {
66+
"mode": "direct",
67+
"round_value": True,
68+
"compare": "<=",
69+
"level": "warning",
70+
},
6371
# synth
6472
"synth__design__instance__area__stdcell": {
6573
"mode": "padding",
@@ -308,130 +316,145 @@ def gen_rule_file(
308316

309317
format_str = "| {:45} | {:8} | {:8} | {:8} |\n"
310318
change_str = ""
311-
for field, option in rules_dict.items():
312-
if field not in metrics.keys():
313-
print(f"[WARNING] Metric {field} not found")
314-
continue
315-
316-
if isinstance(metrics[field], str):
317-
print(f"[WARNING] Skipping string field {field} = {metrics[field]}")
318-
continue
319-
320-
if len(period_list) != 1 and field == "globalroute__timing__clock__slack":
321-
print("[WARNING] Skipping clock slack until multiple clocks support.")
322-
continue
323-
324-
rule_value = None
325-
if option["mode"] == "direct":
326-
rule_value = metrics[field]
327-
328-
elif option["mode"] == "sum_fixed":
329-
rule_value = metrics[field] + option["padding"]
330-
331-
elif option["mode"] == "period":
332-
rule_value = metrics[field] - period * option["padding"] / 100
333-
rule_value = min(rule_value, 0)
334-
335-
elif option["mode"] == "padding":
336-
rule_value = metrics[field] * (1 + option["padding"] / 100)
337-
338-
elif option["mode"] == "period_padding":
339-
negative_slack = min(metrics[field], 0)
340-
rule_value = negative_slack - max(
341-
negative_slack * option["padding"] / 100,
342-
period * option["padding"] / 100,
343-
)
344-
345-
elif option["mode"] == "abs_padding":
346-
rule_value = abs(metrics[field]) * (1 + option["padding"] / 100)
347319

348-
elif option["mode"] == "metric":
349-
rule_value = metrics[option["metric"]] * option["padding"] / 100
350-
351-
if (
352-
field == "cts__design__instance__count__setup_buffer"
353-
or field == "cts__design__instance__count__hold_buffer"
354-
):
355-
rule_value = max(rule_value, metrics[field] * 1.1)
320+
processed_fields = set()
321+
for pattern, option in rules_dict.items():
322+
matching_fields = []
323+
# Find all metric fields that match this pattern.
324+
if "*" in pattern:
325+
for metric_field in sorted(metrics.keys()):
326+
if (
327+
fnmatch.fnmatch(metric_field, pattern)
328+
and metric_field not in processed_fields
329+
):
330+
matching_fields.append(metric_field)
331+
elif pattern in metrics and pattern not in processed_fields:
332+
matching_fields.append(pattern)
333+
334+
for field in matching_fields:
335+
processed_fields.add(field)
336+
if isinstance(metrics[field], str):
337+
print(f"[WARNING] Skipping string field {field} = {metrics[field]}")
338+
continue
339+
340+
if len(period_list) != 1 and field == "globalroute__timing__clock__slack":
341+
print("[WARNING] Skipping clock slack until multiple clocks support.")
342+
continue
343+
344+
rule_value = None
345+
if option["mode"] == "direct":
346+
rule_value = metrics[field]
347+
348+
elif option["mode"] == "sum_fixed":
349+
rule_value = metrics[field] + option["padding"]
350+
351+
elif option["mode"] == "period":
352+
rule_value = metrics[field] - period * option["padding"] / 100
353+
rule_value = min(rule_value, 0)
354+
355+
elif option["mode"] == "padding":
356+
rule_value = metrics[field] * (1 + option["padding"] / 100)
356357

357-
if "min_max" in option.keys():
358-
if "min_max_direct" in option.keys():
359-
rule_value = option["min_max"](rule_value, option["min_max_direct"])
360-
elif "min_max_sum" in option.keys():
361-
rule_value = option["min_max"](
362-
rule_value + option["min_max_sum"], option["min_max_sum"]
358+
elif option["mode"] == "period_padding":
359+
negative_slack = min(metrics[field], 0)
360+
rule_value = negative_slack - max(
361+
negative_slack * option["padding"] / 100,
362+
period * option["padding"] / 100,
363363
)
364-
elif "min_max_period" in option.keys():
365-
rule_value = option["min_max"](
366-
rule_value, -period * option["min_max_period"] / 100.0
367-
)
368-
else:
369-
print(
370-
f"[ERROR] Metric {field} has 'min_max' field but no "
371-
"'min_max_direct', 'min_max_sum', or 'min_max_period' field."
372-
)
373-
sys.exit(1)
374364

375-
if rule_value is None:
376-
print(f"[ERROR] Metric {field} has invalid mode {option['mode']}.")
377-
sys.exit(1)
378-
379-
if option["round_value"] and not isinf(rule_value):
380-
rule_value = int(round(rule_value))
381-
else:
382-
rule_value = float(f"{rule_value:.3g}")
383-
384-
preserve_old_rule = (
385-
True
386-
if len(metrics_to_consider) > 0 and field not in metrics_to_consider
387-
else False
388-
)
389-
has_old_rule = OLD_RULES is not None and field in OLD_RULES.keys()
365+
elif option["mode"] == "abs_padding":
366+
rule_value = abs(metrics[field]) * (1 + option["padding"] / 100)
390367

391-
if has_old_rule and preserve_old_rule:
392-
rule_value = OLD_RULES[field]["value"]
368+
elif option["mode"] == "metric":
369+
rule_value = metrics[option["metric"]] * option["padding"] / 100
393370

394-
if has_old_rule and not preserve_old_rule:
395-
old_rule = OLD_RULES[field]
396-
if old_rule["compare"] != option["compare"]:
397-
print("[WARNING] Compare operator changed since last update.")
398-
399-
compare = ops[option["compare"]]
400-
401-
if compare(rule_value, metrics[field]) and "padding" in option.keys():
402-
rule_value = metrics[field] * (1 + option["padding"] / 100)
403-
if option["round_value"] and not isinf(rule_value):
404-
rule_value = int(round(rule_value))
405-
else:
406-
rule_value = float(f"{rule_value:.3g}")
407-
408-
need_to_update = False
409371
if (
410-
tighten
411-
and rule_value != old_rule["value"]
412-
and compare(rule_value, old_rule["value"])
372+
field == "cts__design__instance__count__setup_buffer"
373+
or field == "cts__design__instance__count__hold_buffer"
413374
):
414-
need_to_update = True
415-
change_str += format_str.format(
416-
field, old_rule["value"], rule_value, "Tighten"
417-
)
418-
419-
if failing and not compare(metrics[field], old_rule["value"]):
420-
need_to_update = True
421-
change_str += format_str.format(
422-
field, old_rule["value"], rule_value, "Failing"
423-
)
424-
425-
if update and old_rule["value"] != rule_value:
426-
need_to_update = True
427-
change_str += format_str.format(
428-
field, old_rule["value"], rule_value, "Updating"
429-
)
375+
rule_value = max(rule_value, metrics[field] * 1.1)
376+
377+
if "min_max" in option.keys():
378+
if "min_max_direct" in option.keys():
379+
rule_value = option["min_max"](rule_value, option["min_max_direct"])
380+
elif "min_max_sum" in option.keys():
381+
rule_value = option["min_max"](
382+
rule_value + option["min_max_sum"], option["min_max_sum"]
383+
)
384+
elif "min_max_period" in option.keys():
385+
rule_value = option["min_max"](
386+
rule_value, -period * option["min_max_period"] / 100.0
387+
)
388+
else:
389+
print(
390+
f"[ERROR] Metric {field} has 'min_max' field but no "
391+
"'min_max_direct', 'min_max_sum', or 'min_max_period' field."
392+
)
393+
sys.exit(1)
394+
395+
if rule_value is None:
396+
print(f"[ERROR] Metric {field} has invalid mode {option['mode']}.")
397+
sys.exit(1)
430398

431-
if not need_to_update:
432-
rule_value = old_rule["value"]
399+
if option["round_value"] and not isinf(rule_value):
400+
rule_value = int(round(rule_value))
401+
else:
402+
rule_value = float(f"{rule_value:.3g}")
433403

434-
rules[field] = dict(value=rule_value, compare=option["compare"])
404+
preserve_old_rule = (
405+
True
406+
if len(metrics_to_consider) > 0 and field not in metrics_to_consider
407+
else False
408+
)
409+
has_old_rule = OLD_RULES is not None and field in OLD_RULES.keys()
410+
411+
if has_old_rule and preserve_old_rule:
412+
rule_value = OLD_RULES[field]["value"]
413+
414+
if has_old_rule and not preserve_old_rule:
415+
old_rule = OLD_RULES[field]
416+
if old_rule["compare"] != option["compare"]:
417+
print("[WARNING] Compare operator changed since last update.")
418+
419+
compare = ops[option["compare"]]
420+
421+
if compare(rule_value, metrics[field]) and "padding" in option.keys():
422+
rule_value = metrics[field] * (1 + option["padding"] / 100)
423+
if option["round_value"] and not isinf(rule_value):
424+
rule_value = int(round(rule_value))
425+
else:
426+
rule_value = float(f"{rule_value:.3g}")
427+
428+
need_to_update = False
429+
if (
430+
tighten
431+
and rule_value != old_rule["value"]
432+
and compare(rule_value, old_rule["value"])
433+
):
434+
need_to_update = True
435+
change_str += format_str.format(
436+
field, old_rule["value"], rule_value, "Tighten"
437+
)
438+
439+
if failing and not compare(metrics[field], old_rule["value"]):
440+
need_to_update = True
441+
change_str += format_str.format(
442+
field, old_rule["value"], rule_value, "Failing"
443+
)
444+
445+
if update and old_rule["value"] != rule_value:
446+
need_to_update = True
447+
change_str += format_str.format(
448+
field, old_rule["value"], rule_value, "Updating"
449+
)
450+
451+
if not need_to_update:
452+
rule_value = old_rule["value"]
453+
454+
rule_entry = {"value": rule_value, "compare": option["compare"]}
455+
if "level" in option:
456+
rule_entry["level"] = option["level"]
457+
rules[field] = rule_entry
435458

436459
if len(change_str) > 0:
437460
print(f"{os.path.normpath(rules_file)} updates:")

0 commit comments

Comments
 (0)