forked from kuznia-rdzeni/coreblocks
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Transaction profiles (kuznia-rdzeni#547)
- Loading branch information
Showing
12 changed files
with
442 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,3 +17,5 @@ cocotb==1.7.2 | |
cocotb-bus==0.2.1 | ||
pytest==7.2.2 | ||
pyelftools==0.29 | ||
dataclasses-json==0.6.3 | ||
tabulate==0.9.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import argparse | ||
import sys | ||
import re | ||
from pathlib import Path | ||
from typing import Optional | ||
from collections.abc import Callable, Iterable | ||
from tabulate import tabulate | ||
from dataclasses import asdict | ||
|
||
topdir = Path(__file__).parent.parent | ||
sys.path.insert(0, str(topdir)) | ||
|
||
|
||
from transactron.profiler import Profile, RunStat, RunStatNode # noqa: E402 | ||
|
||
|
||
def process_stat_tree( | ||
xs: Iterable[RunStatNode], recursive: bool, ret: Optional[list[tuple]] = None, depth=0 | ||
) -> list[tuple]: | ||
if ret is None: | ||
ret = list[tuple]() | ||
for x in xs: | ||
row = asdict(x.stat) | ||
if recursive and depth: | ||
row["name"] = (2 * depth - 1) * "-" + " " + row["name"] | ||
ret.append(tuple(row.values())) | ||
if recursive and x.callers: | ||
process_stat_tree(x.callers.values(), recursive, ret, depth + 1) | ||
return ret | ||
|
||
|
||
def filter_nodes(nodes: list[RunStatNode], key: Callable[[RunStat], str], regex: str): | ||
pattern = re.compile(regex) | ||
return [node for node in nodes if pattern.search(key(node.stat))] | ||
|
||
|
||
def sort_node(node: RunStatNode, sort_order: str): | ||
node.callers = dict(sorted(node.callers.items(), key=lambda node: asdict(node[1].stat)[sort_order])) | ||
for node2 in node.callers.values(): | ||
sort_node(node2, sort_order) | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("-g", "--call-graph", action="store_true", help="Show call graph") | ||
parser.add_argument("-s", "--sort", choices=["name", "locked", "run"], default="name", help="Sort by column") | ||
parser.add_argument( | ||
"-m", "--mode", choices=["transactions", "methods"], default="transactions", help="Profile display mode" | ||
) | ||
parser.add_argument("-f", "--filter-name", help="Filter by name, regular expressions can be used") | ||
parser.add_argument("-l", "--filter-loc", help="Filter by source location, regular expressions can be used") | ||
parser.add_argument("file_name", nargs=1) | ||
|
||
args = parser.parse_args() | ||
|
||
profile = Profile.decode(args.file_name[0]) | ||
|
||
recursive = args.call_graph | ||
|
||
if args.mode == "transactions": | ||
nodes = profile.analyze_transactions(recursive=recursive) | ||
elif args.mode == "methods": | ||
nodes = profile.analyze_methods(recursive=recursive) | ||
else: | ||
assert False | ||
|
||
headers = ["name", "source location", "locked", "run"] | ||
|
||
nodes.sort(key=lambda node: asdict(node.stat)[args.sort]) | ||
for node in nodes: | ||
sort_node(node, args.sort) | ||
|
||
if args.filter_name: | ||
nodes = filter_nodes(nodes, lambda stat: stat.name, args.filter_name) | ||
if args.filter_loc: | ||
nodes = filter_nodes(nodes, lambda stat: stat.src_loc, args.filter_loc) | ||
|
||
print(tabulate(process_stat_tree(nodes, recursive), headers=headers)) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import os.path | ||
from amaranth.sim import * | ||
from transactron.core import MethodMap, TransactionManager | ||
from transactron.profiler import CycleProfile, Profile, ProfileInfo | ||
from transactron.utils import SrcLoc | ||
from .functions import TestGen | ||
|
||
__all__ = ["profiler_process"] | ||
|
||
|
||
def profiler_process(transaction_manager: TransactionManager, profile: Profile, clk_period: float): | ||
def process() -> TestGen: | ||
method_map = MethodMap(transaction_manager.transactions) | ||
cgr, _, _ = TransactionManager._conflict_graph(method_map) | ||
id_map = dict[int, int]() | ||
id_seq = 0 | ||
|
||
def get_id(obj): | ||
try: | ||
return id_map[id(obj)] | ||
except KeyError: | ||
nonlocal id_seq | ||
id_seq = id_seq + 1 | ||
id_map[id(obj)] = id_seq | ||
return id_seq | ||
|
||
def local_src_loc(src_loc: SrcLoc): | ||
return (os.path.relpath(src_loc[0]), src_loc[1]) | ||
|
||
for transaction in method_map.transactions: | ||
profile.transactions_and_methods[get_id(transaction)] = ProfileInfo( | ||
transaction.owned_name, local_src_loc(transaction.src_loc), True | ||
) | ||
|
||
for method in method_map.methods: | ||
profile.transactions_and_methods[get_id(method)] = ProfileInfo( | ||
method.owned_name, local_src_loc(method.src_loc), False | ||
) | ||
|
||
yield Passive() | ||
while True: | ||
yield Delay((1 - 1e-4) * clk_period) # shorter than one clock cycle | ||
|
||
cprof = CycleProfile() | ||
profile.cycles.append(cprof) | ||
|
||
for transaction in method_map.transactions: | ||
request = yield transaction.request | ||
runnable = yield transaction.runnable | ||
grant = yield transaction.grant | ||
|
||
if grant: | ||
cprof.running[get_id(transaction)] = None | ||
elif request and runnable: | ||
for transaction2 in cgr[transaction]: | ||
if (yield transaction2.grant): | ||
cprof.locked[get_id(transaction)] = get_id(transaction2) | ||
|
||
running = set(cprof.running) | ||
for method in method_map.methods: | ||
if (yield method.run): | ||
running.add(get_id(method)) | ||
|
||
locked_methods = set[int]() | ||
for method in method_map.methods: | ||
if get_id(method) not in running: | ||
if any(get_id(transaction) in running for transaction in method_map.transactions_by_method[method]): | ||
locked_methods.add(get_id(method)) | ||
|
||
for method in method_map.methods: | ||
if get_id(method) in running: | ||
for t_or_m in method_map.method_parents[method]: | ||
if get_id(t_or_m) in running: | ||
cprof.running[get_id(method)] = get_id(t_or_m) | ||
elif get_id(method) in locked_methods: | ||
caller = next( | ||
get_id(t_or_m) | ||
for t_or_m in method_map.method_parents[method] | ||
if get_id(t_or_m) in running or get_id(t_or_m) in locked_methods | ||
) | ||
cprof.locked[get_id(method)] = caller | ||
|
||
yield | ||
|
||
return process |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.