You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
|
From: Nicholas N. <nj...@so...> - 2023-04-21 12:44:29
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=307f96a519d458818d32d8c63eb3628c25db97e4 commit 307f96a519d458818d32d8c63eb3628c25db97e4 Author: Nicholas Nethercote <n.n...@gm...> Date: Fri Apr 21 15:59:39 2023 +1000 Reorder options in Cachegrind's `-h` output. Put the commonly used ones first. Diff: --- cachegrind/cg_arch.c | 2 +- cachegrind/cg_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cachegrind/cg_arch.c b/cachegrind/cg_arch.c index 57570dd638..52e8982184 100644 --- a/cachegrind/cg_arch.c +++ b/cachegrind/cg_arch.c @@ -317,7 +317,7 @@ void VG_(print_cache_clo_opts)() " --I1=<size>,<assoc>,<line_size> set I1 cache manually\n" " --D1=<size>,<assoc>,<line_size> set D1 cache manually\n" " --LL=<size>,<assoc>,<line_size> set LL cache manually\n" - ); + ); } diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c index c4e111aa30..c17ab975b0 100644 --- a/cachegrind/cg_main.c +++ b/cachegrind/cg_main.c @@ -1758,12 +1758,12 @@ static Bool cg_process_cmd_line_option(const HChar* arg) static void cg_print_usage(void) { - VG_(print_cache_clo_opts)(); VG_(printf)( +" --cachegrind-out-file=<file> output file name [cachegrind.out.%%p]\n" " --cache-sim=yes|no collect cache stats? [yes]\n" " --branch-sim=yes|no collect branch prediction stats? [no]\n" -" --cachegrind-out-file=<file> output file name [cachegrind.out.%%p]\n" ); + VG_(print_cache_clo_opts)(); } static void cg_print_debug_usage(void) |
|
From: Nicholas N. <nj...@so...> - 2023-04-21 12:44:28
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=1fdf0e728a047f0aab4de805576b6a3a84f37b79 commit 1fdf0e728a047f0aab4de805576b6a3a84f37b79 Author: Nicholas Nethercote <n.n...@gm...> Date: Wed Apr 12 10:02:13 2023 +1000 Add diff and merge capability to `cg_annotate`. And deprecate the use of `cg_diff` and `cg_merge`. Because `cg_annotate` can do a better job, even annotating source files when doing diffs in some cases. The user requests merging by passing multiple cgout files to `cg_annotate`, and diffing by passing two cgout files to `cg_annotate` along with `--diff`. Diff: --- cachegrind/cg_annotate.in | 603 +++++++++++++++++++++++---------- cachegrind/cg_diff.in | 14 +- cachegrind/cg_merge.in | 10 +- cachegrind/tests/Makefile.am | 8 + cachegrind/tests/ann-diff1.post.exp | 11 +- cachegrind/tests/ann-diff1.vgtest | 8 +- cachegrind/tests/ann-diff2.post.exp | 10 +- cachegrind/tests/ann-diff2.vgtest | 6 +- cachegrind/tests/ann-diff2b.cgout | 2 +- cachegrind/tests/ann-diff3.post.exp | 63 ++++ cachegrind/tests/ann-diff3.stderr.exp | 3 + cachegrind/tests/ann-diff3.vgtest | 8 + cachegrind/tests/ann-diff4.post.exp | 125 +++++++ cachegrind/tests/ann-diff4.stderr.exp | 3 + cachegrind/tests/ann-diff4.vgtest | 14 + cachegrind/tests/ann-diff4a-aux/w.rs | 3 + cachegrind/tests/ann-diff4a-aux/x.rs | 5 + cachegrind/tests/ann-diff4a-aux/y.rs | 5 + cachegrind/tests/ann-diff4a-aux/z.rs | 3 + cachegrind/tests/ann-diff4a.cgout | 30 ++ cachegrind/tests/ann-diff4b-aux/x.rs | 5 + cachegrind/tests/ann-diff4b-aux/y.rs | 6 + cachegrind/tests/ann-diff4b.cgout | 31 ++ cachegrind/tests/ann-merge1.post.exp | 9 +- cachegrind/tests/ann-merge1.vgtest | 5 +- cachegrind/tests/ann-merge2.post.exp | 85 +++++ cachegrind/tests/ann-merge2.stderr.exp | 3 + cachegrind/tests/ann-merge2.vgtest | 8 + cachegrind/tests/ann1a.post.exp | 42 ++- cachegrind/tests/ann1a.vgtest | 4 +- cachegrind/tests/ann1b.post.exp | 14 +- cachegrind/tests/ann1b.vgtest | 4 +- cachegrind/tests/ann2.post.exp | 23 +- cachegrind/tests/ann2.vgtest | 2 +- 34 files changed, 921 insertions(+), 254 deletions(-) diff --git a/cachegrind/cg_annotate.in b/cachegrind/cg_annotate.in index 5e64a94485..c76a760be0 100755 --- a/cachegrind/cg_annotate.in +++ b/cachegrind/cg_annotate.in @@ -34,17 +34,28 @@ from __future__ import annotations +import filecmp import os import re import sys from argparse import ArgumentParser, BooleanOptionalAction, Namespace from collections import defaultdict -from typing import DefaultDict, NoReturn, TextIO +from typing import Callable, DefaultDict, NoReturn, TextIO +def die(msg: str) -> NoReturn: + print("cg_annotate: error:", msg, file=sys.stderr) + sys.exit(1) + + +SearchAndReplace = Callable[[str], str] + # A typed wrapper for parsed args. class Args(Namespace): # None of these fields are modified after arg parsing finishes. + diff: bool + mod_filename: SearchAndReplace + mod_funcname: SearchAndReplace show: list[str] sort: list[str] threshold: float # a percentage @@ -55,6 +66,42 @@ class Args(Namespace): @staticmethod def parse() -> Args: + # We support Perl-style `s/old/new/flags` search-and-replace + # expressions, because that's how this option was implemented in the + # old Perl version of `cg_diff`. This requires conversion from + # `s/old/new/` style to `re.sub`. The conversion isn't a perfect + # emulation of Perl regexps (e.g. Python uses `\1` rather than `$1` for + # using captures in the `new` part), but it should be close enough. The + # only supported flags are `g` (global) and `i` (ignore case). + def search_and_replace(regex: str | None) -> SearchAndReplace: + if regex is None: + return lambda s: s + + # Extract the parts of an `s/old/new/tail` regex. `(?<!\\)/` is an + # example of negative lookbehind. It means "match a forward slash + # unless preceded by a backslash". + m = re.match(r"s/(.*)(?<!\\)/(.*)(?<!\\)/(g|i|gi|ig|)$", regex) + if m is None: + raise ValueError + + # Forward slashes must be escaped in an `s/old/new/` expression, + # but we then must unescape them before using them with `re.sub`. + pat = m.group(1).replace(r"\/", r"/") + repl = m.group(2).replace(r"\/", r"/") + tail = m.group(3) + + if "g" in tail: + count = 0 # unlimited + else: + count = 1 + + if "i" in tail: + flags = re.IGNORECASE + else: + flags = re.RegexFlag(0) + + return lambda s: re.sub(re.compile(pat, flags=flags), repl, s, count=count) + def comma_separated_list(values: str) -> list[str]: return values.split(",") @@ -97,9 +144,30 @@ class Args(Namespace): help=f"(deprecated) same as --no-{new_name}", ) - p = ArgumentParser(description="Process a Cachegrind output file.") + p = ArgumentParser(description="Process one or more Cachegrind output files.") p.add_argument("--version", action="version", version="%(prog)s-@VERSION@") + p.add_argument( + "--diff", + default=False, + action="store_true", + help="perform a diff between two Cachegrind output files", + ) + p.add_argument( + "--mod-filename", + type=search_and_replace, + metavar="REGEX", + default=search_and_replace(None), + help="a search-and-replace regex applied to filenames, e.g. " + "`s/prog[0-9]/progN/`", + ) + p.add_argument( + "--mod-funcname", + type=search_and_replace, + metavar="REGEX", + default=search_and_replace(None), + help="like --mod-filename, but for function names", + ) p.add_argument( "--show", type=comma_separated_list, @@ -143,12 +211,19 @@ class Args(Namespace): ) p.add_argument( "cgout_filename", - nargs=1, + nargs="+", metavar="cachegrind-out-file", help="file produced by Cachegrind", ) - return p.parse_args(namespace=Args()) + # `args0` name used to avoid shadowing the global `args`, which pylint + # doesn't like. + args0 = p.parse_args(namespace=Args()) + if args0.diff and len(args0.cgout_filename) != 2: + p.print_usage(file=sys.stderr) + die("argument --diff: requires exactly two Cachegrind output files") + + return args0 # Args are stored in a global for easy access. @@ -178,7 +253,11 @@ class Events: # Like `sort_events`, but indices into `events`, rather than names. sort_indices: list[int] - def __init__(self, text: str) -> None: + def __init__(self) -> None: + # All fields are left uninitialized here, and set instead in `init`. + pass + + def init(self, text: str) -> None: self.events = text.split() self.num_events = len(self.events) @@ -245,9 +324,15 @@ def add_cc_to_cc(a_cc: Cc, b_cc: Cc) -> None: b_cc[i] += a_count +# Subtract the counts in `a_cc` from `b_cc`. +def sub_cc_from_cc(a_cc: Cc, b_cc: Cc) -> None: + for i, a_count in enumerate(a_cc): + b_cc[i] -= a_count + + # Unrolled version of `add_cc_to_cc`, for speed. def add_cc_to_ccs( - a_cc: Cc, b_cc1: Cc, b_cc2: Cc, b_cc3: Cc, b_cc4: Cc, b_cc5: Cc + a_cc: Cc, b_cc1: Cc, b_cc2: Cc, b_cc3: Cc, b_cc4: Cc, b_cc5: Cc, total_cc: Cc ) -> None: for i, a_count in enumerate(a_cc): b_cc1[i] += a_count @@ -255,6 +340,21 @@ def add_cc_to_ccs( b_cc3[i] += a_count b_cc4[i] += a_count b_cc5[i] += a_count + total_cc[i] += a_count + + +# Unrolled version of `sub_cc_from_cc`, for speed. Note that the last one, +# `total_cc`, is added. +def sub_cc_from_ccs( + a_cc: Cc, b_cc1: Cc, b_cc2: Cc, b_cc3: Cc, b_cc4: Cc, b_cc5: Cc, total_cc: Cc +) -> None: + for i, a_count in enumerate(a_cc): + b_cc1[i] -= a_count + b_cc2[i] -= a_count + b_cc3[i] -= a_count + b_cc4[i] -= a_count + b_cc5[i] -= a_count + total_cc[i] += a_count # Update `min_cc` and `max_cc` with `self`. @@ -266,59 +366,70 @@ def update_cc_extremes(self: Cc, min_cc: Cc, max_cc: Cc) -> None: min_cc[i] = count -# A deep cost centre with a dict for the inner names and CCs. +# Note: some abbrevations used below: +# - Ofl/ofl: original filename, as mentioned in a cgout file. +# - Ofn/ofn: original function name, as mentioned in a cgout file. +# - Mfl/mfl: modified filename, the result of passing an Ofl through +# `--mod-filename`. +# - Mfn/mfn: modified function name, the result of passing an Ofn through +# `--mod-funcname`. +# - Mname/mname: modified name, used for what could be an Mfl or an Mfn. + +# A deep cost centre with a dict for the inner mnames and CCs. class Dcc: outer_cc: Cc - inner_dict_name_cc: DictNameCc + inner_dict_mname_cc: DictMnameCc - def __init__(self, outer_cc: Cc, inner_dict_name_cc: DictNameCc) -> None: + def __init__(self, outer_cc: Cc, inner_dict_mname_cc: DictMnameCc) -> None: self.outer_cc = outer_cc - self.inner_dict_name_cc = inner_dict_name_cc + self.inner_dict_mname_cc = inner_dict_mname_cc -# A deep cost centre with a list for the inner names and CCs. Used during +# A deep cost centre with a list for the inner mnames and CCs. Used during # filtering and sorting. class Lcc: outer_cc: Cc - inner_list_name_cc: ListNameCc + inner_list_mname_cc: ListMnameCc - def __init__(self, outer_cc: Cc, inner_list_name_cc: ListNameCc) -> None: + def __init__(self, outer_cc: Cc, inner_list_mname_cc: ListMnameCc) -> None: self.outer_cc = outer_cc - self.inner_list_name_cc = inner_list_name_cc + self.inner_list_mname_cc = inner_list_mname_cc -# Per-file/function CCs. The list version is used during filtering and sorting. -DictNameCc = DefaultDict[str, Cc] -ListNameCc = list[tuple[str, Cc]] +# Per-Mfl/Mfn CCs. The list version is used during filtering and sorting. +DictMnameCc = DefaultDict[str, Cc] +ListMnameCc = list[tuple[str, Cc]] -# Per-file/function DCCs. The outer names are filenames and the inner names are -# function names, or vice versa. The list version is used during filtering and -# sorting. -DictNameDcc = DefaultDict[str, Dcc] -ListNameLcc = list[tuple[str, Lcc]] +# Per-Mfl/Mfn DCCs. The outer Mnames are Mfls and the inner Mnames are Mfns, or +# vice versa. The list version is used during filtering and sorting. +DictMnameDcc = DefaultDict[str, Dcc] +ListMnameLcc = list[tuple[str, Lcc]] -# Per-line CCs, organised by filename and line number. +# Per-line CCs, organised by Mfl and line number. DictLineCc = DefaultDict[int, Cc] -DictFlDictLineCc = DefaultDict[str, DictLineCc] +DictMflDictLineCc = DefaultDict[str, DictLineCc] - -def die(msg: str) -> NoReturn: - print("cg_annotate: error:", msg, file=sys.stderr) - sys.exit(1) +# A dictionary tracking how Ofls get mapped to Mfls by `--mod-filename`. If +# `--mod-filename` isn't used, each entry will be the identity mapping: ("foo" +# -> set(["foo"])). +DictMflOfls = DefaultDict[str, set[str]] -def read_cgout_file() -> tuple[ - str, - str, - Events, - DictNameDcc, - DictNameDcc, - DictFlDictLineCc, - Cc, -]: +def read_cgout_file( + cgout_filename: str, + is_first_file: bool, + descs: list[str], + cmds: list[str], + events: Events, + dict_mfl_ofls: DictMflOfls, + dict_mfl_dcc: DictMnameDcc, + dict_mfn_dcc: DictMnameDcc, + dict_mfl_dict_line_cc: DictMflDictLineCc, + summary_cc: Cc, +) -> None: # The file format is described in Cachegrind's manual. try: - cgout_file = open(args.cgout_filename[0], "r", encoding="utf-8") + cgout_file = open(cgout_filename, "r", encoding="utf-8") except OSError as err: die(f"{err}") @@ -340,40 +451,64 @@ def read_cgout_file() -> tuple[ desc += m.group(1) + "\n" else: break + descs.append(desc) # Read "cmd:" line. (`line` is already set from the "desc:" loop.) if m := re.match(r"cmd:\s+(.*)", line): - cmd = m.group(1) + cmds.append(m.group(1)) else: parse_die("missing a `command:` line") # Read "events:" line. line = readline() if m := re.match(r"events:\s+(.*)", line): - events = Events(m.group(1)) + if is_first_file: + events.init(m.group(1)) + else: + events2 = Events() + events2.init(m.group(1)) + if events.events != events2.events: + die("events in data files don't match") else: parse_die("missing an `events:` line") def mk_empty_dict_line_cc() -> DictLineCc: return defaultdict(events.mk_empty_cc) - # The current filename and function name. - fl = "" - fn = "" - - # Different places where we accumulate CC data. - dict_fl_dcc: DictNameDcc = defaultdict(events.mk_empty_dcc) - dict_fn_dcc: DictNameDcc = defaultdict(events.mk_empty_dcc) - dict_fl_dict_line_cc: DictFlDictLineCc = defaultdict(mk_empty_dict_line_cc) - summary_cc = None + # The current Mfl and Mfn. + mfl = "" + mfn = "" + + # These values are passed in by reference and are modified by this + # function. But they can't be properly initialized until the `events:` + # line of the first file is read and the number of events is known. So + # we initialize them in an invalid state in `main`, and then + # reinitialize them properly here, before their first use. + if is_first_file: + dict_mfl_dcc.default_factory = events.mk_empty_dcc + dict_mfn_dcc.default_factory = events.mk_empty_dcc + dict_mfl_dict_line_cc.default_factory = mk_empty_dict_line_cc + summary_cc.extend(events.mk_empty_cc()) # These are refs into the dicts above, used to avoid repeated lookups. # They are all overwritten before first use. - fl_dcc = events.mk_empty_dcc() - fn_dcc = events.mk_empty_dcc() - fl_dcc_inner_fn_cc = events.mk_empty_cc() - fn_dcc_inner_fl_cc = events.mk_empty_cc() + mfl_dcc = events.mk_empty_dcc() + mfn_dcc = events.mk_empty_dcc() + mfl_dcc_inner_mfn_cc = events.mk_empty_cc() + mfn_dcc_inner_mfl_cc = events.mk_empty_cc() dict_line_cc = mk_empty_dict_line_cc() + total_cc = events.mk_empty_cc() + + # When diffing, we negate the first cgout file's counts to effectively + # achieve `cgout2 - cgout1`. + if args.diff and is_first_file: + combine_cc_with_cc = sub_cc_from_cc + combine_cc_with_ccs = sub_cc_from_ccs + else: + combine_cc_with_cc = add_cc_to_cc + combine_cc_with_ccs = add_cc_to_ccs + + summary_cc_present = False # Line matching is done in order of pattern frequency, for speed. while line := readline(): @@ -385,37 +520,54 @@ def read_cgout_file() -> tuple[ except ValueError: parse_die("malformed or too many event counts") - # Record this CC at the file:function level, the function:file - # level, and the file/line level. - add_cc_to_ccs( + # Record this CC at various levels. + combine_cc_with_ccs( cc, - fl_dcc.outer_cc, - fn_dcc.outer_cc, - fl_dcc_inner_fn_cc, - fn_dcc_inner_fl_cc, + mfl_dcc.outer_cc, + mfn_dcc.outer_cc, + mfl_dcc_inner_mfn_cc, + mfn_dcc_inner_mfl_cc, dict_line_cc[line_num], + total_cc, ) elif line.startswith("fn="): - fn = line[3:-1] - # `fl_dcc` is unchanged. - fn_dcc = dict_fn_dcc[fn] - fl_dcc_inner_fn_cc = fl_dcc.inner_dict_name_cc[fn] - fn_dcc_inner_fl_cc = fn_dcc.inner_dict_name_cc[fl] + ofn = line[3:-1] + mfn = args.mod_funcname(ofn) + # `mfl_dcc` is unchanged. + mfn_dcc = dict_mfn_dcc[mfn] + mfl_dcc_inner_mfn_cc = mfl_dcc.inner_dict_mname_cc[mfn] + mfn_dcc_inner_mfl_cc = mfn_dcc.inner_dict_mname_cc[mfl] elif line.startswith("fl="): - fl = line[3:-1] + ofl = line[3:-1] + mfl = args.mod_filename(ofl) + dict_mfl_ofls[mfl].add(ofl) # A `fn=` line should follow, overwriting the function name. - fn = "<unspecified>" - fl_dcc = dict_fl_dcc[fl] - fn_dcc = dict_fn_dcc[fn] - fl_dcc_inner_fn_cc = fl_dcc.inner_dict_name_cc[fn] - fn_dcc_inner_fl_cc = fn_dcc.inner_dict_name_cc[fl] - dict_line_cc = dict_fl_dict_line_cc[fl] + mfn = "<unspecified>" + mfl_dcc = dict_mfl_dcc[mfl] + mfn_dcc = dict_mfn_dcc[mfn] + mfl_dcc_inner_mfn_cc = mfl_dcc.inner_dict_mname_cc[mfn] + mfn_dcc_inner_mfl_cc = mfn_dcc.inner_dict_mname_cc[mfl] + dict_line_cc = dict_mfl_dict_line_cc[mfl] elif m := re.match(r"summary:\s+(.*)", line): + summary_cc_present = True try: - summary_cc = events.mk_cc(m.group(1).split()) + this_summary_cc = events.mk_cc(m.group(1).split()) + combine_cc_with_cc(this_summary_cc, summary_cc) + + # Check summary is correct. Note that `total_cc` doesn't + # get negated for the first file in a diff, unlike the + # other CCs, because it's only used here as a sanity check. + if this_summary_cc != total_cc: + msg = ( + "`summary:` line doesn't match computed total\n" + f"- summary: {this_summary_cc}\n" + f"- computed: {total_cc}" + ) + parse_die(msg) + except ValueError: parse_die("malformed or too many event counts") @@ -427,31 +579,9 @@ def read_cgout_file() -> tuple[ parse_die(f"malformed line: {line[:-1]}") # Check if summary line was present. - if not summary_cc: + if not summary_cc_present: parse_die("missing `summary:` line, aborting") - # Check summary is correct. (Only using the outer CCs.) - total_cc = events.mk_empty_cc() - for dcc in dict_fl_dcc.values(): - add_cc_to_cc(dcc.outer_cc, total_cc) - if summary_cc != total_cc: - msg = ( - "`summary:` line doesn't match computed total\n" - f"- summary: {summary_cc}\n" - f"- total: {total_cc}" - ) - parse_die(msg) - - return ( - desc, - cmd, - events, - dict_fl_dcc, - dict_fn_dcc, - dict_fl_dict_line_cc, - summary_cc, - ) - # The width of a column, in three parts. class Width: @@ -487,7 +617,7 @@ class CcPrinter: # Text of a missing CC, which can be computed in advance. missing_cc_str: str - # Must call `init_ccs` or `init_list_name_lcc` after this. + # Must call `init_ccs` or `init_list_mname_lcc` after this. def __init__(self, events: Events, summary_cc: Cc) -> None: self.events = events self.summary_cc = summary_cc @@ -505,7 +635,7 @@ class CcPrinter: self.init_widths(min_cc, max_cc, None, None) - def init_list_name_lcc(self, list_name_lcc: ListNameLcc) -> None: + def init_list_mname_lcc(self, list_mname_lcc: ListMnameLcc) -> None: self.events_prefix = " " cumul_cc = self.events.mk_empty_cc() @@ -516,10 +646,10 @@ class CcPrinter: max_cc = self.events.mk_empty_cc() min_cumul_cc = self.events.mk_empty_cc() max_cumul_cc = self.events.mk_empty_cc() - for _, lcc in list_name_lcc: + for _, lcc in list_mname_lcc: # Consider both outer and inner CCs for `count` and `perc1`. update_cc_extremes(lcc.outer_cc, min_cc, max_cc) - for _, inner_cc in lcc.inner_list_name_cc: + for _, inner_cc in lcc.inner_list_mname_cc: update_cc_extremes(inner_cc, min_cc, max_cc) # Consider only outer CCs for `perc2`. @@ -604,24 +734,24 @@ class CcPrinter: print(suffix) - def print_lcc(self, lcc: Lcc, outer_name: str, cumul_cc: Cc) -> None: - print("> ", end="") + def print_lcc(self, indent: str, lcc: Lcc, outer_mname: str, cumul_cc: Cc) -> None: + print(indent, end="") if ( - len(lcc.inner_list_name_cc) == 1 - and lcc.outer_cc == lcc.inner_list_name_cc[0][1] + len(lcc.inner_list_mname_cc) == 1 + and lcc.outer_cc == lcc.inner_list_mname_cc[0][1] ): # There is only one inner CC, it met the threshold, and it is equal # to the outer CC. Print the inner CC and outer CC in a single # line, because they are the same. - inner_name = lcc.inner_list_name_cc[0][0] - self.print_cc(lcc.outer_cc, cumul_cc, f"{outer_name}:{inner_name}") + inner_mname = lcc.inner_list_mname_cc[0][0] + self.print_cc(lcc.outer_cc, cumul_cc, f"{outer_mname}:{inner_mname}") else: # There are multiple inner CCs, and at least one met the threshold. # Print the outer CC and then the inner CCs, indented. - self.print_cc(lcc.outer_cc, cumul_cc, f"{outer_name}:") - for inner_name, inner_cc in lcc.inner_list_name_cc: + self.print_cc(lcc.outer_cc, cumul_cc, f"{outer_mname}:") + for inner_mname, inner_cc in lcc.inner_list_mname_cc: print(" ", end="") - self.print_cc(inner_cc, None, f" {inner_name}") + self.print_cc(inner_cc, None, f" {inner_mname}") print() # If `cc2` is `None`, it's a vanilla CC or inner CC. Otherwise, it's an @@ -645,15 +775,42 @@ def print_fancy(text: str) -> None: print(fancy) -def print_metadata(desc: str, cmd: str, events: Events) -> None: +def print_metadata(descs: list[str], cmds: list[str], events: Events) -> None: print_fancy("Metadata") - print(desc, end="") - print("Command: ", cmd) - print("Data file: ", args.cgout_filename[0]) + + def all_the_same(strs: list[str]) -> bool: + for i in range(len(strs) - 1): + if strs[i] != strs[i + 1]: + return False + + return True + + print("Invocation: ", *sys.argv) + + # When there are multiple descriptions, they are usually all the same. Only + # print the description once in that case. + if all_the_same(descs): + print(descs[0], end="") + else: + for i, desc in enumerate(descs): + print(f"Description {i+1}:") + print(desc, end="") + + # Commands are sometimes the same, sometimes not. Always print them + # individually, but refer to the previous one when appropriate. + if len(cmds) == 1: + print("Command: ", cmds[0]) + else: + for i, cmd in enumerate(cmds): + if i > 0 and cmds[i - 1] == cmd: + print(f"Command {i+1}: (same as Command {i})") + else: + print(f"Command {i+1}: ", cmd) + print("Events recorded: ", *events.events) print("Events shown: ", *events.show_events) print("Event sort order:", *events.sort_events) - print("Threshold: ", args.threshold) + print("Threshold: ", args.threshold, "%", sep="") print("Annotation: ", "on" if args.annotate else "off") print() @@ -668,8 +825,8 @@ def print_summary(events: Events, summary_cc: Cc) -> None: print() -def print_name_summary( - kind: str, events: Events, dict_name_dcc: DictNameDcc, summary_cc: Cc +def print_mname_summary( + kind: str, indent: str, events: Events, dict_mname_dcc: DictMnameDcc, summary_cc: Cc ) -> set[str]: # The primary sort event is used for the threshold. threshold_index = events.sort_indices[0] @@ -677,66 +834,67 @@ def print_name_summary( # Convert the threshold from a percentage to an event count. threshold = args.threshold * abs(summary_cc[threshold_index]) / 100 - def meets_threshold(name_and_cc: tuple[str, Cc]) -> bool: - cc = name_and_cc[1] + def meets_threshold(mname_and_cc: tuple[str, Cc]) -> bool: + cc = mname_and_cc[1] return abs(cc[threshold_index]) >= threshold # Create a list with the outer CC counts in sort order, so that # left-to-right list comparison does the right thing. Plus the outer name # at the end for deterministic output when all the event counts are # identical in two CCs. - def key_name_and_lcc(name_and_lcc: tuple[str, Lcc]) -> tuple[list[int], str]: - (outer_name, lcc) = name_and_lcc + def key_mname_and_lcc(mname_and_lcc: tuple[str, Lcc]) -> tuple[list[int], str]: + (outer_mname, lcc) = mname_and_lcc return ( [abs(lcc.outer_cc[i]) for i in events.sort_indices], - outer_name, + outer_mname, ) - # Similar to `key_name_and_lcc`. - def key_name_and_cc(name_and_cc: tuple[str, Cc]) -> tuple[list[int], str]: - (name, cc) = name_and_cc - return ([abs(cc[i]) for i in events.sort_indices], name) + # Similar to `key_mname_and_lcc`. + def key_mname_and_cc(mname_and_cc: tuple[str, Cc]) -> tuple[list[int], str]: + (mname, cc) = mname_and_cc + return ([abs(cc[i]) for i in events.sort_indices], mname) # This is a `filter_map` operation, which Python doesn't directly support. - list_name_lcc: ListNameLcc = [] - for outer_name, dcc in dict_name_dcc.items(): + list_mname_lcc: ListMnameLcc = [] + for outer_mname, dcc in dict_mname_dcc.items(): # Filter out inner CCs for which the primary sort event count is below the # threshold, and sort the remainder. - inner_list_name_cc = sorted( - filter(meets_threshold, dcc.inner_dict_name_cc.items()), - key=key_name_and_cc, + inner_list_mname_cc = sorted( + filter(meets_threshold, dcc.inner_dict_mname_cc.items()), + key=key_mname_and_cc, reverse=True, ) # If no inner CCs meet the threshold, ignore the entire DCC, even if # the outer CC meets the threshold. - if len(inner_list_name_cc) == 0: + if len(inner_list_mname_cc) == 0: continue - list_name_lcc.append((outer_name, Lcc(dcc.outer_cc, inner_list_name_cc))) + list_mname_lcc.append((outer_mname, Lcc(dcc.outer_cc, inner_list_mname_cc))) - list_name_lcc = sorted(list_name_lcc, key=key_name_and_lcc, reverse=True) + list_mname_lcc = sorted(list_mname_lcc, key=key_mname_and_lcc, reverse=True) printer = CcPrinter(events, summary_cc) - printer.init_list_name_lcc(list_name_lcc) + printer.init_list_mname_lcc(list_mname_lcc) print_fancy(kind + " summary") printer.print_events(" " + kind.lower()) print() # Print LCCs. - threshold_names = set([]) + threshold_mnames = set([]) cumul_cc = events.mk_empty_cc() - for name, lcc in list_name_lcc: + for mname, lcc in list_mname_lcc: add_cc_to_cc(lcc.outer_cc, cumul_cc) - printer.print_lcc(lcc, name, cumul_cc) - threshold_names.add(name) + printer.print_lcc(indent, lcc, mname, cumul_cc) + threshold_mnames.add(mname) - return threshold_names + return threshold_mnames class AnnotatedCcs: line_nums_known_cc: Cc line_nums_unknown_cc: Cc + non_identical_cc: Cc unreadable_cc: Cc below_threshold_cc: Cc files_unknown_cc: Cc @@ -744,6 +902,7 @@ class AnnotatedCcs: labels = [ " annotated: files known & above threshold & readable, line numbers known", " annotated: files known & above threshold & readable, line numbers unknown", + "unannotated: files known & above threshold & two or more non-identical", "unannotated: files known & above threshold & unreadable ", "unannotated: files known & below threshold", "unannotated: files unknown", @@ -752,6 +911,7 @@ class AnnotatedCcs: def __init__(self, events: Events) -> None: self.line_nums_known_cc = events.mk_empty_cc() self.line_nums_unknown_cc = events.mk_empty_cc() + self.non_identical_cc = events.mk_empty_cc() self.unreadable_cc = events.mk_empty_cc() self.below_threshold_cc = events.mk_empty_cc() self.files_unknown_cc = events.mk_empty_cc() @@ -760,6 +920,7 @@ class AnnotatedCcs: return [ self.line_nums_known_cc, self.line_nums_unknown_cc, + self.non_identical_cc, self.unreadable_cc, self.below_threshold_cc, self.files_unknown_cc, @@ -776,10 +937,11 @@ def mk_warning(msg: str) -> str: """ -def warn_src_file_is_newer(src_filename: str, cgout_filename: str) -> None: +def warn_ofls_are_all_newer(ofls: list[str], cgout_filename: str) -> None: + s = "".join([f"@ - {ofl}\n" for ofl in ofls]) msg = f"""\ -@ Source file '{src_filename}' is newer than data file '{cgout_filename}'. -@ Annotations may not be correct. +@ Original source files are all newer than data file '{cgout_filename}': +{s}@ Annotations may not be correct. """ print(mk_warning(msg)) @@ -798,10 +960,6 @@ def print_annotated_src_file( annotated_ccs: AnnotatedCcs, summary_cc: Cc, ) -> None: - # If the source file is more recent than the cgout file, issue warning. - if os.stat(src_file.name).st_mtime_ns > os.stat(args.cgout_filename[0]).st_mtime_ns: - warn_src_file_is_newer(src_file.name, args.cgout_filename[0]) - printer = CcPrinter(events, summary_cc) printer.init_ccs(list(dict_line_cc.values())) # The starting fancy has already been printed by the caller. @@ -884,52 +1042,101 @@ def print_annotated_src_file( print() -# This (partially) consumes `dict_fl_dict_line_cc`. +# This partially consumes `dict_mfl_dict_line_cc`, and fully consumes +# `dict_mfl_olfs`. def print_annotated_src_files( + ann_mfls: set[str], events: Events, - ann_src_filenames: set[str], - dict_fl_dict_line_cc: DictFlDictLineCc, + dict_mfl_ofls: DictMflOfls, + dict_mfl_dict_line_cc: DictMflDictLineCc, summary_cc: Cc, ) -> AnnotatedCcs: annotated_ccs = AnnotatedCcs(events) - 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(): - add_cc_to_cc(line_cc, accum_cc) + def add_dict_line_cc_to_cc(dict_line_cc: DictLineCc, accum_cc: Cc) -> None: + for line_cc in dict_line_cc.values(): + add_cc_to_cc(line_cc, accum_cc) # 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) + ann_mfls.discard("???") + if "???" in dict_mfl_dict_line_cc: + dict_line_cc = dict_mfl_dict_line_cc.pop("???") + add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.files_unknown_cc) + + def print_ann_fancy(mfl: str) -> None: + print_fancy(f"Annotated source file: {mfl}") + + # This can raise an `OSError`. + def all_ofl_contents_identical(ofls: list[str]) -> bool: + for i in range(len(ofls) - 1): + if not filecmp.cmp(ofls[i], ofls[i + 1], shallow=False): + return False + + return True - def print_ann_fancy(src_filename: str) -> None: - print_fancy(f"Annotated source file: {src_filename}") + for mfl in sorted(ann_mfls): + ofls = sorted(dict_mfl_ofls.pop(mfl)) + first_ofl = ofls[0] - for src_filename in sorted(ann_src_filenames): try: - with open(src_filename, "r", encoding="utf-8") as src_file: - dict_line_cc = dict_fl_dict_line_cc.pop(src_filename, None) - assert dict_line_cc is not None - print_ann_fancy(src_filename) - print_annotated_src_file( - events, - dict_line_cc, - src_file, - annotated_ccs, - summary_cc, + if all_ofl_contents_identical(ofls): + # All the Ofls that map to this Mfl are identical, which means we + # can annotate, and it doesn't matter which Ofl we use. + with open(first_ofl, "r", encoding="utf-8") as src_file: + dict_line_cc = dict_mfl_dict_line_cc.pop(mfl) + print_ann_fancy(mfl) + + # Because all the Ofls are identical, we can treat their + # mtimes as if they are all as early as the earliest one. + # Therefore, we warn only if the earliest source file is + # more recent than the cgout file. + min_ofl_st_mtime_ns = min( + [os.stat(ofl).st_mtime_ns for ofl in ofls] + ) + + for cgout_filename in args.cgout_filename: + if min_ofl_st_mtime_ns > os.stat(cgout_filename).st_mtime_ns: + warn_ofls_are_all_newer(ofls, cgout_filename) + + print_annotated_src_file( + events, + dict_line_cc, + src_file, + annotated_ccs, + summary_cc, + ) + else: + dict_line_cc = dict_mfl_dict_line_cc.pop(mfl) + add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.non_identical_cc) + + # We could potentially do better here. + # - Annotate until the first line where the src files diverge. + # - Also, heuristic resyncing, e.g. by looking for matching + # lines (of sufficient complexity) after a divergence. + print_ann_fancy(mfl) + print( + "Unannotated because two or more of these original files are not " + "identical:", + *ofls, + sep="\n- ", ) + print() except OSError: - dict_line_cc = dict_fl_dict_line_cc.pop(src_filename, None) + dict_line_cc = dict_mfl_dict_line_cc.pop(mfl) add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.unreadable_cc) - print_ann_fancy(src_filename) - print("This file was unreadable") + print_ann_fancy(mfl) + print( + "Unannotated because one or more of these original files are " + "unreadable:", + *ofls, + sep="\n- ", + ) print() - # Sum the CCs remaining in `dict_fl_dict_line_cc`, which are all in files + # Sum the CCs remaining in `dict_mfl_dict_line_cc`, which are all in files # below the threshold. - for dict_line_cc in dict_fl_dict_line_cc.values(): + for dict_line_cc in dict_mfl_dict_line_cc.values(): add_dict_line_cc_to_cc(dict_line_cc, annotated_ccs.below_threshold_cc) return annotated_ccs @@ -965,26 +1172,46 @@ def print_annotation_summary( def main() -> None: - ( - desc, - cmd, - events, - dict_fl_dcc, - dict_fn_dcc, - dict_fl_dict_line_cc, - summary_cc, - ) = read_cgout_file() + # Metadata, initialized to empty states. + descs: list[str] = [] + cmds: list[str] = [] + events = Events() + + # For tracking original filenames to modified filenames. + dict_mfl_ofls: DictMflOfls = defaultdict(set) + + # Different places where we accumulate CC data. Initialized to invalid + # states prior to the number of events being known. + dict_mfl_dcc: DictMnameDcc = defaultdict(None) + dict_mfn_dcc: DictMnameDcc = defaultdict(None) + dict_mfl_dict_line_cc: DictMflDictLineCc = defaultdict(None) + summary_cc: Cc = [] + + for n, filename in enumerate(args.cgout_filename): + is_first_file = n == 0 + read_cgout_file( + filename, + is_first_file, + descs, + cmds, + events, + dict_mfl_ofls, + dict_mfl_dcc, + dict_mfn_dcc, + dict_mfl_dict_line_cc, + summary_cc, + ) # Each of the following calls prints a section of the output. - print_metadata(desc, cmd, events) + print_metadata(descs, cmds, events) print_summary(events, summary_cc) - ann_src_filenames = print_name_summary( - "File:function", events, dict_fl_dcc, summary_cc + ann_mfls = print_mname_summary( + "File:function", "< ", events, dict_mfl_dcc, summary_cc ) - print_name_summary("Function:file", events, dict_fn_dcc, summary_cc) + print_mname_summary("Function:file", "> ", events, dict_mfn_dcc, summary_cc) if args.annotate: annotated_ccs = print_annotated_src_files( - events, ann_src_filenames, dict_fl_dict_line_cc, summary_cc + ann_mfls, events, dict_mfl_ofls, dict_mfl_dict_line_cc, summary_cc ) print_annotation_summary(events, annotated_ccs, summary_cc) diff --git a/cachegrind/cg_diff.in b/cachegrind/cg_diff.in index 38910f31b1..d3a63189ea 100755 --- a/cachegrind/cg_diff.in +++ b/cachegrind/cg_diff.in @@ -66,7 +66,7 @@ class Args(Namespace): if regex is None: return lambda s: s - # Extract the parts of a `s/old/new/tail` regex. `(?<!\\)/` is an + # Extract the parts of an `s/old/new/tail` regex. `(?<!\\)/` is an # example of negative lookbehind. It means "match a forward slash # unless preceded by a backslash". m = re.match(r"s/(.*)(?<!\\)/(.*)(?<!\\)/(g|i|gi|ig|)$", regex) @@ -74,7 +74,7 @@ class Args(Namespace): raise ValueError # Forward slashes must be escaped in an `s/old/new/` expression, - # but we then must unescape them before using them with `re.sub` + # but we then must unescape them before using them with `re.sub`. pat = m.group(1).replace(r"\/", r"/") repl = m.group(2).replace(r"\/", r"/") tail = m.group(3) @@ -91,7 +91,11 @@ class Args(Namespace): return lambda s: re.sub(re.compile(pat, flags=flags), repl, s, count=count) - p = ArgumentParser(description="Diff two Cachegrind output files.") + desc = ( + "Diff two Cachegrind output files. Deprecated; use " + "`cg_annotate --diff` instead." + ) + p = ArgumentParser(description=desc) p.add_argument("--version", action="version", version="%(prog)s-@VERSION@") @@ -304,8 +308,8 @@ def main() -> None: (cmd1, events1, dict_flfn_cc1, summary_cc1) = read_cgout_file(filename1) (cmd2, events2, dict_flfn_cc2, summary_cc2) = read_cgout_file(filename2) - if events1.num_events != events2.num_events: - die("events don't match") + if events1.events != events2.events: + die("events in data files don't match") # Subtract file 1's CCs from file 2's CCs, at the Flfn level. for flfn, flfn_cc1 in dict_flfn_cc1.items(): diff --git a/cachegrind/cg_merge.in b/cachegrind/cg_merge.in index 8304e8b279..7c385b4c8e 100755 --- a/cachegrind/cg_merge.in +++ b/cachegrind/cg_merge.in @@ -51,7 +51,11 @@ class Args(Namespace): @staticmethod def parse() -> Args: - p = ArgumentParser(description="Merge multiple Cachegrind output files.") + desc = ( + "Merge multiple Cachegrind output files. Deprecated; use " + "`cg_annotate` with multiple Cachegrind output files instead." + ) + p = ArgumentParser(description=desc) p.add_argument("--version", action="version", version="%(prog)s-@VERSION@") @@ -272,8 +276,8 @@ def main() -> None: events1 = events_n else: assert events1 - if events1.num_events != events_n.num_events: - die("events don't match") + if events1.events != events_n.events: + die("events in data files don't match") def write_output(f: TextIO) -> None: # These assertions hold because the loop above executes at least twice. diff --git a/cachegrind/tests/Makefile.am b/cachegrind/tests/Makefile.am index d38d300b90..9b977d5810 100644 --- a/cachegrind/tests/Makefile.am +++ b/cachegrind/tests/Makefile.am @@ -16,9 +16,17 @@ EXTRA_DIST = \ ann-diff1.post.exp ann-diff1.stderr.exp ann-diff1.vgtest \ ann-diff2.post.exp ann-diff2.stderr.exp ann-diff2.vgtest \ ann-diff2a.cgout ann-diff2b.cgout \ + ann-diff2-aux/ann-diff2-basic.rs \ + ann-diff3.post.exp ann-diff3.stderr.exp ann-diff3.vgtest \ + ann-diff4.post.exp ann-diff4.stderr.exp ann-diff4.vgtest \ + ann-diff4a.cgout ann-diff4b.cgout \ + ann-diff4a-aux/w.rs ann-diff4a-aux/x.rs ann-diff4a-aux/y.rs \ + ann-diff4a-aux/z.rs \ + ann-diff4b-aux/w.rs ann-diff4b-aux/x.rs ann-diff4b-aux/y.rs \ ann-merge1.post.exp ann-merge1.stderr.exp ann-merge1.vgtest \ ann-merge1a.cgout ann-merge1b.cgout \ ann-merge-x.rs ann-merge-y.rs \ + ann-merge2.post.exp ann-merge2.stderr.exp ann-merge2.vgtest \ ann1a.post.exp ann1a.stderr.exp ann1a.vgtest ann1.cgout \ ann1b.post.exp ann1b.stderr.exp ann1b.vgtest ann1b.cgout \ ann2.post.exp ann2.stderr.exp ann2.vgtest ann2.cgout \ diff --git a/cachegrind/tests/ann-diff1.post.exp b/cachegrind/tests/ann-diff1.post.exp index 54962b513d..d8ccea091e 100644 --- a/cachegrind/tests/ann-diff1.post.exp +++ b/cachegrind/tests/ann-diff1.post.exp @@ -1,13 +1,13 @@ -------------------------------------------------------------------------------- -- Metadata -------------------------------------------------------------------------------- +Invocation: ../cg_annotate --mod-filename=s/a.c/A.c/ --mod-funcname s/MAIN/Main/ ann-diff1.cgout Files compared: ann1.cgout; ann1b.cgout Command: ./a.out; ./a.out -Data file: ann-diff1.cgout Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Events shown: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw -Threshold: 0.1 +Threshold: 0.1% Annotation: on -------------------------------------------------------------------------------- @@ -22,17 +22,17 @@ Ir________________ I1mr ILmr Dr_________________ D1mr DLmr Dw D1mw DLmw -------------------------------------------------------------------------------- Ir________________________ I1mr________ ILmr________ Dr_________________________ D1mr________ DLmr________ Dw__________ D1mw________ DLmw________ file:function -> 5,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) -2,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) a.c:MAIN +< 5,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) -2,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) A.c:Main -------------------------------------------------------------------------------- -- Function:file summary -------------------------------------------------------------------------------- Ir________________________ I1mr________ ILmr________ Dr_________________________ D1mr________ DLmr________ Dw__________ D1mw________ DLmw________ function:file -> 5,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) -2,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) MAIN:a.c +> 5,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) -2,000,000 (100.0%, 100.0%) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) 0 (n/a, n/a) Main:A.c -------------------------------------------------------------------------------- --- Annotated source file: a.c +-- Annotated source file: A.c -------------------------------------------------------------------------------- Ir________________ I1mr ILmr Dr_________________ D1mr DLmr Dw D1mw DLmw @@ -45,6 +45,7 @@ Ir________________ I1mr ILmr Dr_________________ D1mr DLmr Dw D1mw DLmw 0 0 0 0 0 0 0 0 0 annotated: files known & above threshold & readable, line numbers known 5,000,000 (100.0%) 0 0 -2,000,000 (100.0%) 0 0 0 0 0 annotated: files known & above threshold & readable, line numbers unknown + 0 0 0 0 0 0 0 0 0 unannotated: files known & above threshold & two or more non-identical 0 0 0 0 0 0 0 0 0 unannotated: files known & above threshold & unreadable 0 0 0 0 0 0 0 0 0 unannotated: files known & below threshold 0 0 0 0 0 0 0 0 0 unannotated: files unknown diff --git a/cachegrind/tests/ann-diff1.vgtest b/cachegrind/tests/ann-diff1.vgtest index e379401876..ab119b3b36 100644 --- a/cachegrind/tests/ann-diff1.vgtest +++ b/cachegrind/tests/ann-diff1.vgtest @@ -1,6 +1,8 @@ # The `prog` doesn't matter because we don't use its output. Instead we test -# the post-processing of the `ann{1,1b}.cgout` test files. +# the post-processing of the cgout files. prog: ../../tests/true vgopts: --cachegrind-out-file=cachegrind.out -post: python3 ../cg_diff --mod-funcname="s/main/MAIN/" ann1.cgout ann1b.cgout > ann-diff1.cgout && python3 ../cg_annotate ann-diff1.cgout -cleanup: rm ann-diff1.cgout + +post: python3 ../cg_diff --mod-funcname="s/main/MAIN/" ann1.cgout ann1b.cgout > ann-diff1.cgout && python3 ../cg_annotate --mod-filename="s/a.c/A.c/" --mod-funcname s/MAIN/Main/ ann-diff1.cgout + +cleanup: rm cachegrind.out ann-diff1.cgout diff --git a/cachegrind/tests/ann-diff2.post.exp b/cachegrind/tests/ann-diff2.post.exp index e1060dbd23..b6567418f7 100644 --- a/cachegrind/tests/ann-diff2.post.exp +++ b/cachegrind/tests/ann-diff2.post.exp @@ -1,13 +1,13 @@ -------------------------------------------------------------------------------- -- Metadata -------------------------------------------------------------------------------- +Invocation: ../cg_annotate ann-diff2c.cgout Files compared: ann-diff2a.cgout; ann-diff2b.cgout Command: cmd1; cmd2 -Data file: ann-diff2c.cgout Events recorded: One Two Events shown: One Two Event sort order: One Two -Threshold: 0.1 +Threshold: 0.1% Annotation: on -------------------------------------------------------------------------------- @@ -22,7 +22,7 @@ One___________ Two___________ -------------------------------------------------------------------------------- One___________________ Two___________________ file:function -> 2,100 (100.0%, 100.0%) 1,900 (100.0%, 100.0%) aux/ann-diff2-basic.rs: +< 2,100 (100.0%, 100.0%) 1,900 (100.0%, 100.0%) aux/ann-diff2-basic.rs: 1,000 (47.6%) 1,000 (52.6%) groffN 1,000 (47.6%) 1,000 (52.6%) fN_ffN_fooN_F4_g5 100 (4.8%) -100 (-5.3%) basic1 @@ -41,7 +41,8 @@ One___________ Two___________ -------------------------------------------------------------------------------- -- Annotated source file: aux/ann-diff2-basic.rs -------------------------------------------------------------------------------- -This file was unreadable +Unannotated because one or more of these original files are unreadable: +- aux/ann-diff2-basic.rs -------------------------------------------------------------------------------- -- Annotation summary @@ -50,6 +51,7 @@ One___________ Two___________ 0 0 annotated: files known & above threshold & readable, line numbers known 0 0 annotated: files known & above threshold & readable, line numbers unknown + 0 0 unannotated: files known & above threshold & two or more non-identical 2,100 (100.0%) 1,900 (100.0%) unannotated: files known & above threshold & unreadable 0 0 unannotated: files known & below threshold 0 0 unannotated: files unknown diff --git a/cachegrind/tests/ann-diff2.vgtest b/cachegrind/tests/ann-diff2.vgtest index 7b395e4e48..bae3ab9875 100644 --- a/cachegrind/tests/ann-diff2.vgtest +++ b/cachegrind/tests/ann-diff2.vgtest @@ -1,6 +1,8 @@ # The `prog` doesn't matter because we don't use its output. Instead we test -# the post-processing of the `ann-diff2{a,b}.cgout` test files. +# the post-processing of the cgout files. prog: ../../tests/true vgopts: --cachegrind-out-file=cachegrind.out + post: python3 ../cg_diff --mod-filename="s/.*aux\//aux\//i" --mod-funcname="s/(f[a-z]*)[0-9]/\1N/g" ann-diff2a.cgout ann-diff2b.cgout > ann-diff2c.cgout && python3 ../cg_annotate ann-diff2c.cgout -cleanup: rm ann-diff2c.cgout + +cleanup: rm cachegrind.out ann-diff2c.cgout diff --git a/cachegrind/tests/ann-diff2b.cgout b/cachegrind/tests/ann-diff2b.cgout index 9fb733e708..e6864107bb 100644 --- a/cachegrind/tests/ann-diff2b.cgout +++ b/cachegrind/tests/ann-diff2b.cgout @@ -1,4 +1,4 @@ -desc: Description for ann-diff2a.cgout +desc: Description for ann-diff2b.cgout cmd: cmd2 events: One Two diff --git a/cachegrind/tests/ann-diff3.post.exp b/cachegrind/tests/ann-diff3.post.exp new file mode 100644 index 0000000000..fa7ea4ad7b --- /dev/null +++ b/cachegrind/tests/ann-diff3.post.exp @@ -0,0 +1,63 @@ +-------------------------------------------------------------------------------- +-- Metadata +-------------------------------------------------------------------------------- +Invocation: ../cg_annotate --diff --mod-filename=s/.*aux\//aux\//i --mod-funcname=s/(f[a-z]*)[0-9]/\1N/g ann-diff2a.cgout ann-diff2b.cgout +Description 1: +Description for ann-diff2a.cgout +Description 2: +Description for ann-diff2b.cgout +Command 1: cmd1 +Command 2: cmd2 +Events recorded: One Two +Events shown: One Two +Event sort order: One Two +Threshold: 0.1% +Annotation: on + +-------------------------------------------------------------------------------- +-- Summary +-------------------------------------------------------------------------------- +One___________ Two___________ + +2,100 (100.0%) 1,900 (100.0%) PROGRAM TOTALS + +-------------------------------------------------------------------------------- +-- File:function summary +-------------------------------------------------------------------------------- + One___________________ Two___________________ file:function + +< 2,100 (100.0%, 100.0%) 1,900 (100.0%, 100.0%) aux/ann-diff2-basic.rs: + 1,000 (47.6%) 1,000 (52.6%) groffN + 1,000 (47.6%) 1,000 (52.6%) fN_ffN_fooN_F4_g5 + 100 (4.8%) -100 (-5.3%) basic1 + +-------------------------------------------------------------------------------- +-- Function:file summary +-------------------------------------------------------------------------------- + One__________________ Two__________________ function:file + +> 1,000 (47.6%, 47.6%) 1,000 (52.6%, 52.6%) groffN:aux/ann-diff2-basic.rs + +> 1,000 (47.6%, 95.2%) 1,000 (52.6%, 105.3%) fN_ffN_fooN_F4_g5:aux/ann-diff2-basic.rs + +> 100 (4.8%, 100.0%) -100 (-5.3%, 100.0%) basic1:aux/ann-diff2-basic.rs + +-------------------------------------------------------------------------------- +-- Annotated source file: aux/ann-diff2-basic.rs +-------------------------------------------------------------------------------- +Unannotated because one or more of these original files are unreadable: +- ann2-diff-AUX/ann-diff2-basic.rs +- ann2-diff-Aux/ann-diff2-basic.rs + +-------------------------------------------------------------------------------- +-- Annotation summary +-------------------------------------------------------------------------------- +One___________ Two___________ + + 0 0 annotated: files known & above threshold & readable, line numbers known + 0 0 annotated: files known & above threshold & readable, line numbers unknown + 0 0 unannotated: files known & above threshold & two or more non-identical +2,100 (100.0%) 1,900 (100.0%) unannotated: files known & above threshold & unreadable + 0 0 unannotated: files known & below threshold + 0 0 unannotated: files unknown + diff --git a/cachegrind/tests/ann-diff3.stderr.exp b/cachegrind/tests/ann-diff3.stderr.exp new file mode 100644 index 0000000000..ec68407b27 --- /dev/null +++ b/cachegrind/tests/ann-diff3.stderr.exp @@ -0,0 +1,3 @@ + + +I refs: diff --git a/cachegrind/tests/ann-diff3.vgtest b/cachegrind/tests/ann-diff3.vgtest new file mode 100644 index 0000000000..5831e3de61 --- /dev/null +++ b/cachegrind/tests/ann-diff3.vgtest @@ -0,0 +1,8 @@ +# The `prog` doesn't matter because we don't use its output. Instead we test +# the post-processing of the cgout files. +prog: ../../tests/true +vgopts: --cachegrind-out-file=cachegrind.out + +post: python3 ../cg_annotate --diff --mod-filename="s/.*aux\//aux\//i" --mod-funcname="s/(f[a-z]*)[0-9]/\1N/g" ann-diff2a.cgout ann-diff2b.cgout + +cleanup: rm cachegrind.out diff --git a/cachegrind/tests/ann-diff4.post.exp b/cachegrind/tests/ann-diff4.post.exp new file mode 100644 index 0000000000..0196948a62 --- /dev/null +++ b/cachegrind/tests/ann-diff4.post.exp @@ -0,0 +1,125 @@ +-------------------------------------------------------------------------------- +-- Metadata +-------------------------------------------------------------------------------- +Invocation: ../cg_annotate ann-diff4a.cgout ann-diff4b.cgout --mod-filename=s/ann-diff4[ab]/ann-diff4N/ --diff +DescA +DescB +DescC +Command 1: my-command +Command 2: (same as Command 1) +Events recorded: Ir +Events shown: Ir +Event sort order: Ir +Threshold: 0.1% +Annotation: on + +-------------------------------------------------------------------------------- +-- Summary +-------------------------------------------------------------------------------- +Ir__________ + +700 (100.0%) PROGRAM TOTALS + +-------------------------------------------------------------------------------- +-- File:function summary +-------------------------------------------------------------------------------- + Ir___________________ file:function + +< 600 (85.7%, 85.7%) ann-diff4N-aux/y.rs:b + +< 200 (28.6%, 114.3%) ann-diff4N-aux/x.rs:a + +< -200 (-28.6%, 85.7%) ann-diff4N-aux/w.rs:a + +< 200 (28.6%, 114.3%) ann-diff4N-aux/no-such-file.rs:f + +< -100 (-14.3%, 100.0%) ann-diff4N-aux/z.rs:c + +-------------------------------------------------------------------------------- +-- Function:file summary +-------------------------------------------------------------------------------- + Ir___________________ function:file + +> 600 (85.7%, 85.7%) b:ann-diff4N-aux/y.rs + +> 200 (28.6%, 114.3%) f:ann-diff4N-aux/no-such-file.rs + +> -100 (-14.3%, 100.0%) c:ann-diff4N-aux/z.rs + +> 0 (0.0%, 100.0%) a: + 200 (28.6%) ann-diff4N-aux/x.rs + -200 (-28.6%) ann-diff4N-aux/w.rs + +-------------------------------------------------------------------------------- +-- Annotated source file: ann-diff4N-aux/no-such-file.rs +-------------------------------------------------------------------------------- +Unannotated because one or more of these original files are unreadable: +- ann-diff4a-aux/no-such-file.rs +- ann-diff4b-aux/no-such-file.rs + +-------------------------------------------------------------------------------- +-- Annotated source file: ann-diff4N-aux/w.rs +-------------------------------------------------------------------------------- +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Original source files are all newer than data file 'ann-diff4a.cgout': +@ - ann-diff4a-aux/w.rs +@ - ann-diff4b-aux/w.rs +@ Annotations may not be correct. +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Original source files are all newer than data file 'ann-diff4b.cgout': +@ - ann-diff4a-aux/w.rs +@ - ann-diff4b-aux/w.rs +@ Annotations may not be correct. +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +Ir___________ + +-200 (-28.6%) one + . two + . three + +-------------------------------------------------------------------------------- +-- Annotated source file: ann-diff4N-aux/x.rs +-------------------------------------------------------------------------------- +Ir___________ + + 100 (14.3%) <unknown (line 0)> + +-200 (-28.6%) one + 300 (42.9%) two + . three + . four + . five + +-------------------------------------------------------------------------------- +-- Annotated source file: ann-diff4N-aux/y.rs +-------------------------------------------------------------------------------- +Unannotated because two or more of these original files are not identical: +- ann-diff4a-aux/y.rs +- ann-diff4b-aux/y.rs + +-------------------------------------------------------------------------------- +-- Annotated source file: ann-diff4N-aux/z.rs +-------------------------------------------------------------------------------- +Unannotated because one or more of these original files are unreadable: +- ann-diff4a-aux/z.rs +- ann-diff4b-aux/z.rs + +-------------------------------------------------------------------------------- +-- Annotation summary +-------------------------------------------------------------------------------- +Ir___________ + +-100 (-14.3%) annotated: files known & above threshold & readable, line numbers known + 100 (14.3%) annotated: files known & above threshold & readable, line numbers unknown + 600 (85.7%) unannotated: files known & above threshold & two or more non-identical + 100 (14.3%) unannotated: files known & above threshold & unreadable + 0 unannotated: files known & below threshold + 0 unannotated: files unknown + diff --git a/cachegrind/tests/ann-diff4.stderr.exp b/cachegrind/tests/ann-diff4.stderr.exp new file mode 100644 index 0000000000..ec68407b27 --- /dev/null +++ b/cachegrind/tests/ann-diff4.stderr.exp @@ -0,0 +1,3 @@ + + +I refs: diff --git a/cachegrind/tests/ann-diff4.vgtest b/cachegrind/tests/ann-diff4.vgtest new file mode 100644 index 0000000000..da6e00a216 --- /dev/null +++ b/cachegrind/tests/ann-diff4.vgtest @@ -0,0 +1,14 @@ +# The `prog` doesn't matter becaus... [truncated message content] |
|
From: Jojo R <rj...@li...> - 2023-04-21 10:06:23
|
Hi,
We consider to add RVV/Vector [1] feature in valgrind, there are some
challenges.
RVV like ARM's SVE [2] programming model, it's scalable/VLA, that means
the vector length is agnostic.
ARM's SVE is not supported in valgrind :(
There are three major issues in implementing RVV instruction set in
Valgrind as following:
1. Scalable vector register width VLENB
2. Runtime changing property of LMUL and SEW
3. Lack of proper VEX IR to represent all vector operations
We propose applicable methods to solve 1 and 2. As for 3, we explore
several possible but maybe imperfect approaches to handle different cases.
We start from 1. As each guest register should be described in
VEXGuestState struct, the vector registers with scalable width of VLENB
can be added into VEXGuestState as arrays using an allowable maximum
length like 2048/4096.
The actual available access range can be determined at Valgrind startup
time by querying the CPU for its vector capability or some suitable
setup steps.
To solve problem 2, we are inspired by already-proven techniques in
QEMU, where translation blocks are broken up when certain critical CSRs
are set. Because the guest code to IR translation relies on the precise
value of LMUL/SEW and they may change within a basic block, we can break
up the basic block each time encountering a vsetvl{i} instruction and
return to the scheduler to execute the translated code and update
LMUL/SEW. Accordingly, translation cache management should be refactored
to detect the changing of LMUL/SEW to invalidate outdated code cache.
Without losing the generality, the LMUL/SEW should be encoded into an
ULong flag such that other architectures can leverage this flag to store
their arch-dependent information. The TTentry struct should also take
the flag into account no matter insertion or deletion. By doing this,
the flag carries the newest LMUL/SEW throughout the simulation and can
be passed to disassemble functions using the VEXArchInfo struct such
that we can get the real and newest value of LMUL and SEW to facilitate
our translation.
Also, some architecture-related code should be taken care of. Like
m_dispatch part, disp_cp_xindir function looks up code cache using
hardcoded assembly by checking the requested guest state IP and
translation cache entry address with no more constraints. Many other
modules should be checked to ensure the in-time update of LMUL/SEW is
instantly visible to essential parts in Valgrind.
The last remaining big issue is 3, which we introduce some ad-hoc
approaches to deal with. We summarize these approaches into three types
as following:
1. Break down a vector instruction to scalar VEX IR ops.
2. Break down a vector instruction to fixed-length VEX IR ops.
3. Use dirty helpers to realize vector instructions.
The very first method theoretically exists but is probably not
applicable as the number of IR ops explodes when a large VLENB is
adopted. Imaging a configuration of VLENB=512, SEW=8, LMUL=8, the VL is
512 * 8 / 8 = 512, meaning that a single vector instruction turns into
512 scalar instructions and each scalar instruction would be expanded to
multiple IRs. To make things worse, the tool instrumentation will insert
more IRs between adjacent scalar IR ops. As a result, the performance is
likely to be slowed down thousand times during running a real-world
application with lots of vector instructions. Therefore, the other two
methods are more promising and we will discuss them below.
2 and 3 are not mutually exclusive as we may choose a suitable method
from them to implement a vector instruction regarding its concrete
behavior. To explain these methods in detail, we present some instances
to illustrate their pros and cons.
In terms of method 2, we have real values of VLENB/LMUL/SEW. The simple
case is VLENB <= 256 and LMUL=1, where many SIMD IR ops are available
and can be directly applied to represent vector operations. However,
even when VLENB is restricted to 128, it still exceeds the maximum SIMD
width of 256 supported by VEX IR if LMUL>2. Hence, here are two variants
of method 2 to deal with long vectors:
*2.1*Add more SIMD IR ops such as 1024/2048/4096, and translate vector
instructions in the granularity of VLENB. Accordingly, VLENB=4096 with
LMUL=2 is fulfilled by two 4096 SIMD VEX IR ops.
* *pros*: it encourages VEX backend to generate more compact and
efficient SIMD code (maybe). Particularly,it accommodatesmask and
gather/scatter (indexed) instructions by delivering more information
in IR itself.
* *cons*: too many new IR ops need to be introduced in VEX as each op
of different length should implement its add/sub/mul variants. New
data types to denote long vectors are necessary too, causing
difficulties in both VEX backend register allocation and tool
instrumentation.
*2.2*Break down long vectors to multiple repeated SIMD ops. For
instance, a vadd.vv vector instruction with VLENB=256/LMUL=2/SEW=8 is
composed of four operators of Iop_Add8x16 type.
* *pros:*less efforts are required in register allocation and tool
instrumentation. The VEX frontend is able to notify the backend to
generate efficient vector instructions by existing Iops. It better
trades off the complexity of adding many long vector IR ops and the
benefit of generating high-efficiency host code.
* *cons:*it is hard to describe a mask operation given that the mask
is pretty flexible (the least significant bit of each segment of
v0). Additionally, gather/scatter instructions may have similar
problems in appropriately dividing index registers. There are
various corner cases left here such as widening arithmetic
operations (widening SIMD IR ops are currently not compatible) and
vstart CSR register. When using fixed-length IR ops to comprise a
vector instruction, we will inevitably tell each IR op which
position encoded in vstart you can start to process the data. We can
use vstart as a normal guest state virtual register to calculate
each op's start position as a guard IRExpr or obtain the value of
vstart like what we do in LMUL/SEW. Nevertheless, it is non-trivial
to decompose a vector instruction concisely.
In short, both 2.1 and 2.2 confront a dilemma in reducing engineering
efforts of refactoring Valgrind elegantly as well as implementing the
vector instruction set efficiently. Same obstacles exist in ARM SVE as
they are scalable vector instructions and flexible in many ways.
The final solution is the dirty helper. It is undoubtedly practical and
requires possibly the least engineering efforts in dealing with so many
details in Valgrind. In this design, each instruction is completed using
an inline assembly running the same instruction on the host. Moreover,
tool instrumentation already handles IRDirty except that new fields
should be added in _IRDirty struct to indicate strided/indexed/masked
memory accesses and arithmetic operations.
* *pros:*it supports all instructions without bothering to build
complicated IR expressions and statements. It executes vector
instructions using host CPU to get acceleration to some extent.
Besides, we do not need to add VEX backend to translate new IRs to
vector instructions.
* *cons:*the dirty helper always keeps its operations in a black box
such that tools can never see what happens in a dirty helper. Like
memcheck, the bit precision merit is missing once it meets a dirty
helper as the V-bit propagation chain adopts a pretty coarse
determination strategy. On the other hand, it is also not an elegant
way to implement the entire ISA extension in dirty helpers.
In summary, it is far to reach a truly applicable solution in adding
vector extensions in Valgrind. We need to do detailed and comprehensive
estimations on different vector instruction categories.
Any feedback is welcome in github [3] also.
[1] https://github.com/riscv/riscv-v-spec
[2]
https://community.arm.com/arm-research/b/articles/posts/the-arm-scalable-vector-extension-sve
[3] https://github.com/petrpavlu/valgrind-riscv64/issues/17
Thanks.
Jojo
|
|
From: Nicholas N. <n.n...@gm...> - 2023-04-20 23:06:24
|
On Fri, 21 Apr 2023 at 07:06, Bart Van Assche <bva...@ac...> wrote: > No matter how > much time is spent on tuning the .clang-format file, there will always > be code for which the formatting is made worse by clang-format than the > existing code. > It's true that there are rare cases where an auto-formatter does a bad job, such as code in tabular form. Fortunately there's an easy workaround for that too: you just put `// clang-format off` at the start of the block and `// clang-format on` at the end of the block. Nick |
|
From: Bart V. A. <bva...@ac...> - 2023-04-20 21:06:51
|
On 4/20/23 13:51, Nicholas Nethercote wrote: > On Fri, 21 Apr 2023 at 06:02, Mark Wielaard <ma...@kl... > <mailto:ma...@kl...>> wrote: > I am not a fan, but also not dead against. > > Have you ever worked on a project that uses auto-formatting? Skepticism > followed by enthusiasm is common. Paul, Julian, and I all have used it > on other codebases and are now advocates. I'm using it for Cachegrind's > Python code right now. It makes life easier. I have worked on large projects that use auto-formatting. Despite this I'm strongly opposed against reformatting existing code. No matter how much time is spent on tuning the .clang-format file, there will always be code for which the formatting is made worse by clang-format than the existing code. Bart. |
|
From: Nicholas N. <n.n...@gm...> - 2023-04-20 20:52:09
|
On Fri, 21 Apr 2023 at 06:02, Mark Wielaard <ma...@kl...> wrote: > > Sure you can work around it, but I don't think that is a great > solution. It requires everyone to make some local changes. > You can send up a .gitconfig for the project, so it'll work automatically for everyone. > I am not a fan, but also not dead against. > Have you ever worked on a project that uses auto-formatting? Skepticism followed by enthusiasm is common. Paul, Julian, and I all have used it on other codebases and are now advocates. I'm using it for Cachegrind's Python code right now. It makes life easier. Personally I am happy with emacs M-x indent-region on the code I edit. > There is a .dir-locals.el in git which catches some (but certainly not > all) formatting things. > What about people who don't use emacs? Nick |
|
From: Paul F. <pa...@so...> - 2023-04-20 20:40:36
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=a2af9adec4536c3ce95d4ea5ddf15d00d7c55c6c commit a2af9adec4536c3ce95d4ea5ddf15d00d7c55c6c Author: Paul Floyd <pj...@wa...> Date: Thu Apr 20 22:11:31 2023 +0200 Bug 397083 - Likely false positive "uninitialised value(s)" for __wmemchr_avx2 and __wmemcmp_avx2_movbe Diff: --- .gitignore | 1 + NEWS | 1 + memcheck/tests/Makefile.am | 2 ++ memcheck/tests/wmemcmp.c | 17 +++++++++++++++++ memcheck/tests/wmemcmp.stderr.exp | 0 memcheck/tests/wmemcmp.vgtest | 2 ++ shared/vg_replace_strmem.c | 21 +++++++++++++++++++++ 7 files changed, 44 insertions(+) diff --git a/.gitignore b/.gitignore index 6622e7c59e..9e26e2fbf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1004,6 +1004,7 @@ /memcheck/tests/wcs /memcheck/tests/weirdioctl /memcheck/tests/with space +/memcheck/tests/wmemcmp /memcheck/tests/wrap1 /memcheck/tests/wrap2 /memcheck/tests/wrap3 diff --git a/NEWS b/NEWS index 4ba0c31709..57e39f42a3 100644 --- a/NEWS +++ b/NEWS @@ -126,6 +126,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 351857 confusing error message about valid command line option 374596 inconsistent RDTSCP support on x86_64 392331 Spurious lock not held error from inside pthread_cond_timedwait +397083 Likely false positive "uninitialised value(s)" for __wmemchr_avx2 and __wmemcmp_avx2_movbe 400793 pthread_rwlock_timedwrlock false positive 419054 Unhandled syscall getcpu on arm32 433873 openat2 syscall unimplemented on Linux diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index b4d80f837a..faf9130bcd 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -376,6 +376,7 @@ EXTRA_DIST = \ vcpu_fnfns.stdout.exp-darwin vcpu_fnfns.stdout.exp-solaris \ vcpu_fnfns.stderr.exp vcpu_fnfns.vgtest \ wcs.vgtest wcs.stderr.exp wcs.stdout.exp \ + wmemcmp.vgtest wmemcmp.stderr.exp \ wrap1.vgtest wrap1.stdout.exp wrap1.stderr.exp \ wrap2.vgtest wrap2.stdout.exp wrap2.stderr.exp \ wrap3.vgtest wrap3.stdout.exp wrap3.stderr.exp \ @@ -478,6 +479,7 @@ check_PROGRAMS = \ vcpu_fbench vcpu_fnfns \ wcs \ xml1 \ + wmemcmp \ wrap1 wrap2 wrap3 wrap4 wrap5 wrap6 wrap7 wrap7so.so wrap8 \ wrapmalloc wrapmallocso.so wrapmallocstatic \ writev1 diff --git a/memcheck/tests/wmemcmp.c b/memcheck/tests/wmemcmp.c new file mode 100644 index 0000000000..d737620094 --- /dev/null +++ b/memcheck/tests/wmemcmp.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <wchar.h> + +int main () +{ + wchar_t *s = (wchar_t *) malloc (8 * sizeof (wchar_t)); + s[0] = '-'; + s[1] = 'N'; + s[2] = 'A'; + s[3] = 'N'; + s[4] = ' '; + s[5] = '3'; + s[6] = '3'; + s[7] = '\0'; + return wmemcmp (s + 1, L"NAN", 3) == 0; +} + diff --git a/memcheck/tests/wmemcmp.stderr.exp b/memcheck/tests/wmemcmp.stderr.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/memcheck/tests/wmemcmp.vgtest b/memcheck/tests/wmemcmp.vgtest new file mode 100644 index 0000000000..637a2335c0 --- /dev/null +++ b/memcheck/tests/wmemcmp.vgtest @@ -0,0 +1,2 @@ +prog: wmemcmp +vgopts: -q diff --git a/shared/vg_replace_strmem.c b/shared/vg_replace_strmem.c index 30065d537a..b32f13f76d 100644 --- a/shared/vg_replace_strmem.c +++ b/shared/vg_replace_strmem.c @@ -104,6 +104,7 @@ 20440 WCSNLEN 20450 WSTRNCMP 20460 MEMMEM + 20470 WMEMCMP */ #if defined(VGO_solaris) @@ -2262,6 +2263,26 @@ static inline void my_exit ( int x ) #if defined(VGO_freebsd) WMEMCHR(VG_Z_LIBC_SONAME, wmemchr) #endif + + +#define WMEMCMP(soname, fnname) \ + int VG_REPLACE_FUNCTION_EZU(20470,soname,fnname) \ + ( const Int *b1, const Int *b2, SizeT n ); \ + int VG_REPLACE_FUNCTION_EZU(20470,soname,fnname) \ + ( const Int *b1, const Int *b2, SizeT n ) \ + { \ + for (SizeT i = 0U; i < n; ++i) { \ + if (b1[i] != b2[i]) \ + return b1[i] > b2[i] ? 1 : -1; \ + } \ + return 0; \ + } + +#if defined(VGO_linux) + WMEMCMP(VG_Z_LIBC_SONAME, wmemcmp) +#endif + + /*------------------------------------------------------------*/ /*--- Improve definedness checking of process environment ---*/ /*------------------------------------------------------------*/ |
|
From: Bart V. A. <bva...@ac...> - 2023-04-20 20:23:04
|
On 4/17/23 20:30, Nicholas Nethercote wrote: > Is there any appetite for clang-formatting Valgrind's code? Why to reformat the entire code base? Auto-formatting can be used without reformatting the entire code base. This is how I reformat Linux kernel and Android patches before I publish these: git clang-format HEAD^ git diff # to review the changes git commit -a --amend --no-edit # to keep the changes git reset --hard # to discard the changes Plugins are available for many editors (including Emacs and vi) that support clang-format. Bart. |
|
From: Mark W. <ma...@kl...> - 2023-04-20 20:14:08
|
Hi Philippe,
On Tue, Apr 18, 2023 at 01:02:44PM +0200, Philippe Waroquiers via Valgrind-developers wrote:
> The nightly build script produces a mail that indicates if there is
> a difference between the results of one day ago and the new results.
>
> When no difference, the mail subject contains 'unchanged'.
>
> It looks like the 'unchanged' logic is broken due to the addition of
> the time taken to run tests.
>
> It would be good to keep the 'unchanged' marker only depending on
> the functional results.
Sorry, I hadn't realized that would change the diff emails.
Paul has added a workaround:
commit 04054f36be59eeb337f23932424a7e70bbfeba70
Author: Paul Floyd <pj...@wa...>
Date: Tue Apr 18 21:18:12 2023 +0200
regtest: try to make the nightly script independent of test times
Which adds a sed filter that deletes the timing info from the log
files.
It does have to be installed on some of the nightly builders though.
Cheers,
Mark
|
|
From: Mark W. <ma...@kl...> - 2023-04-20 20:02:59
|
Hi, On Tue, Apr 18, 2023 at 03:05:28PM +1000, Nicholas Nethercote wrote: > On Tue, 18 Apr 2023 at 13:41, Eyal Soha <eya...@gm...> wrote: > > > The problem with doing this is that it really messes with the git blame, > > introducing a lot of changes! > > That's always the first objection that is raised. Turns out there's a good > solution > <https://medium.com/codex/how-to-introduce-a-code-formatter-without-messing-up-git-history-4a16bd074c10> > . (Note that article requires javascript to turn on, or you won't be able to read more than the first paragraph.) Sure you can work around it, but I don't think that is a great solution. It requires everyone to make some local changes. > > If you do this, you should probably add some sort of formatting check to a > > CI process somewhere, otherwise your work will get stale and you'll just be > > doing the clang-format again in a year from now. > > > > Yes. > > > Good luck to you trying to get everyone to agree on a format! Ha! > > > > It requires negotiation, but it's doable. > > Remember, all of this was done successfully for Firefox, which is a much > bigger and gnarlier codebase than Valgrind. I am not a fan, but also not dead against. Personally I am happy with emacs M-x indent-region on the code I edit. There is a .dir-locals.el in git which catches some (but certainly not all) formatting things. I played a bit with the .clang-format file. I am not sure I like using clang-format to reformat everything, it seems a little arbitrary. But if we could make the git-clang-format thing working then using that for formatting patches/regions that you changed might be OK. Cheers, Mark |
|
From: Mark W. <ma...@so...> - 2023-04-20 19:18:30
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=e1684bc775c2b253134354f1e903cab48df3758e commit e1684bc775c2b253134354f1e903cab48df3758e Author: Mark Wielaard <ma...@kl...> Date: Thu Apr 20 21:17:46 2023 +0200 Add 436413 Warn about realloc of size zero to NEWS Diff: --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 203b422784..4ba0c31709 100644 --- a/NEWS +++ b/NEWS @@ -131,6 +131,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 433873 openat2 syscall unimplemented on Linux 434057 Add stdio mode to valgrind's gdbserver 435441 valgrind fails to interpose malloc on musl 1.2.2 due to weak symbol name and no libc soname +436413 Warn about realloc of size zero 439685 compiler warning in callgrind/main.c 444110 priv/guest_ppc_toIR.c:36198:31: warning: duplicated 'if' condition. 444487 hginfo test detects an extra lock inside data symbol "_rtld_local" |
|
From: Mark W. <ma...@kl...> - 2023-04-20 13:19:35
|
Hi Sasha,
On Thu, 2023-04-20 at 15:01 +0200, Mark Wielaard wrote:
> Looks like this was in response to Philippe's review. Thanks.
> I added one more comment at the top describing the three usages of
> vgdb. And fixed up a few places where tabs were used for indentation
> (we are not very consistent in that either, after the release we'll
> look into adopting something like clang-format so you don't have to do
> all this by hand). And a missing newline in coregrind/m_main.c to make
> none/tests/cmdline2 pass.
>
> Pushed with the following commit message to show what was changed:
And then I messed up and didn't include those small fixups I described,
sorry. Pushed a followup commit:
Author: Mark Wielaard <ma...@kl...>
Date: Thu Apr 20 15:04:03 2023 +0200
vgdb --multi: fix various typos, indentation and such (followup)
commit 56ccb1e36c4722b56e3e602b986bc45025cb685d missed a few small
fixlets:
- one more comment at the top describing the three usages of vgdb.
- fixed up a few places where tabs were used for indentation (we are
not very consistent in that either, after the release we'll look
into adopting something like clang-format so you don't have to do
all this by hand).
- Add a missing newline in coregrind/m_main.c to make
none/tests/cmdline2 pass.
Sorry for messing this up. One day git and I will become friends...
Cheers,
Mark
|
|
From: Mark W. <ma...@so...> - 2023-04-20 13:18:30
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=9fcac92ab371d210dc54f49a80146be9d0b0433a commit 9fcac92ab371d210dc54f49a80146be9d0b0433a Author: Mark Wielaard <ma...@kl...> Date: Thu Apr 20 15:04:03 2023 +0200 vgdb --multi: fix various typos, indentation and such (followup) commit 56ccb1e36c4722b56e3e602b986bc45025cb685d missed a few small fixlets: - one more comment at the top describing the three usages of vgdb. - fixed up a few places where tabs were used for indentation (we are not very consistent in that either, after the release we'll look into adopting something like clang-format so you don't have to do all this by hand). - Add a missing newline in coregrind/m_main.c to make none/tests/cmdline2 pass. Diff: --- coregrind/m_main.c | 2 +- coregrind/vgdb.c | 515 +++++++++++++++++++++++++++-------------------------- 2 files changed, 262 insertions(+), 255 deletions(-) diff --git a/coregrind/m_main.c b/coregrind/m_main.c index e19796327d..a857e5afeb 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -278,7 +278,7 @@ static void usage_NORETURN ( int need_help ) " --sym-offsets=yes|no show syms in form 'name+offset'? [no]\n" " --progress-interval=<number> report progress every <number>\n" " CPU seconds [0, meaning disabled]\n" -" --command-line-only=no|yes only use command line options [no]\n" +" --command-line-only=no|yes only use command line options [no]\n\n" " Vex options for all Valgrind tools:\n" " --vex-iropt-verbosity=<0..9> [0]\n" " --vex-iropt-level=<0..2> [2]\n" diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c index a3c5f9d88f..6e5e819563 100644 --- a/coregrind/vgdb.c +++ b/coregrind/vgdb.c @@ -49,9 +49,10 @@ #include <sys/time.h> #include <sys/wait.h> -/* vgdb has two usages: +/* vgdb has three usages: 1. relay application between gdb and the gdbserver embedded in valgrind. 2. standalone to send monitor commands to a running valgrind-ified process + 3. multi mode where vgdb uses the GDB extended remote protocol. It is made of a main program which reads arguments. If no arguments are given or only --pid and --vgdb-prefix, then usage 1 is @@ -67,6 +68,12 @@ As a standalone utility, vgdb builds command packets to write to valgrind, sends it and reads the reply. The same two threads are used to write/read. Once all the commands are sent and their replies received, vgdb will exit. + + When --multi is given vgdb communicates with GDB through the extended remote + protocol and will launch valgrind whenever GDB sends the vRun packet, after + which it will function in the first mode, relaying packets between GDB and + the gdbserver embedded in valgrind till that valgrind quits. vgdb will stay + connected to GDB. */ int debuglevel; @@ -710,7 +717,7 @@ getpkt(char *buf, int fromfd, int ackfd) c2 = fromhex(readchar (fromfd)); if (csum == (c1 << 4) + c2) - break; + break; TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", (c1 << 4) + c2, csum, buf); @@ -1003,14 +1010,14 @@ send_packet_start: if (!noackmode) { // Look for '+' or '-'. // We must wait for "+" if !noackmode. - do { - ret = read_one_char(&c); - if (ret <= 0) - return False; - // And if in !noackmode if we get "-" we should resent the packet. - if (c == '-') - goto send_packet_start; - } while (c != '+'); + do { + ret = read_one_char(&c); + if (ret <= 0) + return False; + // And if in !noackmode if we get "-" we should resent the packet. + if (c == '-') + goto send_packet_start; + } while (c != '+'); DEBUG(1, "sent packet to gdb got: %c\n",c); } return True; @@ -1036,36 +1043,36 @@ receive_packet_start: // Found start of packet ('$') while (bufcnt < (PBUFSIZ+1)) { - ret = read_one_char(&c); - if (ret <= 0) - return ret; - if (c == '#') { - if ((ret = read_one_char(&c1)) <= 0 - || (ret = read_one_char(&c2)) <= 0) { - return ret; - } - c1 = fromhex(c1); - c2 = fromhex(c2); - break; - } - buf[bufcnt] = c; - csum += buf[bufcnt]; - bufcnt++; + ret = read_one_char(&c); + if (ret <= 0) + return ret; + if (c == '#') { + if ((ret = read_one_char(&c1)) <= 0 + || (ret = read_one_char(&c2)) <= 0) { + return ret; + } + c1 = fromhex(c1); + c2 = fromhex(c2); + break; + } + buf[bufcnt] = c; + csum += buf[bufcnt]; + bufcnt++; } // Packet complete, add terminator. buf[bufcnt] ='\0'; if (!(csum == (c1 << 4) + c2)) { - TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", - (c1 << 4) + c2, csum, buf); - if (!noackmode) - if (!write_to_gdb ("-", 1)) - return -1; - /* Try again, gdb should resend the packet. */ - bufcnt = 0; - csum = 0; - goto receive_packet_start; + TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + if (!noackmode) + if (!write_to_gdb ("-", 1)) + return -1; + /* Try again, gdb should resend the packet. */ + bufcnt = 0; + csum = 0; + goto receive_packet_start; } if (!noackmode) @@ -1315,68 +1322,68 @@ void do_multi_mode(void) #define QSETWORKINGDIR "QSetWorkingDir" #define QTSTATUS "qTStatus" - if (strncmp(QSUPPORTED, buf, strlen(QSUPPORTED)) == 0) { - DEBUG(1, "CASE %s\n", QSUPPORTED); - // And here is our reply. - // XXX error handling? We don't check the arguments. - char *reply; - strcpy(q_buf, buf); - // Keep this in sync with coregrind/m_gdbserver/server.c - asprintf (&reply, - "PacketSize=%x;" - "QStartNoAckMode+;" - "QPassSignals+;" - "QCatchSyscalls+;" - /* Just report support always. */ - "qXfer:auxv:read+;" - /* We'll force --vgdb-shadow-registers=yes */ - "qXfer:features:read+;" - "qXfer:exec-file:read+;" - "qXfer:siginfo:read+;" - /* Some extra's vgdb support before valgrind starts up. */ - "QEnvironmentHexEncoded+;" - "QEnvironmentReset+;" - "QEnvironmentUnset+;" - "QSetWorkingDir+", (UInt)PBUFSIZ - 1); - send_packet(reply, noackmode); - free (reply); - } - else if (strncmp(STARTNOACKMODE, buf, strlen(STARTNOACKMODE)) == 0) { - // We have to ack this one - send_packet("OK", 0); - noackmode = 1; - } - else if (buf[0] == '!') { - send_packet("OK", noackmode); - } - else if (buf[0] == '?') { - send_packet("W00", noackmode); - } - else if (strncmp("H", buf, strlen("H")) == 0) { - // Set thread packet, but we are not running yet. - send_packet("E01", noackmode); - } - else if (strncmp("vMustReplyEmpty", buf, strlen("vMustReplyEmpty")) == 0) { - send_packet ("", noackmode); - } - else if (strncmp(QRCMD, buf, strlen(QRCMD)) == 0) { - send_packet ("No running target, monitor commands not available yet.", noackmode); + if (strncmp(QSUPPORTED, buf, strlen(QSUPPORTED)) == 0) { + DEBUG(1, "CASE %s\n", QSUPPORTED); + // And here is our reply. + // XXX error handling? We don't check the arguments. + char *reply; + strcpy(q_buf, buf); + // Keep this in sync with coregrind/m_gdbserver/server.c + asprintf (&reply, + "PacketSize=%x;" + "QStartNoAckMode+;" + "QPassSignals+;" + "QCatchSyscalls+;" + /* Just report support always. */ + "qXfer:auxv:read+;" + /* We'll force --vgdb-shadow-registers=yes */ + "qXfer:features:read+;" + "qXfer:exec-file:read+;" + "qXfer:siginfo:read+;" + /* Some extra's vgdb support before valgrind starts up. */ + "QEnvironmentHexEncoded+;" + "QEnvironmentReset+;" + "QEnvironmentUnset+;" + "QSetWorkingDir+", (UInt)PBUFSIZ - 1); + send_packet(reply, noackmode); + free (reply); + } + else if (strncmp(STARTNOACKMODE, buf, strlen(STARTNOACKMODE)) == 0) { + // We have to ack this one + send_packet("OK", 0); + noackmode = 1; + } + else if (buf[0] == '!') { + send_packet("OK", noackmode); + } + else if (buf[0] == '?') { + send_packet("W00", noackmode); + } + else if (strncmp("H", buf, strlen("H")) == 0) { + // Set thread packet, but we are not running yet. + send_packet("E01", noackmode); + } + else if (strncmp("vMustReplyEmpty", buf, strlen("vMustReplyEmpty")) == 0) { + send_packet ("", noackmode); + } + else if (strncmp(QRCMD, buf, strlen(QRCMD)) == 0) { + send_packet ("No running target, monitor commands not available yet.", noackmode); - char *decoded_string = decode_hexstring (buf, strlen (QRCMD) + 1, 0); - DEBUG(1, "qRcmd decoded: %s\n", decoded_string); - free (decoded_string); - } - else if (strncmp(VRUN, buf, strlen(VRUN)) == 0) { + char *decoded_string = decode_hexstring (buf, strlen (QRCMD) + 1, 0); + DEBUG(1, "qRcmd decoded: %s\n", decoded_string); + free (decoded_string); + } + else if (strncmp(VRUN, buf, strlen(VRUN)) == 0) { // vRun;filename[;argument]* // vRun, filename and arguments are split on ';', // no ';' at the end. // If there are no arguments count is one (just the filename). // Otherwise it is the number of arguments plus one (the filename). // The filename must be there and starts after the first ';'. - // TODO: Handle vRun;[;argument]* - // https://www.sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets - // If filename is an empty string, the stub may use a default program - // (e.g. the last program run). + // TODO: Handle vRun;[;argument]* + // https://www.sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets + // If filename is an empty string, the stub may use a default program + // (e.g. the last program run). size_t count = count_delims(';', buf); size_t *len = vmalloc(count * sizeof(count)); const char *delim = ";"; @@ -1386,186 +1393,186 @@ void do_multi_mode(void) // Count the lenghts of each substring, init to -1 to compensate for // each substring starting with a delim char. for (int i = 0; i < count; i++) - len[i] = -1; + len[i] = -1; count_len(';', buf, len); if (next_str) { - DEBUG(1, "vRun: next_str %s\n", next_str); - for (int i = 0; i < count; i++) { - /* Handle the case when the arguments - * was specified to gdb's run command - * but no remote exec-file was set, - * so the first vRun argument is missing. - * For example vRun;;6c. */ - if (*next_str == *delim) { - next_str++; - /* empty string that can be freed. */ - decoded_string[i] = strdup(""); - } - else { - decoded_string[i] = decode_hexstring (next_str, 0, len[i]); - if (i < count - 1) - next_str = next_delim_string(next_str, *delim); - } - DEBUG(1, "vRun decoded: %s, next_str %s, len[%d] %d\n", - decoded_string[i], next_str, i, len[i]); - } - - /* If we didn't get any arguments or the filename is an empty - string, valgrind won't know which program to run. */ - DEBUG (1, "count: %d, len[0]: %d\n", count, len[0]); - if (! count || len[0] == 0) { - free(len); - for (int i = 0; i < count; i++) - free (decoded_string[i]); - free (decoded_string); - send_packet ("E01", noackmode); - continue; - } - - /* We have collected the decoded strings so we can use them to - launch valgrind with the correct arguments... We then use the - valgrind pid to start relaying packets. */ - pid_t valgrind_pid = -1; - int res = fork_and_exec_valgrind (count, - decoded_string, - working_dir, - &valgrind_pid); - - if (res == 0) { - // Lets report we Stopped with SIGTRAP (05). - send_packet ("S05", noackmode); - prepare_fifos_and_shared_mem(valgrind_pid); - DEBUG(1, "from_gdb_to_pid %s, to_gdb_from_pid %s\n", - from_gdb_to_pid, to_gdb_from_pid); - // gdb_relay is an endless loop till valgrind quits. - shutting_down = False; - - gdb_relay (valgrind_pid, 1, q_buf); - cleanup_fifos_and_shared_mem(); - DEBUG(1, "valgrind relay done\n"); - int status; - pid_t p = waitpid (valgrind_pid, &status, 0); - DEBUG(2, "waitpid: %d\n", (int) p); - if (p == -1) - DEBUG(1, "waitpid error %s\n", strerror (errno)); - else { - if (WIFEXITED(status)) - DEBUG(1, "valgrind exited with %d\n", - WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - DEBUG(1, "valgrind kill by signal %d\n", - WTERMSIG(status)); - else - DEBUG(1, "valgrind unexpectedly stopped or continued"); - } - } else { - send_packet ("E01", noackmode); - DEBUG(1, "OOPS! couldn't launch valgrind %s\n", - strerror (res)); - } - - free(len); - for (int i = 0; i < count; i++) + DEBUG(1, "vRun: next_str %s\n", next_str); + for (int i = 0; i < count; i++) { + /* Handle the case when the arguments + * was specified to gdb's run command + * but no remote exec-file was set, + * so the first vRun argument is missing. + * For example vRun;;6c. */ + if (*next_str == *delim) { + next_str++; + /* empty string that can be freed. */ + decoded_string[i] = strdup(""); + } + else { + decoded_string[i] = decode_hexstring (next_str, 0, len[i]); + if (i < count - 1) + next_str = next_delim_string(next_str, *delim); + } + DEBUG(1, "vRun decoded: %s, next_str %s, len[%d] %d\n", + decoded_string[i], next_str, i, len[i]); + } + + /* If we didn't get any arguments or the filename is an empty + string, valgrind won't know which program to run. */ + DEBUG (1, "count: %d, len[0]: %d\n", count, len[0]); + if (! count || len[0] == 0) { + free(len); + for (int i = 0; i < count; i++) + free (decoded_string[i]); + free (decoded_string); + send_packet ("E01", noackmode); + continue; + } + + /* We have collected the decoded strings so we can use them to + launch valgrind with the correct arguments... We then use the + valgrind pid to start relaying packets. */ + pid_t valgrind_pid = -1; + int res = fork_and_exec_valgrind (count, + decoded_string, + working_dir, + &valgrind_pid); + + if (res == 0) { + // Lets report we Stopped with SIGTRAP (05). + send_packet ("S05", noackmode); + prepare_fifos_and_shared_mem(valgrind_pid); + DEBUG(1, "from_gdb_to_pid %s, to_gdb_from_pid %s\n", + from_gdb_to_pid, to_gdb_from_pid); + // gdb_relay is an endless loop till valgrind quits. + shutting_down = False; + + gdb_relay (valgrind_pid, 1, q_buf); + cleanup_fifos_and_shared_mem(); + DEBUG(1, "valgrind relay done\n"); + int status; + pid_t p = waitpid (valgrind_pid, &status, 0); + DEBUG(2, "waitpid: %d\n", (int) p); + if (p == -1) + DEBUG(1, "waitpid error %s\n", strerror (errno)); + else { + if (WIFEXITED(status)) + DEBUG(1, "valgrind exited with %d\n", + WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + DEBUG(1, "valgrind kill by signal %d\n", + WTERMSIG(status)); + else + DEBUG(1, "valgrind unexpectedly stopped or continued"); + } + } else { + send_packet ("E01", noackmode); + DEBUG(1, "OOPS! couldn't launch valgrind %s\n", + strerror (res)); + } + + free(len); + for (int i = 0; i < count; i++) free (decoded_string[i]); - free (decoded_string); + free (decoded_string); } else { - free(len); - send_packet ("E01", noackmode); - DEBUG(1, "vRun decoding error: no next_string!\n"); - continue; + free(len); + send_packet ("E01", noackmode); + DEBUG(1, "vRun decoding error: no next_string!\n"); + continue; } - } else if (strncmp(QATTACHED, buf, strlen(QATTACHED)) == 0) { - send_packet ("1", noackmode); - DEBUG(1, "qAttached sent: '1'\n"); - const char *next_str = next_delim_string(buf, ':'); - if (next_str) { + } else if (strncmp(QATTACHED, buf, strlen(QATTACHED)) == 0) { + send_packet ("1", noackmode); + DEBUG(1, "qAttached sent: '1'\n"); + const char *next_str = next_delim_string(buf, ':'); + if (next_str) { char *decoded_string = decode_hexstring (next_str, 0, 0); DEBUG(1, "qAttached decoded: %s, next_str %s\n", decoded_string, next_str); free (decoded_string); - } else { + } else { DEBUG(1, "qAttached decoding error: strdup of %s failed!\n", buf); continue; - } - } /* Reset the state of environment variables in the remote target - before starting the inferior. In this context, reset means - unsetting all environment variables that were previously set - by the user (i.e., were not initially present in the environment). */ - else if (strncmp(QENVIRONMENTRESET, buf, - strlen(QENVIRONMENTRESET)) == 0) { - send_packet ("OK", noackmode); - // TODO clear all environment strings. We're not using - // environment strings now. But we should. - } else if (strncmp(QENVIRONMENTHEXENCODED, buf, - strlen(QENVIRONMENTHEXENCODED)) == 0) { - send_packet ("OK", noackmode); - if (!split_hexdecode(buf, QENVIRONMENTHEXENCODED, ":", &string)) - break; - // TODO Collect all environment strings and add them to environ - // before launching valgrind. - free (string); - string = NULL; - } else if (strncmp(QENVIRONMENTUNSET, buf, - strlen(QENVIRONMENTUNSET)) == 0) { - send_packet ("OK", noackmode); - if (!split_hexdecode(buf, QENVIRONMENTUNSET, ":", &string)) - break; - // TODO Remove this environment string from the collection. - free (string); - string = NULL; - } else if (strncmp(QSETWORKINGDIR, buf, - strlen(QSETWORKINGDIR)) == 0) { - // Silly, but we can only reply OK, even if the working directory is - // bad. Errors will be reported when we try to execute the actual - // process. - send_packet ("OK", noackmode); - // Free any previously set working_dir - free (working_dir); - working_dir = NULL; - if (!split_hexdecode(buf, QSETWORKINGDIR, ":", &working_dir)) { - continue; // We cannot report the error to gdb... - } - DEBUG(1, "set working dir to: %s\n", working_dir); - } else if (strncmp(XFER, buf, strlen(XFER)) == 0) { - char *buf_dup = strdup(buf); - DEBUG(1, "strdup: buf_dup %s\n", buf_dup); - if (buf_dup) { - const char *delim = ":"; - size_t count = count_delims(delim[0], buf); - if (count < 4) { - strsep(&buf_dup, delim); - strsep(&buf_dup, delim); - strsep(&buf_dup, delim); - char *decoded_string = decode_hexstring (buf_dup, 0, 0); - DEBUG(1, "qXfer decoded: %s, buf_dup %s\n", decoded_string, buf_dup); - free (decoded_string); - } - free (buf_dup); + } + } /* Reset the state of environment variables in the remote target + before starting the inferior. In this context, reset means + unsetting all environment variables that were previously set + by the user (i.e., were not initially present in the environment). */ + else if (strncmp(QENVIRONMENTRESET, buf, + strlen(QENVIRONMENTRESET)) == 0) { + send_packet ("OK", noackmode); + // TODO clear all environment strings. We're not using + // environment strings now. But we should. + } else if (strncmp(QENVIRONMENTHEXENCODED, buf, + strlen(QENVIRONMENTHEXENCODED)) == 0) { + send_packet ("OK", noackmode); + if (!split_hexdecode(buf, QENVIRONMENTHEXENCODED, ":", &string)) + break; + // TODO Collect all environment strings and add them to environ + // before launching valgrind. + free (string); + string = NULL; + } else if (strncmp(QENVIRONMENTUNSET, buf, + strlen(QENVIRONMENTUNSET)) == 0) { + send_packet ("OK", noackmode); + if (!split_hexdecode(buf, QENVIRONMENTUNSET, ":", &string)) + break; + // TODO Remove this environment string from the collection. + free (string); + string = NULL; + } else if (strncmp(QSETWORKINGDIR, buf, + strlen(QSETWORKINGDIR)) == 0) { + // Silly, but we can only reply OK, even if the working directory is + // bad. Errors will be reported when we try to execute the actual + // process. + send_packet ("OK", noackmode); + // Free any previously set working_dir + free (working_dir); + working_dir = NULL; + if (!split_hexdecode(buf, QSETWORKINGDIR, ":", &working_dir)) { + continue; // We cannot report the error to gdb... + } + DEBUG(1, "set working dir to: %s\n", working_dir); + } else if (strncmp(XFER, buf, strlen(XFER)) == 0) { + char *buf_dup = strdup(buf); + DEBUG(1, "strdup: buf_dup %s\n", buf_dup); + if (buf_dup) { + const char *delim = ":"; + size_t count = count_delims(delim[0], buf); + if (count < 4) { + strsep(&buf_dup, delim); + strsep(&buf_dup, delim); + strsep(&buf_dup, delim); + char *decoded_string = decode_hexstring (buf_dup, 0, 0); + DEBUG(1, "qXfer decoded: %s, buf_dup %s\n", decoded_string, buf_dup); + free (decoded_string); + } + free (buf_dup); } else { - DEBUG(1, "qXfer decoding error: strdup of %s failed!\n", buf); - free (buf_dup); - continue; + DEBUG(1, "qXfer decoding error: strdup of %s failed!\n", buf); + free (buf_dup); + continue; } // Whether we could decode it or not, we cannot handle it now. We // need valgrind gdbserver to properly reply. So error out here. send_packet ("E00", noackmode); - } else if (strncmp(QTSTATUS, buf, strlen(QTSTATUS)) == 0) { - // We don't support trace experiments - DEBUG(1, "Got QTSTATUS\n"); - send_packet ("", noackmode); - } else if (strcmp("qfThreadInfo", buf) == 0) { - DEBUG(1, "Got qfThreadInfo\n"); - /* There are no threads yet, reply 'l' end of list. */ - send_packet ("l", noackmode); - } else if (buf[0] != '\0') { - // We didn't understand. - DEBUG(1, "Unknown packet received: '%s'\n", buf); - bad_unknown_packets++; - if (bad_unknown_packets > 10) { - DEBUG(1, "Too many bad/unknown packets received\n"); - break; - } - send_packet ("", noackmode); - } + } else if (strncmp(QTSTATUS, buf, strlen(QTSTATUS)) == 0) { + // We don't support trace experiments + DEBUG(1, "Got QTSTATUS\n"); + send_packet ("", noackmode); + } else if (strcmp("qfThreadInfo", buf) == 0) { + DEBUG(1, "Got qfThreadInfo\n"); + /* There are no threads yet, reply 'l' end of list. */ + send_packet ("l", noackmode); + } else if (buf[0] != '\0') { + // We didn't understand. + DEBUG(1, "Unknown packet received: '%s'\n", buf); + bad_unknown_packets++; + if (bad_unknown_packets > 10) { + DEBUG(1, "Too many bad/unknown packets received\n"); + break; + } + send_packet ("", noackmode); + } } DEBUG(1, "done doing multi stuff...\n"); free(working_dir); |
|
From: Mark W. <ma...@kl...> - 2023-04-20 13:02:11
|
Hi Sasha,
Looks like this was in response to Philippe's review. Thanks.
I added one more comment at the top describing the three usages of
vgdb. And fixed up a few places where tabs were used for indentation
(we are not very consistent in that either, after the release we'll
look into adopting something like clang-format so you don't have to do
all this by hand). And a missing newline in coregrind/m_main.c to make
none/tests/cmdline2 pass.
Pushed with the following commit message to show what was changed:
commit a32e26dd072a82aacafcdd22bd7c94c7b4d2afcc
Author: Alexandra Hájková <aha...@re...>
Date: Thu Apr 20 14:17:29 2023 +0200
vgdb --multi: fix various typos, indentation and such
Remove --launched-with-multi from --help-debug output since it is not
a real user option. Do add a comment in m_main.c explaining the
internal usage.
Add a top-level comment describing the three usages of vgdb.
Fix comment description of decode_hexstring, create_packet,
split_hexdecode.
Consistently use 3 space indention in send_packet and receive_packet
and next_delim_string and split_hexdecode, count_delims,
do_multi_mode.
Fix return type of count_delims to size_t.
Add a note in coregrind/m_gdbserver/server.c to sync qSupported
replies with coregrind/vgdb.c.
Use vgdb (all lowercase) and GDB (all caps) consistently in the
manual.
Thanks,
Mark
|
|
From: Mark W. <ma...@so...> - 2023-04-20 13:00:25
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=56ccb1e36c4722b56e3e602b986bc45025cb685d commit 56ccb1e36c4722b56e3e602b986bc45025cb685d Author: Alexandra Hájková <aha...@re...> Date: Thu Apr 20 14:17:29 2023 +0200 vgdb --multi: fix various typos, indentation and such Remove --launched-with-multi from --help-debug output since it is not a real user option. Do add a comment in m_main.c explaining the internal usage. Add a top-level comment describing the three usages of vgdb. Fix comment description of decode_hexstring, create_packet, split_hexdecode. Consistently use 3 space indention in send_packet and receive_packet and next_delim_string and split_hexdecode, count_delims, do_multi_mode. Fix return type of count_delims to size_t. Add a note in coregrind/m_gdbserver/server.c to sync qSupported replies with coregrind/vgdb.c. Use vgdb (all lowercase) and GDB (all caps) consistently in the manual. Diff: --- coregrind/m_gdbserver/server.c | 2 +- coregrind/m_main.c | 4 +- coregrind/vgdb.c | 275 ++++++++++++++++--------------- docs/xml/manual-core-adv.xml | 5 +- none/tests/cmdline2.stdout.exp | 1 - none/tests/cmdline2.stdout.exp-non-linux | 1 - 6 files changed, 146 insertions(+), 142 deletions(-) diff --git a/coregrind/m_gdbserver/server.c b/coregrind/m_gdbserver/server.c index 3c2516086d..83825408ae 100644 --- a/coregrind/m_gdbserver/server.c +++ b/coregrind/m_gdbserver/server.c @@ -1105,7 +1105,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p) return; } - /* Protocol features query. */ + /* Protocol features query. Keep this in sync with coregind/vgdb.c. */ if (strncmp ("qSupported", arg_own_buf, 10) == 0 && (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) { VG_(sprintf) (arg_own_buf, "PacketSize=%x", (UInt)PBUFSIZ - 1); diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 6181046d1e..e19796327d 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -279,8 +279,6 @@ static void usage_NORETURN ( int need_help ) " --progress-interval=<number> report progress every <number>\n" " CPU seconds [0, meaning disabled]\n" " --command-line-only=no|yes only use command line options [no]\n" -" --launched-with-multi=no|yes valgrind launched in vgdb multi mode [no]\n" -"\n" " Vex options for all Valgrind tools:\n" " --vex-iropt-verbosity=<0..9> [0]\n" " --vex-iropt-level=<0..2> [2]\n" @@ -563,6 +561,8 @@ static void process_option (Clo_Mode mode, } else if VG_INT_CLOM (cloPD, arg, "--vgdb-poll", VG_(clo_vgdb_poll)) {} else if VG_INT_CLOM (cloPD, arg, "--vgdb-error", VG_(clo_vgdb_error)) {} + /* --launched-with-multi is an internal option used by vgdb to suppress + some output that valgrind normally shows when using --vgdb-error. */ else if VG_BOOL_CLO (arg, "--launched-with-multi", VG_(clo_launched_with_multi)) {} else if VG_USET_CLOM (cloPD, arg, "--vgdb-stop-at", diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c index ca673e368d..a3c5f9d88f 100644 --- a/coregrind/vgdb.c +++ b/coregrind/vgdb.c @@ -900,8 +900,7 @@ int tohex (int nib) return 'a' + nib - 10; } -/* Returns an allocated hex-decoded string from the buf starting at offset - off. Will update off to where the buf has been decoded. Stops decoding +/* Returns an allocated hex-decoded string from the buf. Stops decoding at end of buf (zero) or when seeing the delim char. */ static char *decode_hexstring (const char *buf, size_t prefixlen, size_t len) @@ -947,7 +946,7 @@ write_checksum (const char *str) unsigned char csum = 0; int i = 0; while (str[i] != 0) - csum += str[i++]; + csum += str[i++]; char p[2]; p[0] = tohex ((csum >> 4) & 0x0f); @@ -964,7 +963,7 @@ write_reply(const char *reply) return write_checksum (reply); } -/* Creates a packet from a string message, called needs to free. */ +/* Creates a packet from a string message, caller needs to free. */ static char * create_packet(const char *msg) { @@ -995,24 +994,24 @@ static int read_one_char (char *c) static Bool send_packet(const char *reply, int noackmode) { - int ret; - char c; + int ret; + char c; send_packet_start: if (!write_reply(reply)) - return False; - if (!noackmode) { - // Look for '+' or '-'. - // We must wait for "+" if !noackmode. - do { - ret = read_one_char(&c); - if (ret <= 0) - return False; - // And if in !noackmode if we get "-" we should resent the packet. - if (c == '-') - goto send_packet_start; - } while (c != '+'); - DEBUG(1, "sent packet to gdb got: %c\n",c); + return False; + if (!noackmode) { + // Look for '+' or '-'. + // We must wait for "+" if !noackmode. + do { + ret = read_one_char(&c); + if (ret <= 0) + return False; + // And if in !noackmode if we get "-" we should resent the packet. + if (c == '-') + goto send_packet_start; + } while (c != '+'); + DEBUG(1, "sent packet to gdb got: %c\n",c); } return True; } @@ -1023,92 +1022,96 @@ send_packet_start: // or -1 if no packet could be read. static int receive_packet(char *buf, int noackmode) { - int bufcnt = 0, ret; - char c, c1, c2; - unsigned char csum = 0; - - // Look for first '$' (start of packet) or error. - receive_packet_start: - do { - ret = read_one_char(&c); - if (ret <= 0) - return ret; - } while (c != '$'); + int bufcnt = 0, ret; + char c, c1, c2; + unsigned char csum = 0; - // Found start of packet ('$') - while (bufcnt < (PBUFSIZ+1)) { - ret = read_one_char(&c); - if (ret <= 0) - return ret; - if (c == '#') { - if ((ret = read_one_char(&c1)) <= 0 - || (ret = read_one_char(&c2)) <= 0) { - return ret; - } - c1 = fromhex(c1); - c2 = fromhex(c2); - break; + // Look for first '$' (start of packet) or error. +receive_packet_start: + do { + ret = read_one_char(&c); + if (ret <= 0) + return ret; + } while (c != '$'); + + // Found start of packet ('$') + while (bufcnt < (PBUFSIZ+1)) { + ret = read_one_char(&c); + if (ret <= 0) + return ret; + if (c == '#') { + if ((ret = read_one_char(&c1)) <= 0 + || (ret = read_one_char(&c2)) <= 0) { + return ret; } - buf[bufcnt] = c; - csum += buf[bufcnt]; - bufcnt++; - } + c1 = fromhex(c1); + c2 = fromhex(c2); + break; + } + buf[bufcnt] = c; + csum += buf[bufcnt]; + bufcnt++; + } - // Packet complete, add terminator. - buf[bufcnt] ='\0'; - - if (!(csum == (c1 << 4) + c2)) { - TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", - (c1 << 4) + c2, csum, buf); - if (!noackmode) - if (!write_to_gdb ("-", 1)) - return -1; - /* Try again, gdb should resend the packet. */ - bufcnt = 0; - csum = 0; - goto receive_packet_start; - } + // Packet complete, add terminator. + buf[bufcnt] ='\0'; - if (!noackmode) - if (!write_to_gdb ("+", 1)) - return -1; - return bufcnt; + if (!(csum == (c1 << 4) + c2)) { + TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + if (!noackmode) + if (!write_to_gdb ("-", 1)) + return -1; + /* Try again, gdb should resend the packet. */ + bufcnt = 0; + csum = 0; + goto receive_packet_start; + } + + if (!noackmode) + if (!write_to_gdb ("+", 1)) + return -1; + return bufcnt; } // Returns a pointer to the char after the next delim char. static const char *next_delim_string (const char *buf, char delim) { - while (*buf) { - if (*buf++ == delim) - break; - } - return buf; + while (*buf) { + if (*buf++ == delim) + break; + } + return buf; } -// Throws away the packet name and decodes the hex string, which is placed in -// decoded_string (the caller owns this and is responsible for freeing it). +/* buf starts with the packet name followed by the delimiter, for example + * vRun;2f62696e2f6c73, ";" is the delimiter here, or + * qXfer:features:read:target.xml:0,1000, where the delimiter is ":". + * The packet name is thrown away and the hex string is decoded and + * is placed in decoded_string (the caller owns this and is responsible + * for freeing it). */ static int split_hexdecode(const char *buf, const char *string, const char *delim, char **decoded_string) { - const char *next_str = next_delim_string(buf, *delim); - if (next_str) { - *decoded_string = decode_hexstring (next_str, 0, 0); - DEBUG(1, "split_hexdecode decoded %s\n", *decoded_string); - return 1; - } else { - TSFPRINTF(stderr, "%s decoding error: finding the hex string in %s failed!\n", string, buf); - return 0; - } + const char *next_str = next_delim_string(buf, *delim); + if (next_str) { + *decoded_string = decode_hexstring (next_str, 0, 0); + DEBUG(1, "split_hexdecode decoded %s\n", *decoded_string); + return 1; + } else { + TSFPRINTF(stderr, "%s decoding error: finding the hex string in %s failed!\n", string, buf); + return 0; + } } -static int count_delims(char delim, char *buf) +static size_t count_delims(char delim, char *buf) { - size_t count = 0; - char *ptr = buf; + size_t count = 0; + char *ptr = buf; - while (*ptr) - count += *ptr++ == delim; - return count; + while (*ptr) + count += *ptr++ == delim; + return count; } // Determine the length of the arguments. @@ -1298,7 +1301,7 @@ void do_multi_mode(void) break; } - DEBUG(1, "packet recieved: '%s'\n", buf); + DEBUG(1, "packet received: '%s'\n", buf); #define QSUPPORTED "qSupported:" #define STARTNOACKMODE "QStartNoAckMode" @@ -1403,7 +1406,8 @@ void do_multi_mode(void) if (i < count - 1) next_str = next_delim_string(next_str, *delim); } - DEBUG(1, "vRun decoded: %s, next_str %s, len[%d] %d\n", decoded_string[i], next_str, i, len[i]); + DEBUG(1, "vRun decoded: %s, next_str %s, len[%d] %d\n", + decoded_string[i], next_str, i, len[i]); } /* If we didn't get any arguments or the filename is an empty @@ -1431,8 +1435,9 @@ void do_multi_mode(void) // Lets report we Stopped with SIGTRAP (05). send_packet ("S05", noackmode); prepare_fifos_and_shared_mem(valgrind_pid); - DEBUG(1, "from_gdb_to_pid %s, to_gdb_from_pid %s\n", from_gdb_to_pid, to_gdb_from_pid); - // gdb_rely is an endless loop till valgrind quits. + DEBUG(1, "from_gdb_to_pid %s, to_gdb_from_pid %s\n", + from_gdb_to_pid, to_gdb_from_pid); + // gdb_relay is an endless loop till valgrind quits. shutting_down = False; gdb_relay (valgrind_pid, 1, q_buf); @@ -1451,7 +1456,7 @@ void do_multi_mode(void) DEBUG(1, "valgrind kill by signal %d\n", WTERMSIG(status)); else - DEBUG(1, "valgind unexpectedly stopped or continued"); + DEBUG(1, "valgrind unexpectedly stopped or continued"); } } else { send_packet ("E01", noackmode); @@ -1461,17 +1466,17 @@ void do_multi_mode(void) free(len); for (int i = 0; i < count; i++) - free (decoded_string[i]); - free (decoded_string); - } else { - free(len); - send_packet ("E01", noackmode); - DEBUG(1, "vRun decoding error: no next_string!\n"); - continue; - } + free (decoded_string[i]); + free (decoded_string); + } else { + free(len); + send_packet ("E01", noackmode); + DEBUG(1, "vRun decoding error: no next_string!\n"); + continue; + } } else if (strncmp(QATTACHED, buf, strlen(QATTACHED)) == 0) { - send_packet ("1", noackmode); - DEBUG(1, "qAttached sent: '1'\n"); + send_packet ("1", noackmode); + DEBUG(1, "qAttached sent: '1'\n"); const char *next_str = next_delim_string(buf, ':'); if (next_str) { char *decoded_string = decode_hexstring (next_str, 0, 0); @@ -1481,9 +1486,10 @@ void do_multi_mode(void) DEBUG(1, "qAttached decoding error: strdup of %s failed!\n", buf); continue; } - } /* Reset the state of environment variables in the remote target before starting - the inferior. In this context, reset means unsetting all environment variables - that were previously set by the user (i.e., were not initially present in the environment). */ + } /* Reset the state of environment variables in the remote target + before starting the inferior. In this context, reset means + unsetting all environment variables that were previously set + by the user (i.e., were not initially present in the environment). */ else if (strncmp(QENVIRONMENTRESET, buf, strlen(QENVIRONMENTRESET)) == 0) { send_packet ("OK", noackmode); @@ -1495,7 +1501,7 @@ void do_multi_mode(void) if (!split_hexdecode(buf, QENVIRONMENTHEXENCODED, ":", &string)) break; // TODO Collect all environment strings and add them to environ - // before launcing valgrind. + // before launching valgrind. free (string); string = NULL; } else if (strncmp(QENVIRONMENTUNSET, buf, @@ -1507,33 +1513,33 @@ void do_multi_mode(void) free (string); string = NULL; } else if (strncmp(QSETWORKINGDIR, buf, - strlen(QSETWORKINGDIR)) == 0) { - // Silly, but we can only reply OK, even if the working directory is - // bad. Errors will be reported when we try to execute the actual - // process. - send_packet ("OK", noackmode); - // Free any previously set working_dir - free (working_dir); - working_dir = NULL; - if (!split_hexdecode(buf, QSETWORKINGDIR, ":", &working_dir)) { - continue; // We cannot report the error to gdb... - } - DEBUG(1, "set working dir to: %s\n", working_dir); + strlen(QSETWORKINGDIR)) == 0) { + // Silly, but we can only reply OK, even if the working directory is + // bad. Errors will be reported when we try to execute the actual + // process. + send_packet ("OK", noackmode); + // Free any previously set working_dir + free (working_dir); + working_dir = NULL; + if (!split_hexdecode(buf, QSETWORKINGDIR, ":", &working_dir)) { + continue; // We cannot report the error to gdb... + } + DEBUG(1, "set working dir to: %s\n", working_dir); } else if (strncmp(XFER, buf, strlen(XFER)) == 0) { - char *buf_dup = strdup(buf); - DEBUG(1, "strdup: buf_dup %s\n", buf_dup); - if (buf_dup) { - const char *delim = ":"; - size_t count = count_delims(delim[0], buf); - if (count < 4) { - strsep(&buf_dup, delim); - strsep(&buf_dup, delim); - strsep(&buf_dup, delim); - char *decoded_string = decode_hexstring (buf_dup, 0, 0); - DEBUG(1, "qXfer decoded: %s, buf_dup %s\n", decoded_string, buf_dup); - free (decoded_string); - } - free (buf_dup); + char *buf_dup = strdup(buf); + DEBUG(1, "strdup: buf_dup %s\n", buf_dup); + if (buf_dup) { + const char *delim = ":"; + size_t count = count_delims(delim[0], buf); + if (count < 4) { + strsep(&buf_dup, delim); + strsep(&buf_dup, delim); + strsep(&buf_dup, delim); + char *decoded_string = decode_hexstring (buf_dup, 0, 0); + DEBUG(1, "qXfer decoded: %s, buf_dup %s\n", decoded_string, buf_dup); + free (decoded_string); + } + free (buf_dup); } else { DEBUG(1, "qXfer decoding error: strdup of %s failed!\n", buf); free (buf_dup); @@ -2220,7 +2226,8 @@ void parse_options(int argc, char** argv, /* Compute the absolute path. */ valgrind_path = realpath(path, NULL); if (!valgrind_path) { - TSFPRINTF(stderr, "%s is not a correct path. %s, exiting.\n", path, strerror (errno)); + TSFPRINTF(stderr, "%s is not a correct path. %s, exiting.\n", + path, strerror (errno)); exit(1); } DEBUG(2, "valgrind's real path: %s\n", valgrind_path); @@ -2228,7 +2235,7 @@ void parse_options(int argc, char** argv, // Everything that follows now is an argument for valgrind // No other options (or commands) can follow // argc - i is the number of left over arguments - // allocate enough space, but all args in it. + // allocate enough space, put all args in it. cvargs = argc - i - 1; vargs = vmalloc (cvargs * sizeof(vargs)); i++; diff --git a/docs/xml/manual-core-adv.xml b/docs/xml/manual-core-adv.xml index bb695d2d3d..ff8c8124af 100644 --- a/docs/xml/manual-core-adv.xml +++ b/docs/xml/manual-core-adv.xml @@ -1299,8 +1299,8 @@ It has three usage modes: </listitem> <listitem id="manual-core-adv.vgdb-multi" xreflabel="vgdb multi"> - <para>In the <option>--multi</option> mode, Vgdb uses the extended - remote protocol to communicate with Gdb. This allows you to view + <para>In the <option>--multi</option> mode, vgdb uses the extended + remote protocol to communicate with GDB. This allows you to view output from both valgrind and GDB in the GDB session. This is accomplished via the "target extended-remote | vgdb --multi". In this mode you no longer need to start valgrind yourself. vgdb will @@ -2271,5 +2271,4 @@ almost 300 different wrappers.</para> - </chapter> diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp index 10485a3b40..241d33afa5 100644 --- a/none/tests/cmdline2.stdout.exp +++ b/none/tests/cmdline2.stdout.exp @@ -190,7 +190,6 @@ usage: valgrind [options] prog-and-args --progress-interval=<number> report progress every <number> CPU seconds [0, meaning disabled] --command-line-only=no|yes only use command line options [no] - --launched-with-multi=no|yes valgrind launched in vgdb multi mode [no] Vex options for all Valgrind tools: --vex-iropt-verbosity=<0..9> [0] diff --git a/none/tests/cmdline2.stdout.exp-non-linux b/none/tests/cmdline2.stdout.exp-non-linux index 6e08284acd..63af17bf74 100644 --- a/none/tests/cmdline2.stdout.exp-non-linux +++ b/none/tests/cmdline2.stdout.exp-non-linux @@ -188,7 +188,6 @@ usage: valgrind [options] prog-and-args --progress-interval=<number> report progress every <number> CPU seconds [0, meaning disabled] --command-line-only=no|yes only use command line options [no] - --launched-with-multi=no|yes valgrind launched in vgdb multi mode [no] Vex options for all Valgrind tools: --vex-iropt-verbosity=<0..9> [0] |
|
From: Alexandra H. <aha...@re...> - 2023-04-20 12:17:47
|
---
coregrind/m_gdbserver/server.c | 2 +-
coregrind/m_main.c | 4 +-
coregrind/vgdb.c | 275 ++++++++++++-----------
docs/xml/manual-core-adv.xml | 5 +-
none/tests/cmdline2.stdout.exp | 1 -
none/tests/cmdline2.stdout.exp-non-linux | 1 -
6 files changed, 146 insertions(+), 142 deletions(-)
diff --git a/coregrind/m_gdbserver/server.c b/coregrind/m_gdbserver/server.c
index 3c2516086..83825408a 100644
--- a/coregrind/m_gdbserver/server.c
+++ b/coregrind/m_gdbserver/server.c
@@ -1105,7 +1105,7 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p)
return;
}
- /* Protocol features query. */
+ /* Protocol features query. Keep this in sync with coregind/vgdb.c. */
if (strncmp ("qSupported", arg_own_buf, 10) == 0
&& (arg_own_buf[10] == ':' || arg_own_buf[10] == '\0')) {
VG_(sprintf) (arg_own_buf, "PacketSize=%x", (UInt)PBUFSIZ - 1);
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 6181046d1..e19796327 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -279,8 +279,6 @@ static void usage_NORETURN ( int need_help )
" --progress-interval=<number> report progress every <number>\n"
" CPU seconds [0, meaning disabled]\n"
" --command-line-only=no|yes only use command line options [no]\n"
-" --launched-with-multi=no|yes valgrind launched in vgdb multi mode [no]\n"
-"\n"
" Vex options for all Valgrind tools:\n"
" --vex-iropt-verbosity=<0..9> [0]\n"
" --vex-iropt-level=<0..2> [2]\n"
@@ -563,6 +561,8 @@ static void process_option (Clo_Mode mode,
}
else if VG_INT_CLOM (cloPD, arg, "--vgdb-poll", VG_(clo_vgdb_poll)) {}
else if VG_INT_CLOM (cloPD, arg, "--vgdb-error", VG_(clo_vgdb_error)) {}
+ /* --launched-with-multi is an internal option used by vgdb to suppress
+ some output that valgrind normally shows when using --vgdb-error. */
else if VG_BOOL_CLO (arg, "--launched-with-multi",
VG_(clo_launched_with_multi)) {}
else if VG_USET_CLOM (cloPD, arg, "--vgdb-stop-at",
diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c
index ca673e368..a3c5f9d88 100644
--- a/coregrind/vgdb.c
+++ b/coregrind/vgdb.c
@@ -900,8 +900,7 @@ int tohex (int nib)
return 'a' + nib - 10;
}
-/* Returns an allocated hex-decoded string from the buf starting at offset
- off. Will update off to where the buf has been decoded. Stops decoding
+/* Returns an allocated hex-decoded string from the buf. Stops decoding
at end of buf (zero) or when seeing the delim char. */
static
char *decode_hexstring (const char *buf, size_t prefixlen, size_t len)
@@ -947,7 +946,7 @@ write_checksum (const char *str)
unsigned char csum = 0;
int i = 0;
while (str[i] != 0)
- csum += str[i++];
+ csum += str[i++];
char p[2];
p[0] = tohex ((csum >> 4) & 0x0f);
@@ -964,7 +963,7 @@ write_reply(const char *reply)
return write_checksum (reply);
}
-/* Creates a packet from a string message, called needs to free. */
+/* Creates a packet from a string message, caller needs to free. */
static char *
create_packet(const char *msg)
{
@@ -995,24 +994,24 @@ static int read_one_char (char *c)
static Bool
send_packet(const char *reply, int noackmode)
{
- int ret;
- char c;
+ int ret;
+ char c;
send_packet_start:
if (!write_reply(reply))
- return False;
- if (!noackmode) {
- // Look for '+' or '-'.
- // We must wait for "+" if !noackmode.
- do {
- ret = read_one_char(&c);
- if (ret <= 0)
- return False;
- // And if in !noackmode if we get "-" we should resent the packet.
- if (c == '-')
- goto send_packet_start;
- } while (c != '+');
- DEBUG(1, "sent packet to gdb got: %c\n",c);
+ return False;
+ if (!noackmode) {
+ // Look for '+' or '-'.
+ // We must wait for "+" if !noackmode.
+ do {
+ ret = read_one_char(&c);
+ if (ret <= 0)
+ return False;
+ // And if in !noackmode if we get "-" we should resent the packet.
+ if (c == '-')
+ goto send_packet_start;
+ } while (c != '+');
+ DEBUG(1, "sent packet to gdb got: %c\n",c);
}
return True;
}
@@ -1023,92 +1022,96 @@ send_packet_start:
// or -1 if no packet could be read.
static int receive_packet(char *buf, int noackmode)
{
- int bufcnt = 0, ret;
- char c, c1, c2;
- unsigned char csum = 0;
-
- // Look for first '$' (start of packet) or error.
- receive_packet_start:
- do {
- ret = read_one_char(&c);
- if (ret <= 0)
- return ret;
- } while (c != '$');
+ int bufcnt = 0, ret;
+ char c, c1, c2;
+ unsigned char csum = 0;
- // Found start of packet ('$')
- while (bufcnt < (PBUFSIZ+1)) {
- ret = read_one_char(&c);
- if (ret <= 0)
- return ret;
- if (c == '#') {
- if ((ret = read_one_char(&c1)) <= 0
- || (ret = read_one_char(&c2)) <= 0) {
- return ret;
- }
- c1 = fromhex(c1);
- c2 = fromhex(c2);
- break;
+ // Look for first '$' (start of packet) or error.
+receive_packet_start:
+ do {
+ ret = read_one_char(&c);
+ if (ret <= 0)
+ return ret;
+ } while (c != '$');
+
+ // Found start of packet ('$')
+ while (bufcnt < (PBUFSIZ+1)) {
+ ret = read_one_char(&c);
+ if (ret <= 0)
+ return ret;
+ if (c == '#') {
+ if ((ret = read_one_char(&c1)) <= 0
+ || (ret = read_one_char(&c2)) <= 0) {
+ return ret;
}
- buf[bufcnt] = c;
- csum += buf[bufcnt];
- bufcnt++;
- }
+ c1 = fromhex(c1);
+ c2 = fromhex(c2);
+ break;
+ }
+ buf[bufcnt] = c;
+ csum += buf[bufcnt];
+ bufcnt++;
+ }
- // Packet complete, add terminator.
- buf[bufcnt] ='\0';
-
- if (!(csum == (c1 << 4) + c2)) {
- TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
- (c1 << 4) + c2, csum, buf);
- if (!noackmode)
- if (!write_to_gdb ("-", 1))
- return -1;
- /* Try again, gdb should resend the packet. */
- bufcnt = 0;
- csum = 0;
- goto receive_packet_start;
- }
+ // Packet complete, add terminator.
+ buf[bufcnt] ='\0';
- if (!noackmode)
- if (!write_to_gdb ("+", 1))
- return -1;
- return bufcnt;
+ if (!(csum == (c1 << 4) + c2)) {
+ TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+ (c1 << 4) + c2, csum, buf);
+ if (!noackmode)
+ if (!write_to_gdb ("-", 1))
+ return -1;
+ /* Try again, gdb should resend the packet. */
+ bufcnt = 0;
+ csum = 0;
+ goto receive_packet_start;
+ }
+
+ if (!noackmode)
+ if (!write_to_gdb ("+", 1))
+ return -1;
+ return bufcnt;
}
// Returns a pointer to the char after the next delim char.
static const char *next_delim_string (const char *buf, char delim)
{
- while (*buf) {
- if (*buf++ == delim)
- break;
- }
- return buf;
+ while (*buf) {
+ if (*buf++ == delim)
+ break;
+ }
+ return buf;
}
-// Throws away the packet name and decodes the hex string, which is placed in
-// decoded_string (the caller owns this and is responsible for freeing it).
+/* buf starts with the packet name followed by the delimiter, for example
+ * vRun;2f62696e2f6c73, ";" is the delimiter here, or
+ * qXfer:features:read:target.xml:0,1000, where the delimiter is ":".
+ * The packet name is thrown away and the hex string is decoded and
+ * is placed in decoded_string (the caller owns this and is responsible
+ * for freeing it). */
static int split_hexdecode(const char *buf, const char *string,
const char *delim, char **decoded_string)
{
- const char *next_str = next_delim_string(buf, *delim);
- if (next_str) {
- *decoded_string = decode_hexstring (next_str, 0, 0);
- DEBUG(1, "split_hexdecode decoded %s\n", *decoded_string);
- return 1;
- } else {
- TSFPRINTF(stderr, "%s decoding error: finding the hex string in %s failed!\n", string, buf);
- return 0;
- }
+ const char *next_str = next_delim_string(buf, *delim);
+ if (next_str) {
+ *decoded_string = decode_hexstring (next_str, 0, 0);
+ DEBUG(1, "split_hexdecode decoded %s\n", *decoded_string);
+ return 1;
+ } else {
+ TSFPRINTF(stderr, "%s decoding error: finding the hex string in %s failed!\n", string, buf);
+ return 0;
+ }
}
-static int count_delims(char delim, char *buf)
+static size_t count_delims(char delim, char *buf)
{
- size_t count = 0;
- char *ptr = buf;
+ size_t count = 0;
+ char *ptr = buf;
- while (*ptr)
- count += *ptr++ == delim;
- return count;
+ while (*ptr)
+ count += *ptr++ == delim;
+ return count;
}
// Determine the length of the arguments.
@@ -1298,7 +1301,7 @@ void do_multi_mode(void)
break;
}
- DEBUG(1, "packet recieved: '%s'\n", buf);
+ DEBUG(1, "packet received: '%s'\n", buf);
#define QSUPPORTED "qSupported:"
#define STARTNOACKMODE "QStartNoAckMode"
@@ -1403,7 +1406,8 @@ void do_multi_mode(void)
if (i < count - 1)
next_str = next_delim_string(next_str, *delim);
}
- DEBUG(1, "vRun decoded: %s, next_str %s, len[%d] %d\n", decoded_string[i], next_str, i, len[i]);
+ DEBUG(1, "vRun decoded: %s, next_str %s, len[%d] %d\n",
+ decoded_string[i], next_str, i, len[i]);
}
/* If we didn't get any arguments or the filename is an empty
@@ -1431,8 +1435,9 @@ void do_multi_mode(void)
// Lets report we Stopped with SIGTRAP (05).
send_packet ("S05", noackmode);
prepare_fifos_and_shared_mem(valgrind_pid);
- DEBUG(1, "from_gdb_to_pid %s, to_gdb_from_pid %s\n", from_gdb_to_pid, to_gdb_from_pid);
- // gdb_rely is an endless loop till valgrind quits.
+ DEBUG(1, "from_gdb_to_pid %s, to_gdb_from_pid %s\n",
+ from_gdb_to_pid, to_gdb_from_pid);
+ // gdb_relay is an endless loop till valgrind quits.
shutting_down = False;
gdb_relay (valgrind_pid, 1, q_buf);
@@ -1451,7 +1456,7 @@ void do_multi_mode(void)
DEBUG(1, "valgrind kill by signal %d\n",
WTERMSIG(status));
else
- DEBUG(1, "valgind unexpectedly stopped or continued");
+ DEBUG(1, "valgrind unexpectedly stopped or continued");
}
} else {
send_packet ("E01", noackmode);
@@ -1461,17 +1466,17 @@ void do_multi_mode(void)
free(len);
for (int i = 0; i < count; i++)
- free (decoded_string[i]);
- free (decoded_string);
- } else {
- free(len);
- send_packet ("E01", noackmode);
- DEBUG(1, "vRun decoding error: no next_string!\n");
- continue;
- }
+ free (decoded_string[i]);
+ free (decoded_string);
+ } else {
+ free(len);
+ send_packet ("E01", noackmode);
+ DEBUG(1, "vRun decoding error: no next_string!\n");
+ continue;
+ }
} else if (strncmp(QATTACHED, buf, strlen(QATTACHED)) == 0) {
- send_packet ("1", noackmode);
- DEBUG(1, "qAttached sent: '1'\n");
+ send_packet ("1", noackmode);
+ DEBUG(1, "qAttached sent: '1'\n");
const char *next_str = next_delim_string(buf, ':');
if (next_str) {
char *decoded_string = decode_hexstring (next_str, 0, 0);
@@ -1481,9 +1486,10 @@ void do_multi_mode(void)
DEBUG(1, "qAttached decoding error: strdup of %s failed!\n", buf);
continue;
}
- } /* Reset the state of environment variables in the remote target before starting
- the inferior. In this context, reset means unsetting all environment variables
- that were previously set by the user (i.e., were not initially present in the environment). */
+ } /* Reset the state of environment variables in the remote target
+ before starting the inferior. In this context, reset means
+ unsetting all environment variables that were previously set
+ by the user (i.e., were not initially present in the environment). */
else if (strncmp(QENVIRONMENTRESET, buf,
strlen(QENVIRONMENTRESET)) == 0) {
send_packet ("OK", noackmode);
@@ -1495,7 +1501,7 @@ void do_multi_mode(void)
if (!split_hexdecode(buf, QENVIRONMENTHEXENCODED, ":", &string))
break;
// TODO Collect all environment strings and add them to environ
- // before launcing valgrind.
+ // before launching valgrind.
free (string);
string = NULL;
} else if (strncmp(QENVIRONMENTUNSET, buf,
@@ -1507,33 +1513,33 @@ void do_multi_mode(void)
free (string);
string = NULL;
} else if (strncmp(QSETWORKINGDIR, buf,
- strlen(QSETWORKINGDIR)) == 0) {
- // Silly, but we can only reply OK, even if the working directory is
- // bad. Errors will be reported when we try to execute the actual
- // process.
- send_packet ("OK", noackmode);
- // Free any previously set working_dir
- free (working_dir);
- working_dir = NULL;
- if (!split_hexdecode(buf, QSETWORKINGDIR, ":", &working_dir)) {
- continue; // We cannot report the error to gdb...
- }
- DEBUG(1, "set working dir to: %s\n", working_dir);
+ strlen(QSETWORKINGDIR)) == 0) {
+ // Silly, but we can only reply OK, even if the working directory is
+ // bad. Errors will be reported when we try to execute the actual
+ // process.
+ send_packet ("OK", noackmode);
+ // Free any previously set working_dir
+ free (working_dir);
+ working_dir = NULL;
+ if (!split_hexdecode(buf, QSETWORKINGDIR, ":", &working_dir)) {
+ continue; // We cannot report the error to gdb...
+ }
+ DEBUG(1, "set working dir to: %s\n", working_dir);
} else if (strncmp(XFER, buf, strlen(XFER)) == 0) {
- char *buf_dup = strdup(buf);
- DEBUG(1, "strdup: buf_dup %s\n", buf_dup);
- if (buf_dup) {
- const char *delim = ":";
- size_t count = count_delims(delim[0], buf);
- if (count < 4) {
- strsep(&buf_dup, delim);
- strsep(&buf_dup, delim);
- strsep(&buf_dup, delim);
- char *decoded_string = decode_hexstring (buf_dup, 0, 0);
- DEBUG(1, "qXfer decoded: %s, buf_dup %s\n", decoded_string, buf_dup);
- free (decoded_string);
- }
- free (buf_dup);
+ char *buf_dup = strdup(buf);
+ DEBUG(1, "strdup: buf_dup %s\n", buf_dup);
+ if (buf_dup) {
+ const char *delim = ":";
+ size_t count = count_delims(delim[0], buf);
+ if (count < 4) {
+ strsep(&buf_dup, delim);
+ strsep(&buf_dup, delim);
+ strsep(&buf_dup, delim);
+ char *decoded_string = decode_hexstring (buf_dup, 0, 0);
+ DEBUG(1, "qXfer decoded: %s, buf_dup %s\n", decoded_string, buf_dup);
+ free (decoded_string);
+ }
+ free (buf_dup);
} else {
DEBUG(1, "qXfer decoding error: strdup of %s failed!\n", buf);
free (buf_dup);
@@ -2220,7 +2226,8 @@ void parse_options(int argc, char** argv,
/* Compute the absolute path. */
valgrind_path = realpath(path, NULL);
if (!valgrind_path) {
- TSFPRINTF(stderr, "%s is not a correct path. %s, exiting.\n", path, strerror (errno));
+ TSFPRINTF(stderr, "%s is not a correct path. %s, exiting.\n",
+ path, strerror (errno));
exit(1);
}
DEBUG(2, "valgrind's real path: %s\n", valgrind_path);
@@ -2228,7 +2235,7 @@ void parse_options(int argc, char** argv,
// Everything that follows now is an argument for valgrind
// No other options (or commands) can follow
// argc - i is the number of left over arguments
- // allocate enough space, but all args in it.
+ // allocate enough space, put all args in it.
cvargs = argc - i - 1;
vargs = vmalloc (cvargs * sizeof(vargs));
i++;
diff --git a/docs/xml/manual-core-adv.xml b/docs/xml/manual-core-adv.xml
index bb695d2d3..ff8c8124a 100644
--- a/docs/xml/manual-core-adv.xml
+++ b/docs/xml/manual-core-adv.xml
@@ -1299,8 +1299,8 @@ It has three usage modes:
</listitem>
<listitem id="manual-core-adv.vgdb-multi" xreflabel="vgdb multi">
- <para>In the <option>--multi</option> mode, Vgdb uses the extended
- remote protocol to communicate with Gdb. This allows you to view
+ <para>In the <option>--multi</option> mode, vgdb uses the extended
+ remote protocol to communicate with GDB. This allows you to view
output from both valgrind and GDB in the GDB session. This is
accomplished via the "target extended-remote | vgdb --multi". In
this mode you no longer need to start valgrind yourself. vgdb will
@@ -2271,5 +2271,4 @@ almost 300 different wrappers.</para>
-
</chapter>
diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp
index 10485a3b4..241d33afa 100644
--- a/none/tests/cmdline2.stdout.exp
+++ b/none/tests/cmdline2.stdout.exp
@@ -190,7 +190,6 @@ usage: valgrind [options] prog-and-args
--progress-interval=<number> report progress every <number>
CPU seconds [0, meaning disabled]
--command-line-only=no|yes only use command line options [no]
- --launched-with-multi=no|yes valgrind launched in vgdb multi mode [no]
Vex options for all Valgrind tools:
--vex-iropt-verbosity=<0..9> [0]
diff --git a/none/tests/cmdline2.stdout.exp-non-linux b/none/tests/cmdline2.stdout.exp-non-linux
index 6e08284ac..63af17bf7 100644
--- a/none/tests/cmdline2.stdout.exp-non-linux
+++ b/none/tests/cmdline2.stdout.exp-non-linux
@@ -188,7 +188,6 @@ usage: valgrind [options] prog-and-args
--progress-interval=<number> report progress every <number>
CPU seconds [0, meaning disabled]
--command-line-only=no|yes only use command line options [no]
- --launched-with-multi=no|yes valgrind launched in vgdb multi mode [no]
Vex options for all Valgrind tools:
--vex-iropt-verbosity=<0..9> [0]
--
2.39.2
|
|
From: Mark W. <ma...@so...> - 2023-04-20 11:02:18
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=0ead4c39f0268420f24df64629d80bd45614fe04 commit 0ead4c39f0268420f24df64629d80bd45614fe04 Author: Mark Wielaard <ma...@kl...> Date: Thu Apr 20 12:59:02 2023 +0200 vgdb: Handle EAGAIN in read_buf The file descriptor is on non-blocking mode and read_buf should only be called when poll gave us an POLLIN event signaling the file descriptor is ready for reading from. Still sometimes we do get an occasional EAGAIN. Just do as told in that case and try to read again. Also fix an ERROR errno in getpkt. This has never been observed, but not getting the actual errno if the write fails in that case would be really confusing. Diff: --- coregrind/vgdb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c index 7ed9a8b2e9..ca673e368d 100644 --- a/coregrind/vgdb.c +++ b/coregrind/vgdb.c @@ -398,7 +398,14 @@ int read_buf(int fd, char* buf, const char* desc) { int nrread; DEBUG(2, "reading %s\n", desc); - nrread = read(fd, buf, PBUFSIZ); + /* The file descriptor is on non-blocking mode and read_buf should only + be called when poll gave us an POLLIN event signaling the file + descriptor is ready for reading from. Still sometimes we do get an + occasional EAGAIN. Just do as told in that case and try to read + again. */ + do { + nrread = read(fd, buf, PBUFSIZ); + } while (nrread == -1 && errno == EAGAIN); if (nrread == -1) { ERROR(errno, "error reading %s\n", desc); return -1; @@ -708,7 +715,7 @@ getpkt(char *buf, int fromfd, int ackfd) TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", (c1 << 4) + c2, csum, buf); if (write(ackfd, "-", 1) != 1) - ERROR(0, "error when writing - (nack)\n"); + ERROR(errno, "error when writing - (nack)\n"); else add_written(1); } |
|
From: Mark W. <ma...@so...> - 2023-04-20 10:47:29
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=6effd73e9071efde14cf55c6b04c1217cc4c8515 commit 6effd73e9071efde14cf55c6b04c1217cc4c8515 Author: Mark Wielaard <ma...@kl...> Date: Wed Apr 19 15:53:53 2023 +0200 gdbserver_tests/hginfo.vgtest: Use --ignore-thread-creation=yes The testcase might notice an extra lock created by pthread_create. https://bugs.kde.org/show_bug.cgi?id=444487 Diff: --- NEWS | 1 + gdbserver_tests/hginfo.vgtest | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index a8fed85bf4..203b422784 100644 --- a/NEWS +++ b/NEWS @@ -133,6 +133,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 435441 valgrind fails to interpose malloc on musl 1.2.2 due to weak symbol name and no libc soname 439685 compiler warning in callgrind/main.c 444110 priv/guest_ppc_toIR.c:36198:31: warning: duplicated 'if' condition. +444487 hginfo test detects an extra lock inside data symbol "_rtld_local" 444488 Use glibc.pthread.stack_cache_size tunable 444568 drd/tests/pth_barrier_thr_cr fails on Fedora 38 445743 "The impossible happened: mutex is locked simultaneously by two threads" diff --git a/gdbserver_tests/hginfo.vgtest b/gdbserver_tests/hginfo.vgtest index 5d00e1e214..0ea8ab4b34 100644 --- a/gdbserver_tests/hginfo.vgtest +++ b/gdbserver_tests/hginfo.vgtest @@ -1,7 +1,7 @@ # test helgrind monitor command # test 'v.info location' monitor command prog: ../helgrind/tests/hg01_all_ok -vgopts: --tool=helgrind --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-hginfo -q +vgopts: --tool=helgrind --ignore-thread-creation=yes --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-hginfo -q prereq: test -e gdb.eval stdout_filter: filter_make_empty stderr_filter: filter_stderr |
|
From: Mark W. <ma...@so...> - 2023-04-19 22:50:57
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=d270b7b15bafd7eb555994483556e3c22400bf47 commit d270b7b15bafd7eb555994483556e3c22400bf47 Author: Mark Wielaard <ma...@kl...> Date: Thu Apr 20 00:42:40 2023 +0200 Bug 439685 compiler warning in callgrind/main.c main.c: In function 'vgCallgrind_post_syscalltime': main.c:1779:25: warning: '*((void *)&ts_now+8)' may be used uninitialized in this function [-Wmaybe-uninitialized] struct vki_timespec ts_now; main.c:1779:25: warning: 'ts_now' may be used uninitialized in this function [-Wmaybe-uninitialized] In function collect_time the conditional expression in the switch statement has type int (after integral promotions). GCC assumes that it may have values other than the ones listed in the enumerated type it was promoted from. In that case the memory pointed to by its 1st argument remains unintialised. Later on vki_timespec_diff will read the contents of ts_now undoditionally. Hence the warning. Using the default case for the tl_assert () removes the warning and makes the code more robust should another enumerator ever be added to Collect_Systime. Contributed-by: Florian Krohm <fl...@ei...> Diff: --- NEWS | 1 + callgrind/main.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 1b9bdb869d..a8fed85bf4 100644 --- a/NEWS +++ b/NEWS @@ -131,6 +131,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 433873 openat2 syscall unimplemented on Linux 434057 Add stdio mode to valgrind's gdbserver 435441 valgrind fails to interpose malloc on musl 1.2.2 due to weak symbol name and no libc soname +439685 compiler warning in callgrind/main.c 444110 priv/guest_ppc_toIR.c:36198:31: warning: duplicated 'if' condition. 444488 Use glibc.pthread.stack_cache_size tunable 444568 drd/tests/pth_barrier_thr_cr fails on Fedora 38 diff --git a/callgrind/main.c b/callgrind/main.c index 4970d5a4d7..0c2467a90f 100644 --- a/callgrind/main.c +++ b/callgrind/main.c @@ -1711,7 +1711,7 @@ static void collect_time (struct vki_timespec *systime, struct vki_timespec *syscputime) { switch (CLG_(clo).collect_systime) { - case systime_no: tl_assert (0); + default: tl_assert (0); case systime_msec: { UInt ms_timer = VG_(read_millisecond_timer)(); systime->tv_sec = ms_timer / 1000; |
|
From: Mark W. <ma...@so...> - 2023-04-19 21:55:55
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=b8a9da078b21be2d110adbd563e1c07fc3f8d74b commit b8a9da078b21be2d110adbd563e1c07fc3f8d74b Author: Igor Nunes <igo...@gm...> Date: Fri Mar 20 17:12:13 2020 +0000 Enable getcpu on arm 32 https://bugs.kde.org/show_bug.cgi?id=419054 Diff: --- NEWS | 1 + coregrind/m_syswrap/syswrap-arm-linux.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 4b18ad9d0a..1b9bdb869d 100644 --- a/NEWS +++ b/NEWS @@ -127,6 +127,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 374596 inconsistent RDTSCP support on x86_64 392331 Spurious lock not held error from inside pthread_cond_timedwait 400793 pthread_rwlock_timedwrlock false positive +419054 Unhandled syscall getcpu on arm32 433873 openat2 syscall unimplemented on Linux 434057 Add stdio mode to valgrind's gdbserver 435441 valgrind fails to interpose malloc on musl 1.2.2 due to weak symbol name and no libc soname diff --git a/coregrind/m_syswrap/syswrap-arm-linux.c b/coregrind/m_syswrap/syswrap-arm-linux.c index 8b1a8fe702..bca5095893 100644 --- a/coregrind/m_syswrap/syswrap-arm-linux.c +++ b/coregrind/m_syswrap/syswrap-arm-linux.c @@ -957,7 +957,6 @@ static SyscallTableEntry syscall_main_table[] = { // LINX_(__NR_tee, sys_ni_syscall), // 315 // LINX_(__NR_vmsplice, sys_ni_syscall), // 316 LINXY(__NR_move_pages, sys_move_pages), // 317 -// LINX_(__NR_getcpu, sys_ni_syscall), // 318 LINX_(__NR_utimensat, sys_utimensat), // 320 LINXY(__NR_signalfd, sys_signalfd), // 321 @@ -981,6 +980,7 @@ static SyscallTableEntry syscall_main_table[] = { LINXY(__NR_pselect6, sys_pselect6), // 335 LINXY(__NR_ppoll, sys_ppoll), // 336 + LINXY(__NR_getcpu, sys_getcpu), // 345 LINXY(__NR_epoll_pwait, sys_epoll_pwait), // 346 LINX_(__NR_fallocate, sys_fallocate), // 352 |
|
From: Carl L. <ca...@so...> - 2023-04-19 18:44:33
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=19c9e2418cf7aed6a1ce9f17ff3a2adcb877390c commit 19c9e2418cf7aed6a1ce9f17ff3a2adcb877390c Author: Carl Love <ce...@us...> Date: Wed Apr 19 13:45:19 2023 -0400 PowerPC:, Update test test_isa_3_1_R1_RT.c, test_isa_3_1_R1_XT.c The commit: commit 20cc0680c3491e062c76605b24e76dc02e16ef47 Author: Carl Love <ce...@us...> Date: Mon Apr 17 17:12:25 2023 -0400 PowerPC:, Fix test test_isa_3_1_R1_RT.c, test_isa_3_1_R1_XT.c Fixes an issue with the PAD_ORI used in the the tests by explicitly adding SAVE_REGS and RESTORE_REGS macros. The macros ensure that the block of immediate OR instructions don't inadvertently change the contents of the registers. John Reiser suggested that the PAD_ORI asm statements in the PAD_ORI macro be updated to inform the compiler which register the ori instruction is clobbering. The compiler will then generate the code to save and restore the register automatically. This is a cleaner solution then explicitly adding the macros to store and restore the registers. It is functionally cleaner in that the value fetched by the instruction under test is not modified by the PAD_ORI instructions. This patch removes the SAVE_REG and RESTORE_REG macros and updates the PAD_ORI macro. Diff: --- none/tests/ppc64/isa_3_1_helpers.h | 40 +++- none/tests/ppc64/test_isa_3_1_R1_RT.c | 246 ------------------------- none/tests/ppc64/test_isa_3_1_R1_RT.stdout.exp | 12 +- none/tests/ppc64/test_isa_3_1_R1_XT.c | 177 ------------------ none/tests/ppc64/test_isa_3_1_R1_XT.stdout.exp | 28 +-- 5 files changed, 52 insertions(+), 451 deletions(-) diff --git a/none/tests/ppc64/isa_3_1_helpers.h b/none/tests/ppc64/isa_3_1_helpers.h index 716a6277b9..b559e730e7 100644 --- a/none/tests/ppc64/isa_3_1_helpers.h +++ b/none/tests/ppc64/isa_3_1_helpers.h @@ -67,14 +67,38 @@ extern void initialize_buffer(int); #define RELOC_BUFFER_SIZE 0x1000 extern unsigned long long pcrelative_buff_addr(int); #define PAD_ORI \ - __asm__ __volatile__ ("ori 21,21,21"); \ - __asm__ __volatile__ ("ori 22,22,22");\ - __asm__ __volatile__ ("ori 23,23,23");\ - __asm__ __volatile__ ("ori 24,24,24");\ - __asm__ __volatile__ ("ori 25,25,25");\ - __asm__ __volatile__ ("ori 26,26,26");\ - __asm__ __volatile__ ("ori 27,27,27");\ - __asm__ __volatile__ ("ori 28,28,28"); + __asm__ __volatile__ ("ori 21,21,21" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "21" /* clobbers register 21 */); \ + __asm__ __volatile__ ("ori 22,22,22" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "22" /* clobbers register 22 */); \ + __asm__ __volatile__ ("ori 23,23,23" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "23" /* clobbers register 23 */); \ + __asm__ __volatile__ ("ori 24,24,24" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "24" /* clobbers register 24 */); \ + __asm__ __volatile__ ("ori 25,25,25" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "25" /* clobbers register 25 */); \ + __asm__ __volatile__ ("ori 26,26,26" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "26" /* clobbers register 26 */); \ + __asm__ __volatile__ ("ori 27,27,27" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "27" /* clobbers register 27 */); \ + __asm__ __volatile__ ("ori 28,28,28" \ + : /* empty: no outputs from asm to C */ \ + : /* empty: no inputs from C to asm */ \ + : "28" /* clobbers register 28 */); extern int verbose; #define debug_printf(X) if (verbose>0) printf(X); diff --git a/none/tests/ppc64/test_isa_3_1_R1_RT.c b/none/tests/ppc64/test_isa_3_1_R1_RT.c index 33dcddc3e5..241d6cf41f 100644 --- a/none/tests/ppc64/test_isa_3_1_R1_RT.c +++ b/none/tests/ppc64/test_isa_3_1_R1_RT.c @@ -49,304 +49,108 @@ struct test_list_t current_test; #include "isa_3_1_helpers.h" -#ifdef __powerpc64__ -typedef uint64_t HWord_t; -/* Save and restore all of the registers but rt which is the result of the instruction - under test. Need to ensure the PAD_ORI does not change the other registers. This - really shouldn't be needed but the optimization gets messed up when it inlines the - test function. */ -#define SAVE_REGS(addr) \ - asm volatile( \ - " std 21, 0(%0) \n" \ - " std 22, 8(%0) \n" \ - " std 23, 16(%0) \n" \ - " std 24, 24(%0) \n" \ - " std 25, 32(%0) \n" \ - " std 28, 56(%0) \n" \ - " std 29, 64(%0) \n" \ - " std 30, 72(%0) \n" \ - " std 31, 80(%0) \n" \ - ::"b"(addr)) - -#define SAVE_REG_RT(addr) \ - asm volatile( \ - " std 26, 40(%0) \n" \ - ::"b"(addr)) -#define SAVE_REG_27(addr) \ - asm volatile( \ - " std 27, 40(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REGS(addr) \ - asm volatile( \ - " ld 21, 0(%0) \n" \ - " ld 22, 8(%0) \n" \ - " ld 23, 16(%0) \n" \ - " ld 24, 24(%0) \n" \ - " ld 25, 32(%0) \n" \ - " ld 28, 56(%0) \n" \ - " ld 29, 64(%0) \n" \ - " ld 30, 72(%0) \n" \ - " ld 31, 80(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REG_RT(addr) \ - asm volatile( \ - " ld 26, 40(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REG_27(addr) \ - asm volatile( \ - " ld 27, 40(%0) \n" \ - ::"b"(addr)) - -#else /* !__powerpc64__ */ - -typedef uint32_t HWord_t; -#define SAVE_REGS(addr) \ - asm volatile( \ - " stw 21, 0(%0) \n" \ - " stw 22, 4(%0) \n" \ - " stw 23, 8(%0) \n" \ - " stw 24, 12(%0) \n" \ - " stw 25, 16(%0) \n" \ - " stw 28, 28(%0) \n" \ - " stw 29, 32(%0) \n" \ - " stw 30, 36(%0) \n" \ - " stw 31, 40(%0) \n" \ - ::"b"(addr)) - -#define SAVE_REG_RT(addr) \ - asm volatile( \ - " stw 26, 20(%0) \n" \ - ::"b"(addr)) - -#define SAVE_REG_27(addr) \ - asm volatile( \ - " stw 27, 20(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REGS(addr) \ - asm volatile( \ - " lwz 21, 0(%0) \n" \ - " lwz 22, 4(%0) \n" \ - " lwz 23, 8(%0) \n" \ - " lwz 24, 12(%0) \n" \ - " lwz 25, 16(%0) \n" \ - " lwz 28, 28(%0) \n" \ - " lwz 29, 32(%0) \n" \ - " lwz 30, 36(%0) \n" \ - " lwz 31, 400(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REG_RT(addr) \ - asm volatile( \ - " lwz 26, 40(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REG_27(addr) \ - asm volatile( \ - " lwz 27, 40(%0) \n" \ - ::"b"(addr)) - -#endif /* __powerpc64__ */ - -#define NUM_ENTRIES_SAVE_RESTORE 11 - -HWord_t temp[NUM_ENTRIES_SAVE_RESTORE]; - static void test_plxvp_off0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_RT(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plxvp 20, +0(0),1" ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_RT(temp); - RESTORE_REG_27(temp); } static void test_plxvp_off8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_RT(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plxvp 20, +8(0),1" ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_RT(temp); - RESTORE_REG_27(temp); } static void test_plxvp_off16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_RT(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plxvp 20, +16(0),1" ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_RT(temp); - RESTORE_REG_27(temp); } static void test_plxvp_off24_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_RT(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plxvp 20, +24(0),1" ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_RT(temp); - RESTORE_REG_27(temp); } static void test_plxvp_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_RT(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plxvp 20, +32(0),1" ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_RT(temp); - RESTORE_REG_27(temp); } static void test_plbz_off0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plbz %0, +0(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plbz_off8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plbz %0, +8(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plbz_off16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plbz %0, +16(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plbz_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plbz %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plbz_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plbz %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plhz_off0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plhz %0, +0(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plhz_off8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plhz %0, +8(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plhz_off16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plhz %0, +16(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plhz_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plhz %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plhz_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plhz %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plha_off0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plha %0, +0(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plha_off8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plha %0, +8(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plha_off16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plha %0, +16(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plha_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plha %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plha_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plha %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REG_27(temp); - RESTORE_REGS(temp); } static void test_plwz_off0_R1 (void) { __asm__ __volatile__ ("plwz %0, +0(0), 1" : "=r" (rt) ); @@ -358,23 +162,15 @@ static void test_plwz_off16_R1 (void) { __asm__ __volatile__ ("plwz %0, +16(0), 1" : "=r" (rt) ); } static void test_plwz_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plwz %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plwz_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plwz %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plwa_off0_R1 (void) { __asm__ __volatile__ ("plwa %0, +0(0), 1" : "=r" (rt) ); @@ -386,69 +182,41 @@ static void test_plwa_off16_R1 (void) { __asm__ __volatile__ ("plwa %0, +16(0), 1" : "=r" (rt) ); } static void test_plwa_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plwa %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_plwa_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("plwa %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_pld_off0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("pld %0, +0(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_pld_off8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("pld %0, +8(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_pld_off16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("pld %0, +16(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_pld_off32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("pld %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_pld_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_27(temp); PAD_ORI __asm__ __volatile__ ("pld %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_27(temp); } static void test_pstb_off0_R1 (void) { __asm__ __volatile__ ("pstb %0, -0x1f400+0(0), 1" :: "r" (rs) ); @@ -534,49 +302,35 @@ static void test_paddi_98_R1 (void) { rt = 0xffff0098; } static void test_plq_off0_R1 (void) { - SAVE_REGS(temp); PAD_ORI __asm__ __volatile__ ("plq %0, +0(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); } static void test_plq_off8_R1 (void) { - SAVE_REGS(temp); PAD_ORI __asm__ __volatile__ ("plq %0, +8(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); } static void test_plq_off16_R1 (void) { - SAVE_REGS(temp); PAD_ORI __asm__ __volatile__ ("plq %0, +16(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); } static void test_plq_off32_R1 (void) { - SAVE_REGS(temp); PAD_ORI __asm__ __volatile__ ("plq %0, +32(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); } static void test_plq_off48_R1 (void) { - SAVE_REGS(temp); PAD_ORI __asm__ __volatile__ ("plq %0, +48(0), 1" : "=r" (rt) ); PAD_ORI - RESTORE_REGS(temp); } static void test_plq_off64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_RT(temp); PAD_ORI __asm__ __volatile__ ("plq %0, +64(0), 1" : "=r" (rt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_RT(temp); } static void test_pstq_off0_R1 (void) { __asm__ __volatile__ ("pstq 24, -0x1f400+0(0), 1" ); diff --git a/none/tests/ppc64/test_isa_3_1_R1_RT.stdout.exp b/none/tests/ppc64/test_isa_3_1_R1_RT.stdout.exp index 19011bc08d..b6f17f8dcc 100644 --- a/none/tests/ppc64/test_isa_3_1_R1_RT.stdout.exp +++ b/none/tests/ppc64/test_isa_3_1_R1_RT.stdout.exp @@ -52,11 +52,11 @@ plq off8_R1 => 62d6001662b5001f 6318001862f7001f plq off16_R1 => 6318001862f7001f 635a001a6339001b -plq off32_R1 => 639c001c637b001b eac90008eaa9001b +plq off32_R1 => 639c001c637b001b eb81ffe0eae1ffbb -plq off48_R1 => eb090018eae9001a eb890038eb29003b +plq off48_R1 => 4e80003a 9000000001b -plq off64_R1 => 1111111111111111 eac90008eaa9001b +plq off64_R1 => 639c001c637b001b eb81ffe0eae1ffbb plwa off0_R1 => 4100000 @@ -82,11 +82,11 @@ plxvp off0_R1 => 6318001862f70017 635a001a63390019 ea80000004100000 62d6001662b5 plxvp off8_R1 => 635a001a63390019 639c001c637b001b 62d6001662b50015 6318001862f70017 -plxvp off16_R1 => 639c001c637b001b eac90008eaa90000 6318001862f70017 635a001a63390019 +plxvp off16_R1 => 639c001c637b001b eb81ffe0eae1ffb8 6318001862f70017 635a001a63390019 -plxvp off24_R1 => eac90008eaa90000 eb090018eae90010 635a001a63390019 639c001c637b001b +plxvp off24_R1 => eb81ffe0eae1ffb8 000000004e800020 635a001a63390019 639c001c637b001b -plxvp off32_R1 => eb090018eae90010 eb890038eb290020 639c001c637b001b eac90008eaa90000 +plxvp off32_R1 => 000000004e800020 0000090000000000 639c001c637b001b eb81ffe0eae1ffb8 pstb off0_R1 102030405060708 => 08 diff --git a/none/tests/ppc64/test_isa_3_1_R1_XT.c b/none/tests/ppc64/test_isa_3_1_R1_XT.c index 6c06ee64e4..bd30bfd62f 100644 --- a/none/tests/ppc64/test_isa_3_1_R1_XT.c +++ b/none/tests/ppc64/test_isa_3_1_R1_XT.c @@ -48,95 +48,6 @@ unsigned long current_fpscr; struct test_list_t current_test; #include "isa_3_1_helpers.h" -#ifdef __powerpc64__ -typedef uint64_t HWord_t; - -/* Save and restore all of the registers. Need to ensure the PAD_ORI does not change - the other registers. This really shouldn't be needed but the optimization gets - messed up when it inlines the test function. */ -#define SAVE_REGS(addr) \ - asm volatile( \ - " std 21, 0(%0) \n" \ - " std 22, 8(%0) \n" \ - " std 23, 16(%0) \n" \ - " std 24, 24(%0) \n" \ - " std 25, 32(%0) \n" \ - " std 26, 40(%0) \n" \ - " std 27, 48(%0) \n" \ - " std 29, 64(%0) \n" \ - " std 30, 72(%0) \n" \ - " std 31, 80(%0) \n" \ - ::"b"(addr)) - -#define SAVE_REG_28(addr) \ - asm volatile( \ - " std 28, 56(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REGS(addr) \ - asm volatile( \ - " ld 21, 0(%0) \n" \ - " ld 22, 8(%0) \n" \ - " ld 23, 16(%0) \n" \ - " ld 24, 24(%0) \n" \ - " ld 25, 32(%0) \n" \ - " ld 26, 40(%0) \n" \ - " ld 27, 48(%0) \n" \ - " ld 29, 64(%0) \n" \ - " ld 30, 72(%0) \n" \ - " ld 31, 80(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REG_28(addr) \ - asm volatile( \ - " ld 28, 56(%0) \n" \ - ::"b"(addr)) - -#else /* !__powerpc64__ */ - -typedef uint32_t HWord_t; -#define SAVE_REGS(addr) \ - asm volatile( \ - " stw 21, 0(%0) \n" \ - " stw 22, 4(%0) \n" \ - " stw 23, 8(%0) \n" \ - " stw 24, 12(%0) \n" \ - " stw 25, 16(%0) \n" \ - " stw 26, 20(%0) \n" \ - " stw 27, 24(%0) \n" \ - " stw 29, 32(%0) \n" \ - " stw 30, 36(%0) \n" \ - " stw 31, 40(%0) \n" \ - ::"b"(addr)) - -#define SAVE_REG_28(addr) \ - asm volatile( \ - " stw 28, 28(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REGS(addr) \ - asm volatile( \ - " lwz 21, 0(%0) \n" \ - " lwz 22, 4(%0) \n" \ - " lwz 23, 8(%0) \n" \ - " lwz 24, 12(%0) \n" \ - " lwz 25, 16(%0) \n" \ - " lwz 26, 20(%0) \n" \ - " lwz 27, 24(%0) \n" \ - " lwz 29, 32(%0) \n" \ - " lwz 30, 36(%0) \n" \ - " lwz 31, 400(%0) \n" \ - ::"b"(addr)) - -#define RESTORE_REG_28(addr) \ - asm volatile( \ - " lwz 28, 28(%0) \n" \ - ::"b"(addr)) -#endif /* __powerpc64__ */ - -#define NUM_ENTRIES_SAVE_RESTORE 11 - -HWord_t temp[NUM_ENTRIES_SAVE_RESTORE]; static void test_pstxvp_off0_R1 (void) { __asm__ __volatile__ ("pstxvp 20, -0x1f400+0(0),1"); @@ -151,78 +62,54 @@ static void test_pstxvp_off48_R1 (void) { __asm__ __volatile__ ("pstxvp 20, -0x1f400+48(0),1"); } static void test_plfd_64_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfd 28, +64(0), 1"); PAD_ORI PAD_ORI - RESTORE_REGS(temp); } static void test_plfd_32_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfd 28, +32(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfd_16_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfd 28, +16(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfd_8_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfd 28, +8(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfd_4_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfd 28, +4(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfd_0_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfd 28, +0(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfs_64_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfs 28, +64(0), 1"); PAD_ORI PAD_ORI - RESTORE_REGS(temp); } static void test_plfs_32_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfs 28, +32(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfs_16_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfs 28, +16(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfs_8_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfs 28, +8(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfs_4_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfs 28, +4(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_plfs_0_R1 (void) { - SAVE_REGS(temp); __asm__ __volatile__ ("plfs 28, +0(0), 1"); PAD_ORI - RESTORE_REGS(temp); } static void test_pstfd_32_R1 (void) { __asm__ __volatile__ ("pstfd 26, -0x1f400+32(0), 1"); @@ -255,102 +142,54 @@ static void test_pstfs_0_R1 (void) { __asm__ __volatile__ ("pstfs 26, -0x1f400+0(0), 1"); } static void test_plxsd_64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxsd %0, +64(0), 1" : "=v" (vrt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxsd_32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ (".align 2 ; plxsd %0, +32(0), 1" : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxsd_16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxsd %0, +16(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxsd_8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxsd %0, +8(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxsd_4_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxsd %0, +4(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxsd_0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxsd %0, +0(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxssp_64_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxssp %0, +64(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxssp_32_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxssp %0, +32(0), 1; pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxssp_16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxssp %0, +16(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxssp_8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxssp %0, +8(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxssp_4_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxssp %0, +4(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxssp_0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxssp %0, +0(0), 1; pnop;pnop;pnop; " : "=v" (vrt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } /* Follow the short-range plxv instructions with nop in order to pad out subsequent instructions. When written there are found @@ -358,36 +197,20 @@ static void test_plxssp_0_R1 (void) { into the target variable. (pla,pstxv...). */ static void test_plxv_16_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxv %x0, +16(0), 1; pnop;pnop;pnop;" : "=wa" (vec_xt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxv_8_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxv %x0, +8(0), 1; pnop;pnop;pnop;" : "=wa" (vec_xt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxv_4_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxv %x0, +4(0), 1; pnop;pnop;pnop;" : "=wa" (vec_xt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_plxv_0_R1 (void) { - SAVE_REGS(temp); - SAVE_REG_28(temp); __asm__ __volatile__ ("plxv %x0, +0(0), 1; pnop;pnop;pnop; " : "=wa" (vec_xt) ); PAD_ORI - RESTORE_REGS(temp); - RESTORE_REG_28(temp); } static void test_pstxsd_64_R1 (void) { __asm__ __volatile__ (".align 2 ; pstxsd 22, -0x1f400+64(0), 1" ); diff --git a/none/tests/ppc64/test_isa_3_1_R1_XT.stdout.exp b/none/tests/ppc64/test_isa_3_1_R1_XT.stdout.exp index cef5c773fb..fc088cecf6 100644 --- a/none/tests/ppc64/test_isa_3_1_R1_XT.stdout.exp +++ b/none/tests/ppc64/test_isa_3_1_R1_XT.stdout.exp @@ -28,7 +28,7 @@ plxsd 4_R1 => 7000000a8000004,0000000000000000 5.77662562e-275 +Zer plxsd 8_R1 => 7000000,0000000000000000 +Den +Zero -plxsd 16_R1 => 700000060000000,0000000000000000 5.77662407e-275 +Zero +plxsd 16_R1 => 7000000,0000000000000000 +Den +Zero plxsd 32_R1 => 6339001963180018,0000000000000000 9.43505226e+169 +Zero @@ -38,21 +38,21 @@ plxssp 0_R1 => 3882000000000000,0000000000000000 6.19888e-05 +Zero plxssp 4_R1 => bd80000080000000,0000000000000000 -6.25000e-02 -Zero +Zero +Zero -plxssp 8_R1 => 4400000000000000,0000000000000000 5.12000e+02 +Zero +Zero +Zero +plxssp 8_R1 => 38e0000000000000,0000000000000000 1.06812e-04 +Zero +Zero +Zero plxssp 16_R1 => 38e0000000000000,0000000000000000 1.06812e-04 +Zero +Zero +Zero plxssp 32_R1 => 445ac002c0000000,0000000000000000 8.75000e+02 -2.00000e+00 +Zero +Zero -plxssp 64_R1 => 4467200320000000,0000000000000000 9.24500e+02 1.08420e-19 +Zero +Zero +plxssp 64_R1 => 446b400340000000,0000000000000000 9.41000e+02 2.00000e+00 +Zero +Zero -plxv 0_R1 => c800000004100000 700000060000000 +plxv 0_R1 => c800000004100000 7000000 -plxv 4_R1 => 60000000c8000004 7000000 +plxv 4_R1 => 7000000c8000004 6000000000000000 -plxv 8_R1 => 700000060000000 700000000000000 +plxv 8_R1 => 7000000 7000000 -plxv 16_R1 => 700000000000000 700000000000000 +plxv 16_R1 => 7000000 7000000 pstfd 0_R1 43dfe000003fe000 43eff000000ff000 => e000003fe00043df pstfd 0_R1 43eff000000ff000 43efefffffcff000 => f000000ff00043ef @@ -86,15 +86,15 @@ pstfs 32_R1 000000005f7f8000 000000005f7f8000 => 80005f7f pstxsd 0_R1 => 0000000000000000 -pstxsd 4_R1 => 00000000 00000000 +pstxsd 4_R1 => 0000000000000000 -pstxsd 8_R1 => 0000000000000000 +pstxsd 8_R1 => 00000000 00000000 -pstxsd 16_R1 => 0000000000000000 +pstxsd 16_R1 => 00000000 00000000 -pstxsd 32_R1 => 0000000000000000 +pstxsd 32_R1 => 00000000 00000000 -pstxsd 64_R1 => 0000000000000000 +pstxsd 64_R1 => 00000000 00000000 pstxssp 0_R1 => 00000000 @@ -116,9 +116,9 @@ pstxvp off32_R1 0180055e0180077e 0080000e8080000e ff7ffffe7f7ffffe ff8000007f800 pstxvp off48_R1 0180055e0180077e 0080000e8080000e ff7ffffe7f7ffffe ff8000007f800000 => fffe7f7ffffeff7f 00007f800000ff80 077e0180055e0180 000e8080000e0080 -pstxv 0_R1 ff7ffffe7f7ffffe,ff8000007f800000 => fffe7f7ffffeff7f 00007f800000ff80 +pstxv 0_R1 ff7ffffe7f7ffffe,ff8000007f800000 => fffe7f7f fffeff7f00007f80 0000ff80 -pstxv 4_R1 ff7ffffe7f7ffffe,ff8000007f800000 => fffe7f7ffffeff7f 00007f800000ff80 +pstxv 4_R1 ff7ffffe7f7ffffe,ff8000007f800000 => fffe7f7f fffeff7f00007f80 0000ff80 pstxv 8_R1 ff7ffffe7f7ffffe,ff8000007f800000 => fffe7f7ffffeff7f 00007f800000ff80 |
|
From: Carl L. <ce...@us...> - 2023-04-19 18:31:31
|
On Wed, 2023-04-19 at 08:08 -0700, John Reiser wrote:
> >
<snip>
> On 4/18/23 12:53, Carl Love via Valgrind-developers wrote:
>
> At the lowest level, the problem is that a statement such as
> __asm__ __volatile__ ("ori 21,21,21");
Yes, that is the issue because it is using registers that the compiler
is not aware of.
> in the PAD_ORI macro of none/tests/ppc64/isa_3_1_helpers.h
> is incomplete because it does not specify the CLOBBERS portion of
> __asm__.
> [See
> https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
> e= ]
> Here is a more-complete statement that tells the compiler
> that the __asm__ scribbles on register 21:
> __asm__ __volatile__ ("ori 21,21,21"
> : /* empty: no outputs from asm to C */
> : /* empty: no inputs from C to asm */
> : "21" /* clobbers register 21 */
> );
>
I wasn't aware of the full specification on the asm command. This is
really helpful.
> Omitting the CLOBBERS is surprising because other __asm__ in the same
> file
> do use it, such as:
> __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
>
> If the CLOBBERS are specified, the the compiler automatically saves
> and
> restores the clobbered registers, if required because "callee saved"
> by the
> global usage convention.
Yup, I tried removing the SAVE_REG and RESTORE_REG macros I added and
updated the PAD_ORI macro instead. This works as you said. It does
have the added advantage of removing the modification of the fetched
register by the instructions under test which my save/restore registers
macro didn't do.
I have created an additional patch to change the fix for the tests
using your approach which I will commit shortly.
Thanks for the help.
Carl
|
|
From: Mark W. <ma...@kl...> - 2023-04-19 15:41:45
|
Hi Philippe,
On Sun, 2023-04-16 at 14:35 +0200, Philippe Waroquiers wrote:
> > > Not too sure what is going wrong/what I am doing wrong ...
> >
> > Nothing. There is something about sleepers that causes this. It also
> > happens for me. I'll try to debug it. But it works when you give vgdb
> > -d -d debug options...
> Humph, race condition/timing related bugs are hard to debug :(.
Finally found where this happens (sometimes):
diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c
index 7ed9a8b2e..2373bf335 100644
--- a/coregrind/vgdb.c
+++ b/coregrind/vgdb.c
@@ -398,7 +398,9 @@ int read_buf(int fd, char* buf, const char* desc)
{
int nrread;
DEBUG(2, "reading %s\n", desc);
- nrread = read(fd, buf, PBUFSIZ);
+ do {
+ nrread = read(fd, buf, PBUFSIZ);
+ } while (nrread == -1 && errno == EAGAIN);
if (nrread == -1) {
ERROR(errno, "error reading %s\n", desc);
return -1;
This means the pipe isn't actually ready to be read from. Which really
shouldn't happen because we do a poll on the fd to make sure we get an
POLLIN event before starting to read from it.
I'll check in the above if I cannot find a more elegant solution.
Cheers,
Mark
|
|
From: John R. <jr...@bi...> - 2023-04-19 15:08:19
|
On 4/18/23 12:53, Carl Love via Valgrind-developers wrote:
> Mark:
>
> On Mon, 2023-04-17 at 09:22 -0700, Carl Love via Valgrind-developers
> wrote:
>> The test_isa_3_1_R1_RT and test_isa_3_1_R1_XT tests seem to run
>> differently then expected. The tests generate multiple lines of
>> output
>> when only one line was expected. For example:
>
> I have pushed a fix for the two tests. The issue is the tests are
> testing load instructions that load relative to the current PC address.
> The tests of these instructions adds blocks of OR immediate
> instructions before the assembly for the instruction under test.
> Unfortunately, the test didn't save and restore the registers touched
> by the OR immediate instructions. This is fine as long as you are
> calling a function, the touched registers are volitile across a
> function call. It seems the more recent GCC is a bit more aggressive
> in inlining the test functions. However, the compiler doesn't realize
> that the inline OR immediate instructions are touching registers. The
> OR immediate instructions were inadvertently changing the value of the
> register that held the for loop variable. Thus the loops would execute
> more times then expected.
>
> The commit is:
>
> commit 20cc0680c3491e062c76605b24e76dc02e16ef47 (HEAD -> master)
> Author: Carl Love <ce...@us...>
> Date: Mon Apr 17 17:12:25 2023 -0400
>
> PowerPC:, Fix test test_isa_3_1_R1_RT.c, test_isa_3_1_R1_XT.c
>
> If the commit gets into the current release, great. If not, it is not
> an issue. The problem is completely isolated to the test case.
At the lowest level, the problem is that a statement such as
__asm__ __volatile__ ("ori 21,21,21");
in the PAD_ORI macro of none/tests/ppc64/isa_3_1_helpers.h
is incomplete because it does not specify the CLOBBERS portion of __asm__.
[See https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html ]
Here is a more-complete statement that tells the compiler
that the __asm__ scribbles on register 21:
__asm__ __volatile__ ("ori 21,21,21"
: /* empty: no outputs from asm to C */
: /* empty: no inputs from C to asm */
: "21" /* clobbers register 21 */
);
Omitting the CLOBBERS is surprising because other __asm__ in the same file
do use it, such as:
__asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
If the CLOBBERS are specified, the the compiler automatically saves and
restores the clobbered registers, if required because "callee saved" by the
global usage convention. This can be seen by compiling a test such as:
int fn2(int,int,int,int,int,int,int,int,
int,int,int,int,int,int,int,int); /* external */
int fn1(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8)
{
int b1=1, b2=2, b3=3, b4=4, b5=5, b6=6, b7=7, b8=8;
fn2(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7,a8,b8);
__asm__ __volatile__ (
"ori 21,21,21; ori 22,22,22; ori 23,23,23; ori 24,24,24"
: /* empty: no outputs from asm to C */
: /* empty: no inputs from C to asm */
: "21", "22", "23", "24" /* clobbers these registers */
);
fn2(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7,a8,b8);
}
and inspecting the generated code; I used gcc 4.9.2:
fn1:
stwu 1,-160(1)
mflr 0
stw 0,164(1)
stw 21,116(1)
stw 22,120(1)
stw 23,124(1)
stw 24,128(1)
<<snip>>
bl fn2
#APP
# 8 "asm2.c" 1
ori 21,21,21; ori 22,22,22; ori 23,23,23; ori 24,24,24
# 0 "" 2
#NO_APP
<<snip>>
lwz 21,-44(11)
lwz 22,-40(11)
lwz 23,-36(11)
lwz 24,-32(11)
lwz 31,-4(11)
mr 1,11
blr
Not specifying the CLOBBERS may be deliberate, perhaps because the
compiler's automatic save and restore interferes with some other
property of the testing. In that case, there should be a comment
in the code, such as:
/* The __asm__ CLOBBERS are omitted because auto-save and restore
* gets in the way of computing offsets between code blocks.
* Therefore we must save and restore "by hand".
*/
|
|
From: Nicholas N. <nj...@so...> - 2023-04-18 23:26:27
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=b0e9fef2019e8ccc04bfa012077e41fc5e41f5b4 commit b0e9fef2019e8ccc04bfa012077e41fc5e41f5b4 Author: Nicholas Nethercote <n.n...@gm...> Date: Mon Apr 17 09:34:11 2023 +1000 cg_annotate: Remove the `-I`/`--include` option. For much the same reasons that I removed user annotations recently: it's rarely/never used, and complicates things. Diff: --- cachegrind/cg_annotate.in | 60 +++++++-------------------------- cachegrind/tests/Makefile.am | 1 - cachegrind/tests/ann-diff1.post.exp | 1 - cachegrind/tests/ann-diff2.post.exp | 1 - cachegrind/tests/ann-merge1.post.exp | 1 - cachegrind/tests/ann1a.post.exp | 1 - cachegrind/tests/ann1b.post.exp | 1 - cachegrind/tests/ann2-aux/ann2-via-I.rs | 1 - cachegrind/tests/ann2-past-the-end.rs | 2 ++ cachegrind/tests/ann2.cgout | 11 +++--- cachegrind/tests/ann2.post.exp | 35 +++++++------------ cachegrind/tests/ann2.vgtest | 2 +- 12 files changed, 33 insertions(+), 84 deletions(-) diff --git a/cachegrind/cg_annotate.in b/cachegrind/cg_annotate.in index 0b68e094c3..5e64a94485 100755 --- a/cachegrind/cg_annotate.in +++ b/cachegrind/cg_annotate.in @@ -51,7 +51,6 @@ class Args(Namespace): show_percs: bool annotate: bool context: int - include: list[str] cgout_filename: list[str] @staticmethod @@ -142,14 +141,6 @@ class Args(Namespace): help="print N lines of context before and after annotated lines " "(default: %(default)s)", ) - p.add_argument( - "-I", - "--include", - action="append", - default=[], - metavar="D", - help="add D to the list of searched source file directories", - ) p.add_argument( "cgout_filename", nargs=1, @@ -663,14 +654,6 @@ def print_metadata(desc: str, cmd: str, events: Events) -> None: print("Events shown: ", *events.show_events) print("Event sort order:", *events.sort_events) print("Threshold: ", args.threshold) - - if len(args.include) == 0: - print("Include dirs: ") - else: - print(f"Include dirs: {args.include[0]}") - for include_dirname in args.include[1:]: - print(f" {include_dirname}") - print("Annotation: ", "on" if args.annotate else "off") print() @@ -920,40 +903,23 @@ def print_annotated_src_files( 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(src_filename: str) -> None: print_fancy(f"Annotated source file: {src_filename}") for src_filename in sorted(ann_src_filenames): - readable = False - for include_dirname in include_dirnames: - if include_dirname == "": - full_src_filename = src_filename - else: - full_src_filename = os.path.join(include_dirname, src_filename) - - 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) - 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 - except OSError: - pass - - if not readable: + try: + with open(src_filename, "r", encoding="utf-8") as src_file: + dict_line_cc = dict_fl_dict_line_cc.pop(src_filename, None) + assert dict_line_cc is not None + print_ann_fancy(src_filename) + print_annotated_src_file( + events, + dict_line_cc, + src_file, + annotated_ccs, + summary_cc, + ) + except OSError: 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) diff --git a/cachegrind/tests/Makefile.am b/cachegrind/tests/Makefile.am index 0c7219a9bc..d38d300b90 100644 --- a/cachegrind/tests/Makefile.am +++ b/cachegrind/tests/Makefile.am @@ -24,7 +24,6 @@ EXTRA_DIST = \ ann2.post.exp ann2.stderr.exp ann2.vgtest ann2.cgout \ ann2-basic.rs ann2-more-recent-than-cgout.rs \ ann2-negatives.rs ann2-past-the-end.rs \ - ann2-aux/ann2-via-I.rs \ chdir.vgtest chdir.stderr.exp \ clreq.vgtest clreq.stderr.exp \ dlclose.vgtest dlclose.stderr.exp dlclose.stdout.exp \ diff --git a/cachegrind/tests/ann-diff1.post.exp b/cachegrind/tests/ann-diff1.post.exp index 4e13f0c089..54962b513d 100644 --- a/cachegrind/tests/ann-diff1.post.exp +++ b/cachegrind/tests/ann-diff1.post.exp @@ -8,7 +8,6 @@ Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Events shown: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Threshold: 0.1 -Include dirs: Annotation: on -------------------------------------------------------------------------------- diff --git a/cachegrind/tests/ann-diff2.post.exp b/cachegrind/tests/ann-diff2.post.exp index bcf09ea9ca..e1060dbd23 100644 --- a/cachegrind/tests/ann-diff2.post.exp +++ b/cachegrind/tests/ann-diff2.post.exp @@ -8,7 +8,6 @@ Events recorded: One Two Events shown: One Two Event sort order: One Two Threshold: 0.1 -Include dirs: Annotation: on -------------------------------------------------------------------------------- diff --git a/cachegrind/tests/ann-merge1.post.exp b/cachegrind/tests/ann-merge1.post.exp index f12f1c235d..1f47332b8a 100644 --- a/cachegrind/tests/ann-merge1.post.exp +++ b/cachegrind/tests/ann-merge1.post.exp @@ -9,7 +9,6 @@ Events recorded: A Events shown: A Event sort order: A Threshold: 0.1 -Include dirs: Annotation: on -------------------------------------------------------------------------------- diff --git a/cachegrind/tests/ann1a.post.exp b/cachegrind/tests/ann1a.post.exp index a83767cb0a..bde53e6501 100644 --- a/cachegrind/tests/ann1a.post.exp +++ b/cachegrind/tests/ann1a.post.exp @@ -10,7 +10,6 @@ Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Events shown: Ir I1mr ILmr Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Threshold: 0.1 -Include dirs: Annotation: on -------------------------------------------------------------------------------- diff --git a/cachegrind/tests/ann1b.post.exp b/cachegrind/tests/ann1b.post.exp index b76b4236f2..3ec4288cb4 100644 --- a/cachegrind/tests/ann1b.post.exp +++ b/cachegrind/tests/ann1b.post.exp @@ -10,7 +10,6 @@ Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw Events shown: Dw Dr Ir Event sort order: Dr Threshold: 0.1 -Include dirs: Annotation: off -------------------------------------------------------------------------------- diff --git a/cachegrind/tests/ann2-aux/ann2-via-I.rs b/cachegrind/tests/ann2-aux/ann2-via-I.rs deleted file mode 100644 index 5626abf0f7..0000000000 --- a/cachegrind/tests/ann2-aux/ann2-via-I.rs +++ /dev/null @@ -1 +0,0 @@ -one diff --git a/cachegrind/tests/ann2-past-the-end.rs b/cachegrind/tests/ann2-past-the-end.rs index 4cb29ea38f..b2f931a673 100644 --- a/cachegrind/tests/ann2-past-the-end.rs +++ b/cachegrind/tests/ann2-past-the-end.rs @@ -1,3 +1,5 @@ one two three +four +five diff --git a/cachegrind/tests/ann2.cgout b/cachegrind/tests/ann2.cgout index b5d62b1806..2be80fe1ea 100644 --- a/cachegrind/tests/ann2.cgout +++ b/cachegrind/tests/ann2.cgout @@ -71,9 +71,11 @@ fn=neg4 # File with source newer than the cgout file. fl=ann2-past-the-end.rs -# This filename is repeated in ann2-could-not-be-found.rs above. +# No `fn=` line yet, so the function name falls back to `<unspecified>`. +1 1000 500 0 +# This funcname is repeated in ann2-could-not-be-found.rs above. fn=f1 -1 200 100 0 +2 200 100 0 20 300 100 0 21 300 100 0 22 200 0 -1000 @@ -85,11 +87,6 @@ fn=f1 101 3000 2000 0 102 3000 2000 0 -# File found in ann2-aux/, via -I. -fl=ann2-via-I.rs -# No `fn=` line, so the function name falls back to `<unspecified>`. -1 1000 500 0 - # File below the threshold. (It also doesn't exist, but that doesn't matter. We # don't try to open it because it's below the threshold.) fl=ann2-below-threshold.rs diff --git a/cachegrind/tests/ann2.post.exp b/cachegrind/tests/ann2.post.exp index 5cfdbfd1df..8db35f136f 100644 --- a/cachegrind/tests/ann2.post.exp +++ b/cachegrind/tests/ann2.post.exp @@ -7,9 +7,6 @@ Events recorded: A SomeCount VeryLongEventName Events shown: A SomeCount VeryLongEventName Event sort order: A SomeCount VeryLongEventName Threshold: 0.5 -Include dirs: ann2-no-such-dir - ann2-no-such-dir-2 - ann2-aux Annotation: on -------------------------------------------------------------------------------- @@ -33,9 +30,9 @@ A_______________ SomeCount_______ VeryLongEventName > 9,000 (9.0%, 95.6%) 6,000 (6.0%, 99.0%) 0 (n/a, n/a) ann2-could-not-be-found.rs:f1 -> 1,000 (1.0%, 96.6%) 500 (0.5%, 99.5%) 0 (n/a, n/a) ann2-via-I.rs:<unspecified> - -> 1,000 (1.0%, 97.6%) 300 (0.3%, 99.8%) -1,000 (n/a, n/a) ann2-past-the-end.rs:f1 +> 2,000 (2.0%, 97.6%) 800 (0.8%, 99.8%) -1,000 (n/a, n/a) ann2-past-the-end.rs: + 1,000 (1.0%) 500 (0.5%) 0 <unspecified> + 1,000 (1.0%) 300 (0.3%) -1,000 (n/a) f1 > 1,000 (1.0%, 98.6%) 0 (0.0%, 99.8%) 0 (n/a, n/a) ann2-more-recent-than-cgout.rs:new @@ -66,7 +63,7 @@ A_______________ SomeCount_______ VeryLongEventName > 2,000 (2.0%, 95.1%) 100 (0.1%, 97.3%) 0 (n/a, n/a) f2:ann2-basic.rs -> 1,000 (1.0%, 96.1%) 500 (0.5%, 97.8%) 0 (n/a, n/a) <unspecified>:ann2-via-I.rs +> 1,000 (1.0%, 96.1%) 500 (0.5%, 97.8%) 0 (n/a, n/a) <unspecified>:ann2-past-the-end.rs > 1,000 (1.0%, 97.1%) 0 (0.0%, 97.8%) 0 (n/a, n/a) unknown:??? @@ -154,16 +151,17 @@ A____________________ SomeCount_____ VeryLongEventName -------------------------------------------------------------------------------- -- Annotated source file: ann2-past-the-end.rs -------------------------------------------------------------------------------- -A_________ SomeCount_ VeryLongEventName +A___________ SomeCount_ VeryLongEventName -200 (0.2%) 100 (0.1%) 0 one - . . . two - . . . three --- line 3 ---------------------------------------- +1,000 (1.0%) 500 (0.5%) 0 one + 200 (0.2%) 100 (0.1%) 0 two + . . . three + . . . four +-- line 4 ---------------------------------------- -300 (0.3%) 100 (0.1%) 0 <bogus line 20> -300 (0.3%) 100 (0.1%) 0 <bogus line 21> -200 (0.2%) 0 -1,000 (n/a) <bogus line 22> + 300 (0.3%) 100 (0.1%) 0 <bogus line 20> + 300 (0.3%) 100 (0.1%) 0 <bogus line 21> + 200 (0.2%) 0 -1,000 (n/a) <bogus line 22> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ WARNING @@ @@ -171,13 +169,6 @@ A_________ SomeCount_ VeryLongEventName @@ Information recorded about lines past the end of 'ann2-past-the-end.rs'. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ --------------------------------------------------------------------------------- --- Annotated source file: ann2-aux/ann2-via-I.rs --------------------------------------------------------------------------------- -A___________ SomeCount_ VeryLongEventName - -1,000 (1.0%) 500 (0.5%) 0 one - -------------------------------------------------------------------------------- -- Annotation summary -------------------------------------------------------------------------------- diff --git a/cachegrind/tests/ann2.vgtest b/cachegrind/tests/ann2.vgtest index 9fb0d1b86f..4add2fe4cc 100644 --- a/cachegrind/tests/ann2.vgtest +++ b/cachegrind/tests/ann2.vgtest @@ -8,6 +8,6 @@ vgopts: --cachegrind-out-file=cachegrind.out # The `sleep` is to ensure the mtime of the second touched file is greater than # the mtime of the first touched file. -post: touch ann2.cgout && sleep 0.1 && touch ann2-more-recent-than-cgout.rs && python3 ../cg_annotate --context 2 --annotate --show-percs=yes --threshold=0.5 -Iann2-no-such-dir --include ann2-no-such-dir-2 -I=ann2-aux ann2.cgout +post: touch ann2.cgout && sleep 0.1 && touch ann2-more-recent-than-cgout.rs && python3 ../cg_annotate --context 2 --annotate --show-percs=yes --threshold=0.5 ann2.cgout cleanup: rm cachegrind.out |