Expanded ftrace2pyplot for user-supplied ftrace function name

This commit is contained in:
Zhengyi Chen 2024-02-19 15:44:46 +00:00
parent c7798a9358
commit 89a7d48866
7 changed files with 21 additions and 9 deletions

View file

@ -6,6 +6,10 @@ parser = argparse.ArgumentParser(
) )
# Positional # Positional
parser.add_argument(
"fn", metavar="function", type=str,
help="ftrace function name to filter entries for"
)
parser.add_argument( parser.add_argument(
"directory", type=str, help="ftrace-cmd output .dat directory" "directory", type=str, help="ftrace-cmd output .dat directory"
) )

View file

@ -1,7 +1,7 @@
from os import path from os import path
from argparse import Namespace from argparse import Namespace
import glob import glob
from typing import List, Tuple, Union from typing import List, Tuple, Union, Optional
import re import re
import trappy import trappy
@ -12,7 +12,7 @@ import matplotlib.pyplot as plt
from .arguments import parser from .arguments import parser
def parse_basename_into_byte_count(basename: str) -> int: def parse_basename_to_kibs(basename: str) -> int:
ret: int = -1 ret: int = -1
regex = re.compile(r"(?P<size>[0-9]+)(?P<unit>[kmgKMG])") regex = re.compile(r"(?P<size>[0-9]+)(?P<unit>[kmgKMG])")
@ -31,7 +31,7 @@ def parse_basename_into_byte_count(basename: str) -> int:
def clip_to( def clip_to(
dataset: Union[pd.Series, pd.DataFrame], dataset: Union[pd.Series, pd.DataFrame],
percentile: float, percentile: float,
axis: int = None axis: Optional[int] = None
) -> Union[pd.Series, pd.DataFrame]: ) -> Union[pd.Series, pd.DataFrame]:
assert(0 <= percentile <= 1) assert(0 <= percentile <= 1)
if percentile == .0: if percentile == .0:
@ -47,17 +47,22 @@ def clip_to(
return clipped return clipped
def parse_function_graph_ftrace(trace_fpath: str): def parse_function_graph_ftrace(
trace = trappy.FTrace(trace_fpath) ftrace_dat_path: str,
fn: str
) -> Optional[pd.DataFrame]:
trace = trappy.FTrace(ftrace_dat_path)
fngraph_df: pd.DataFrame = trace.funcgraph_exit.data_frame fngraph_df: pd.DataFrame = trace.funcgraph_exit.data_frame
assert fngraph_df is not None assert fngraph_df is not None
# Sieve `__dcache_clean_poc` entries # Sieve function entries
# Notably, the long ones are mostly preempted by e.g., softirq (rcu, etc.) # Notably, the long ones are mostly preempted by e.g., softirq (rcu, etc.)
# I should prob. identify them but whatever # I should prob. identify them but whatever
# Other long ones that are NOT preempted may be due to QEMU process # Other long ones that are NOT preempted may be due to QEMU process
# scheduling on host, not sure # scheduling on host, not sure
fngraph_df = fngraph_df.loc[fngraph_df["func"] == "__dcache_clean_poc"] fngraph_df = fngraph_df.loc[fngraph_df["func"] == fn]
if fngraph_df.shape[0] == 0:
return None
# Compute runtime of function # Compute runtime of function
fngraph_df.loc[:, "rettime"] = (fngraph_df["rettime"] fngraph_df.loc[:, "rettime"] = (fngraph_df["rettime"]
@ -83,8 +88,11 @@ def run(args: Namespace):
for ftrace_dat_path in ftrace_dat_paths: for ftrace_dat_path in ftrace_dat_paths:
print("Loading \"{}\"...".format(ftrace_dat_path)) print("Loading \"{}\"...".format(ftrace_dat_path))
fngraph_df = parse_function_graph_ftrace(ftrace_dat_path) fngraph_df = parse_function_graph_ftrace(ftrace_dat_path, args.fn)
size_in_kb = parse_basename_into_byte_count( if fngraph_df is None:
print("No entry -- pass")
continue
size_in_kb = parse_basename_to_kibs(
str(path.basename(ftrace_dat_path).split(".")[:-1])) str(path.basename(ftrace_dat_path).split(".")[:-1]))
ftrace_dfs.append((size_in_kb, fngraph_df)) ftrace_dfs.append((size_in_kb, fngraph_df))

Binary file not shown.

Binary file not shown.