From: Nicholas Nethercote Date: Thu, 10 Aug 2023 04:10:36 +0000 (+1000) Subject: Add some client requests to Cachegrind. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fusers%2Fnjn%2Ftry-cachegrind-cl-reqs;p=thirdparty%2Fvalgrind.git Add some client requests to Cachegrind. --- diff --git a/cachegrind/Makefile.am b/cachegrind/Makefile.am index 0e0ef12b4d..6ab8fbad90 100644 --- a/cachegrind/Makefile.am +++ b/cachegrind/Makefile.am @@ -10,6 +10,8 @@ EXTRA_DIST = \ # Headers, etc #---------------------------------------------------------------------------- +pkginclude_HEADERS = cachegrind.h + bin_SCRIPTS = cg_annotate cg_diff cg_merge noinst_HEADERS = \ diff --git a/cachegrind/cachegrind.h b/cachegrind/cachegrind.h new file mode 100644 index 0000000000..a4308dbecf --- /dev/null +++ b/cachegrind/cachegrind.h @@ -0,0 +1,94 @@ +/* + ---------------------------------------------------------------- + + Notice that the following BSD-style license applies to this one + file (cachegrind.h) only. The rest of Valgrind is licensed under the + terms of the GNU General Public License, version 2, unless + otherwise indicated. See the COPYING file in the source + distribution for details. + + ---------------------------------------------------------------- + + This file is part of Cachegrind, a high-precision tracing profiler + built with Valgrind. + + Copyright (C) 2023-2023 Nicholas Nethercote. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------- + + Notice that the above BSD-style license applies to this one file + (cachegrind.h) only. The entire rest of Valgrind is licensed under + the terms of the GNU General Public License, version 2. See the + COPYING file in the source distribution for details. + + ---------------------------------------------------------------- +*/ + +#ifndef __CACHEGRIND_H +#define __CACHEGRIND_H + +#include "valgrind.h" + +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! + This enum comprises an ABI exported by Valgrind to programs + which use client requests. DO NOT CHANGE THE ORDER OF THESE + ENTRIES, NOR DELETE ANY -- add new ones at the end. + */ + +typedef + enum { + VG_USERREQ__START_INSTRUMENTATION = VG_USERREQ_TOOL_BASE('C','G'), + VG_USERREQ__STOP_INSTRUMENTATION + } Vg_CachegrindClientRequest; + +/* Start Cachegrind instrumentation if not already enabled. Use this + * in combination with `CACHEGRIND_STOP_INSTRUMENTATION` and + * `--instr-at-start` to measure only part of a client program's + * execution. + */ +#define CACHEGRIND_START_INSTRUMENTATION \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__START_INSTRUMENTATION, \ + 0, 0, 0, 0, 0) + +/* Stop Cachegrind instrumentation if not already disabled. Use this + * in combination with `CACHEGRIND_START_INSTRUMENTATION` and + * `--instr-at-start` to measure only part of a client program's + * execution. + */ +#define CACHEGRIND_STOP_INSTRUMENTATION \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STOP_INSTRUMENTATION, \ + 0, 0, 0, 0, 0) + +#endif /* __CACHEGRIND_H */ + diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c index d8e476adcb..af79b92ce3 100644 --- a/cachegrind/cg_main.c +++ b/cachegrind/cg_main.c @@ -8,7 +8,7 @@ This file is part of Cachegrind, a high-precision tracing profiler built with Valgrind. - Copyright (C) 2002-2017 Nicholas Nethercote + Copyright (C) 2002-2023 Nicholas Nethercote njn@valgrind.org This program is free software; you can redistribute it and/or @@ -38,10 +38,12 @@ #include "pub_tool_options.h" #include "pub_tool_oset.h" #include "pub_tool_tooliface.h" +#include "pub_tool_transtab.h" #include "pub_tool_xarray.h" #include "pub_tool_clientstate.h" #include "pub_tool_machine.h" // VG_(fnptr_to_fnentry) +#include "cachegrind.h" #include "cg_arch.h" #include "cg_sim.c" #include "cg_branchpred.c" @@ -59,6 +61,7 @@ static Bool clo_cache_sim = False; /* do cache simulation? */ static Bool clo_branch_sim = False; /* do branch simulation? */ +static Bool clo_instr_at_start = True; /* instrument at startup? */ static const HChar* clo_cachegrind_out_file = "cachegrind.out.%p"; /*------------------------------------------------------------*/ @@ -177,6 +180,10 @@ static Int file_line_debugs = 0; static Int fn_debugs = 0; static Int no_debugs = 0; +//------------------------------------------------------------ +// Instrumentation control +static Bool instr_enabled = True; + /*------------------------------------------------------------*/ /*--- String table operations ---*/ /*------------------------------------------------------------*/ @@ -1061,6 +1068,10 @@ IRSB* cg_instrument ( VgCallbackClosure* closure, VG_(tool_panic)("host/guest word size mismatch"); } + if (!instr_enabled) { + return sbIn; + } + // Set up new SB cgs.sbOut = deepCopyIRSBExceptStmts(sbIn); @@ -1722,8 +1733,7 @@ static void cg_fini(Int exitcode) static void cg_discard_superblock_info ( Addr orig_addr64, VexGuestExtents vge ) { - SB_info* sbInfo; - Addr orig_addr = vge.base[0]; + Addr orig_addr = vge.base[0]; tl_assert(vge.n_used > 0); @@ -1732,11 +1742,17 @@ void cg_discard_superblock_info ( Addr orig_addr64, VexGuestExtents vge ) (void*)orig_addr, (void*)vge.base[0], (ULong)vge.len[0]); - // Get BB info, remove from table, free BB info. Simple! Note that we - // use orig_addr, not the first instruction address in vge. - sbInfo = VG_(OSetGen_Remove)(instrInfoTable, &orig_addr); - tl_assert(NULL != sbInfo); - VG_(OSetGen_FreeNode)(instrInfoTable, sbInfo); + // Get SB info, remove from table, free SB info. Simple! Unless + // instrumentation is currently disabled, in which case we won't have an SB + // info. Note that we use orig_addr, not the first instruction address in + // `vge`. + SB_info* sbInfo = VG_(OSetGen_Remove)(instrInfoTable, &orig_addr); + if (sbInfo) { + tl_assert(instr_enabled); + VG_(OSetGen_FreeNode)(instrInfoTable, sbInfo); + } else { + tl_assert(!instr_enabled); + } } /*--------------------------------------------------------------------*/ @@ -1753,6 +1769,7 @@ static Bool cg_process_cmd_line_option(const HChar* arg) else if VG_STR_CLO( arg, "--cachegrind-out-file", clo_cachegrind_out_file) {} else if VG_BOOL_CLO(arg, "--cache-sim", clo_cache_sim) {} else if VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim) {} + else if VG_BOOL_CLO(arg, "--instr-at-start", clo_instr_at_start) {} else return False; @@ -1765,6 +1782,7 @@ static void cg_print_usage(void) " --cachegrind-out-file= output file name [cachegrind.out.%%p]\n" " --cache-sim=yes|no collect cache stats? [no]\n" " --branch-sim=yes|no collect branch prediction stats? [no]\n" +" --instr-at-start=yes|no instrument at start? [yes]\n" ); VG_(print_cache_clo_opts)(); } @@ -1776,6 +1794,59 @@ static void cg_print_debug_usage(void) ); } +/*--------------------------------------------------------------------*/ +/*--- Client requests ---*/ +/*--------------------------------------------------------------------*/ + +static void set_instr_enabled(Bool enable) +{ + if (enable) { + // Enable instrumentation. + if (!instr_enabled) { + // Discard first, then update `instr_enabled`; + // `cg_discard_superblock_info` relies on that. + VG_(discard_translations_safely)((Addr)0x1000, ~(SizeT)0xfff, "cachegrind"); + instr_enabled = True; + } else { + VG_(dmsg)("warning: CACHEGRIND_START_INSTRUMENTATION called,\n"); + VG_(dmsg)(" but instrumentation is already enabled\n"); + } + } else { + // Disable instrumentation. + if (instr_enabled) { + // Discard first, then update `instr_enabled`; + // `cg_discard_superblock_info` relies on that. + VG_(discard_translations_safely)((Addr)0x1000, ~(SizeT)0xfff, "cachegrind"); + instr_enabled = False; + } else { + VG_(dmsg)("warning: CACHEGRIND_STOP_INSTRUMENTATION called,\n"); + VG_(dmsg)(" but instrumentation is already disabled\n"); + } + } +} + +static Bool cg_handle_client_request(ThreadId tid, UWord *args, UWord *ret) +{ + if (!VG_IS_TOOL_USERREQ('C', 'G', args[0]) + && VG_USERREQ__GDB_MONITOR_COMMAND != args[0]) + return False; + + switch(args[0]) { + case VG_USERREQ__START_INSTRUMENTATION: + set_instr_enabled(True); + *ret = 0; + return True; + + case VG_USERREQ__STOP_INSTRUMENTATION: + set_instr_enabled(False); + *ret = 0; + return True; + + default: + return False; + } +} + /*--------------------------------------------------------------------*/ /*--- Setup ---*/ /*--------------------------------------------------------------------*/ @@ -1804,6 +1875,7 @@ static void cg_pre_clo_init(void) VG_(needs_command_line_options)(cg_process_cmd_line_option, cg_print_usage, cg_print_debug_usage); + VG_(needs_client_requests)(cg_handle_client_request); } static void cg_post_clo_init(void) @@ -1854,6 +1926,12 @@ static void cg_post_clo_init(void) cachesim_initcaches(I1c, D1c, LLc); } + + // When instrumentation client requests are enabled, we start with + // instrumentation off. + if (!clo_instr_at_start) { + instr_enabled = False; + } } VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init) diff --git a/cachegrind/docs/cg-manual.xml b/cachegrind/docs/cg-manual.xml index a14cd7c926..711b537bb0 100644 --- a/cachegrind/docs/cg-manual.xml +++ b/cachegrind/docs/cg-manual.xml @@ -876,6 +876,21 @@ Cachegrind-specific options are: + + + + + + + Enables or disables instrumentation at the start of execution. + Use this in combination with + CACHEGRIND_START_INSTRUMENTATION and + CACHEGRIND_STOP_INSTRUMENTATION to + measure only part of a client program's execution. + + + + @@ -1139,6 +1154,48 @@ Cachegrind-specific options are: + +Cachegrind Client Requests + +Cachegrind provides the following client requests in +cachegrind.h. + + + + + + + CACHEGRIND_START_INSTRUMENTATION + + + Start Cachegrind instrumentation if not already enabled. Use this + in combination with + CACHEGRIND_STOP_INSTRUMENTATION and + + to measure only part of a client program's execution. + + + + + + + CACHEGRIND_STOP_INSTRUMENTATION + + + Stop Cachegrind instrumentation if not already disabled. Use this + in combination with + CACHEGRIND_START_INSTRUMENTATION and + + to measure only part of a client program's execution. + + + + + + + + + Simulation Details diff --git a/cachegrind/tests/Makefile.am b/cachegrind/tests/Makefile.am index 9b977d5810..33242dfb9d 100644 --- a/cachegrind/tests/Makefile.am +++ b/cachegrind/tests/Makefile.am @@ -8,7 +8,10 @@ endif DIST_SUBDIRS = x86 . -dist_noinst_SCRIPTS = filter_stderr filter_cachesim_discards +dist_noinst_SCRIPTS = \ + filter_stderr \ + filter_cachesim_discards \ + filter_clreq3 # Note that `test.c` and `a.c` are not compiled. # They just serve as input for cg_annotate in `ann1a` and `ann1b`. @@ -34,13 +37,16 @@ EXTRA_DIST = \ ann2-negatives.rs ann2-past-the-end.rs \ chdir.vgtest chdir.stderr.exp \ clreq.vgtest clreq.stderr.exp \ + clreq2a.vgtest clreq2a.stderr.exp \ + clreq2b.vgtest clreq2b.stderr.exp \ + clreq3.vgtest clreq3.stderr.exp \ dlclose.vgtest dlclose.stderr.exp dlclose.stdout.exp \ notpower2.vgtest notpower2.stderr.exp \ test.c a.c \ wrap5.vgtest wrap5.stderr.exp wrap5.stdout.exp check_PROGRAMS = \ - chdir clreq dlclose myprint.so + chdir clreq clreq2 dlclose myprint.so AM_CFLAGS += $(AM_FLAG_M3264_PRI) AM_CXXFLAGS += $(AM_FLAG_M3264_PRI) diff --git a/cachegrind/tests/clreq2.c b/cachegrind/tests/clreq2.c new file mode 100644 index 0000000000..842ee2ffd9 --- /dev/null +++ b/cachegrind/tests/clreq2.c @@ -0,0 +1,14 @@ +// This is not a thorough test, but at least it's something. It's hard to do +// much better because the exact number of instructions executed is +// unpredictable. + +#include "../cachegrind.h" + +int main(void) { + CACHEGRIND_START_INSTRUMENTATION; // warning with `--instr-at-start=yes` + CACHEGRIND_STOP_INSTRUMENTATION; + CACHEGRIND_START_INSTRUMENTATION; + CACHEGRIND_START_INSTRUMENTATION; // warning + CACHEGRIND_STOP_INSTRUMENTATION; + CACHEGRIND_STOP_INSTRUMENTATION; // warning +} diff --git a/cachegrind/tests/clreq2a.stderr.exp b/cachegrind/tests/clreq2a.stderr.exp new file mode 100644 index 0000000000..49527c8b66 --- /dev/null +++ b/cachegrind/tests/clreq2a.stderr.exp @@ -0,0 +1,6 @@ +warning: CACHEGRIND_START_INSTRUMENTATION called, + but instrumentation is already enabled +warning: CACHEGRIND_START_INSTRUMENTATION called, + but instrumentation is already enabled +warning: CACHEGRIND_STOP_INSTRUMENTATION called, + but instrumentation is already disabled diff --git a/cachegrind/tests/clreq2a.vgtest b/cachegrind/tests/clreq2a.vgtest new file mode 100644 index 0000000000..e5fa8efc09 --- /dev/null +++ b/cachegrind/tests/clreq2a.vgtest @@ -0,0 +1,3 @@ +prog: clreq2 +vgopts: -q --instr-at-start=yes +cleanup: rm cachegrind.out.* diff --git a/cachegrind/tests/clreq2b.stderr.exp b/cachegrind/tests/clreq2b.stderr.exp new file mode 100644 index 0000000000..3219696d46 --- /dev/null +++ b/cachegrind/tests/clreq2b.stderr.exp @@ -0,0 +1,4 @@ +warning: CACHEGRIND_START_INSTRUMENTATION called, + but instrumentation is already enabled +warning: CACHEGRIND_STOP_INSTRUMENTATION called, + but instrumentation is already disabled diff --git a/cachegrind/tests/clreq2b.vgtest b/cachegrind/tests/clreq2b.vgtest new file mode 100644 index 0000000000..8f77f3c3a4 --- /dev/null +++ b/cachegrind/tests/clreq2b.vgtest @@ -0,0 +1,3 @@ +prog: clreq2 +vgopts: -q --instr-at-start=no +cleanup: rm cachegrind.out.* diff --git a/cachegrind/tests/clreq3.stderr.exp b/cachegrind/tests/clreq3.stderr.exp new file mode 100644 index 0000000000..97f8c23e95 --- /dev/null +++ b/cachegrind/tests/clreq3.stderr.exp @@ -0,0 +1,3 @@ + + +I refs: 0 diff --git a/cachegrind/tests/clreq3.vgtest b/cachegrind/tests/clreq3.vgtest new file mode 100644 index 0000000000..fc69947b9c --- /dev/null +++ b/cachegrind/tests/clreq3.vgtest @@ -0,0 +1,5 @@ +# Test that `--instr-at-start=no` results in zero instruction counts. +prog: ../../tests/true +vgopts: --instr-at-start=no +stderr_filter: filter_clreq3 +cleanup: rm cachegrind.out.* diff --git a/cachegrind/tests/filter_clreq3 b/cachegrind/tests/filter_clreq3 new file mode 100755 index 0000000000..69d21d2f15 --- /dev/null +++ b/cachegrind/tests/filter_clreq3 @@ -0,0 +1,8 @@ +#! /bin/sh + +dir=`dirname $0` + +$dir/../../tests/filter_stderr_basic | + +# Remove "Cachegrind, ..." line and the following copyright line. +sed "/^Cachegrind, a cache and branch-prediction profiler/ , /./ d"