import sys
from argparse import ArgumentParser, BooleanOptionalAction, Namespace
from collections import defaultdict
-from typing import Callable, DefaultDict, NewType, NoReturn, TextIO
+from typing import DefaultDict, NewType, NoReturn, TextIO
class Args(Namespace):
sort: list[str]
threshold: float # a percentage
show_percs: bool
- auto: bool
+ annotate: bool
context: int
include: list[str]
cgout_filename: list[str]
- src_filenames: list[str]
@staticmethod
def parse() -> Args:
return f
raise ValueError
- def add_bool_argument(p: ArgumentParser, name: str, help: str) -> None:
+ def add_bool_argument(
+ p: ArgumentParser, new_name: str, old_name: str, help: str
+ ) -> None:
"""
Add a bool argument that defaults to true.
The latter two were the forms supported by the old Perl version of
`cg_annotate`, and are now deprecated.
"""
- flag = "--" + name
- dest = name.replace("-", "_")
+ new_flag = "--" + new_name
+ old_flag = "--" + old_name
+ dest = new_name.replace("-", "_")
# Note: the default value is always printed with `BooleanOptionalAction`,
# due to an argparse bug: https://github.com/python/cpython/issues/83137.
p.add_argument(
- flag,
+ new_flag,
default=True,
action=BooleanOptionalAction,
help=help,
)
p.add_argument(
- f"{flag}=yes",
+ f"{old_flag}=yes",
dest=dest,
action="store_true",
- help=f"(deprecated) same as --{name}",
+ help=f"(deprecated) same as --{new_name}",
)
p.add_argument(
- f"{flag}=no",
+ f"{old_flag}=no",
dest=dest,
action="store_false",
- help=f"(deprecated) same as --no-{name}",
+ help=f"(deprecated) same as --no-{new_name}",
)
p = ArgumentParser(description="Process a Cachegrind output file.")
add_bool_argument(
p,
"show-percs",
+ "show-percs",
"show a percentage for each non-zero count",
)
add_bool_argument(
p,
+ "annotate",
"auto",
"annotate all source files containing functions that reached the "
"event count threshold",
metavar="cachegrind-out-file",
help="file produced by Cachegrind",
)
- p.add_argument(
- "src_filenames",
- nargs="*",
- metavar="source-files",
- help="source files to annotate (usually not needed due to --auto)",
- )
return p.parse_args(namespace=Args())
for include_dirname in args.include[1:]:
print(f" {include_dirname}")
- if len(args.src_filenames) == 0:
- print("User annotated: ")
- else:
- print(f"User annotated: {args.src_filenames[0]}")
- for src_filename in args.src_filenames[1:]:
- print(f" {src_filename}")
-
- print("Auto-annotation: ", "on" if args.auto else "off")
+ print("Annotation: ", "on" if args.annotate else "off")
print()
# This (partially) consumes `dict_fl_dict_line_cc`.
def print_annotated_src_files(
events: Events,
- threshold_src_filenames: set[str],
+ ann_src_filenames: set[str],
dict_fl_dict_line_cc: DictFlDictLineCc,
summary_cc: Cc,
) -> AnnotatedCcs:
annotated_ccs = AnnotatedCcs(events)
- def pair_with(label: str) -> Callable[[str], tuple[str, str]]:
- return lambda s: (s, label)
-
def add_dict_line_cc_to_cc(dict_line_cc: DictLineCc | None, accum_cc: Cc) -> None:
if dict_line_cc:
for line_cc in dict_line_cc.values():
accum_cc += line_cc
- # If auto-annotating, add interesting files (excluding "???").
- all_src_filenames = set(map(pair_with("User"), args.src_filenames))
- if args.auto:
- threshold_src_filenames.discard("???")
-
- dict_line_cc = dict_fl_dict_line_cc.pop("???", None)
- add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.files_unknown_cc)
-
- all_src_filenames.update(map(pair_with("Auto"), threshold_src_filenames))
+ # Exclude the unknown ("???") file, which is unannotatable.
+ ann_src_filenames.discard("???")
+ dict_line_cc = dict_fl_dict_line_cc.pop("???", None)
+ add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.files_unknown_cc)
# Prepend "" to the include dirnames so things work in the case where the
# filename has the full path.
include_dirnames = args.include.copy()
include_dirnames.insert(0, "")
- def print_ann_fancy(ann_type: str, src_filename: str) -> None:
- print_fancy(f"{ann_type}-annotated source file: {src_filename}")
+ def print_ann_fancy(src_filename: str) -> None:
+ print_fancy(f"Annotated source file: {src_filename}")
- for src_filename, ann_type in sorted(all_src_filenames):
+ for src_filename in sorted(ann_src_filenames):
readable = False
for include_dirname in include_dirnames:
if include_dirname == "":
try:
with open(full_src_filename, "r", encoding="utf-8") as src_file:
dict_line_cc = dict_fl_dict_line_cc.pop(src_filename, None)
- if dict_line_cc is not None:
- print_ann_fancy(ann_type, src_file.name) # includes full path
- print_annotated_src_file(
- events,
- dict_line_cc,
- src_file,
- annotated_ccs,
- summary_cc,
- )
- else:
- # This only happens for user-specified files that are
- # readable but not mentioned in the cgout file.
- print_ann_fancy(ann_type, src_filename)
- print("This file was not mentioned by the data file")
- print()
+ assert dict_line_cc is not None
+ print_ann_fancy(src_file.name) # includes full path
+ print_annotated_src_file(
+ events,
+ dict_line_cc,
+ src_file,
+ annotated_ccs,
+ summary_cc,
+ )
readable = True
break
dict_line_cc = dict_fl_dict_line_cc.pop(src_filename, None)
add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.unreadable_cc)
- print_ann_fancy(ann_type, src_filename)
+ print_ann_fancy(src_filename)
print("This file was unreadable")
print()
annotated_ccs: AnnotatedCcs,
summary_cc: Cc,
) -> None:
- # If we did any annotating, show how many events were covered by annotated
- # lines above.
- if args.auto or args.src_filenames:
- printer = CcPrinter(events, annotated_ccs.ccs(), summary_cc)
- print_fancy("Annotation summary")
- printer.print_events("")
- print()
+ # Show how many events were covered by annotated lines above.
+ printer = CcPrinter(events, annotated_ccs.ccs(), summary_cc)
+ print_fancy("Annotation summary")
+ printer.print_events("")
+ print()
- total_cc = events.mk_empty_cc()
- for (cc, label) in zip(annotated_ccs.ccs(), AnnotatedCcs.labels):
- printer.print_cc(cc, label)
- total_cc += cc
+ total_cc = events.mk_empty_cc()
+ for (cc, label) in zip(annotated_ccs.ccs(), AnnotatedCcs.labels):
+ printer.print_cc(cc, label)
+ total_cc += cc
- print()
+ print()
- # Internal sanity check.
- if summary_cc != total_cc:
- msg = (
- "`summary:` line doesn't match computed annotated counts\n"
- f"- summary: {summary_cc}\n"
- f"- annotated: {total_cc}"
- )
- die(msg)
+ # Internal sanity check.
+ if summary_cc != total_cc:
+ msg = (
+ "`summary:` line doesn't match computed annotated counts\n"
+ f"- summary: {summary_cc}\n"
+ f"- annotated: {total_cc}"
+ )
+ die(msg)
def main() -> None:
print_summary(events, summary_cc)
- threshold_src_filenames = print_function_summary(events, dict_flfn_cc, summary_cc)
+ ann_src_filenames = print_function_summary(events, dict_flfn_cc, summary_cc)
- annotated_ccs = print_annotated_src_files(
- events, threshold_src_filenames, dict_fl_dict_line_cc, summary_cc
- )
+ if args.annotate:
+ annotated_ccs = print_annotated_src_files(
+ events, ann_src_filenames, dict_fl_dict_line_cc, summary_cc
+ )
- print_annotation_summary(events, annotated_ccs, summary_cc)
+ print_annotation_summary(events, annotated_ccs, summary_cc)
if __name__ == "__main__":
Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Threshold: 0.1
Include dirs:
-User annotated:
-Auto-annotation: on
+Annotation: on
--------------------------------------------------------------------------------
-- Summary
6,898 2 2 /build/glibc-OTsEL5/glibc-2.27/elf/dl-misc.c:_dl_name_match_p
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/../sysdeps/x86_64/dl-machine.h
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/../sysdeps/x86_64/dl-machine.h
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-lookup.c
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-lookup.c
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-misc.c
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-misc.c
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-tunables.c
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-tunables.c
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-tunables.h
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/dl-tunables.h
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/do-rel.h
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/elf/do-rel.h
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: /build/glibc-OTsEL5/glibc-2.27/string/../sysdeps/x86_64/strcmp.S
+-- Annotated source file: /build/glibc-OTsEL5/glibc-2.27/string/../sysdeps/x86_64/strcmp.S
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: a.c
+-- Annotated source file: a.c
--------------------------------------------------------------------------------
Ir I1mr ILmr
Include dirs: ann2-no-such-dir
ann2-no-such-dir-2
ann2-aux
-User annotated: ann2-unmentioned.rs
- ann2-no-such-file.rs
-Auto-annotation: on
+Annotation: on
--------------------------------------------------------------------------------
-- Summary
500 (0.5%) 0 0 ann2-basic.rs:f4
--------------------------------------------------------------------------------
--- Auto-annotated source file: ann2-basic.rs
+-- Annotated source file: ann2-basic.rs
--------------------------------------------------------------------------------
A SomeCount VeryLongEventName
300 (0.3%) 0 0 twenty
--------------------------------------------------------------------------------
--- Auto-annotated source file: ann2-could-not-be-found.rs
+-- Annotated source file: ann2-could-not-be-found.rs
--------------------------------------------------------------------------------
This file was unreadable
--------------------------------------------------------------------------------
--- Auto-annotated source file: ann2-more-recent-than-cgout.rs
+-- Annotated source file: ann2-more-recent-than-cgout.rs
--------------------------------------------------------------------------------
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@
-- line 4 ----------------------------------------
--------------------------------------------------------------------------------
--- Auto-annotated source file: ann2-negatives.rs
+-- Annotated source file: ann2-negatives.rs
--------------------------------------------------------------------------------
A SomeCount VeryLongEventName
-- line 13 ----------------------------------------
--------------------------------------------------------------------------------
--- User-annotated source file: ann2-no-such-file.rs
---------------------------------------------------------------------------------
-This file was unreadable
-
---------------------------------------------------------------------------------
--- Auto-annotated source file: ann2-past-the-end.rs
+-- Annotated source file: ann2-past-the-end.rs
--------------------------------------------------------------------------------
A SomeCount VeryLongEventName
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
--------------------------------------------------------------------------------
--- User-annotated source file: ann2-unmentioned.rs
---------------------------------------------------------------------------------
-This file was not mentioned by the data file
-
---------------------------------------------------------------------------------
--- Auto-annotated source file: ann2-aux/ann2-via-I.rs
+-- Annotated source file: ann2-aux/ann2-via-I.rs
--------------------------------------------------------------------------------
A SomeCount VeryLongEventName