]> sourceware.org Git - valgrind.git/commitdiff
Add some client requests to Cachegrind.
authorNicholas Nethercote <n.nethercote@gmail.com>
Thu, 10 Aug 2023 04:10:36 +0000 (14:10 +1000)
committerNicholas Nethercote <n.nethercote@gmail.com>
Thu, 14 Sep 2023 00:51:19 +0000 (10:51 +1000)
14 files changed:
NEWS
cachegrind/Makefile.am
cachegrind/cachegrind.h [new file with mode: 0644]
cachegrind/cg_main.c
cachegrind/docs/cg-manual.xml
cachegrind/tests/Makefile.am
cachegrind/tests/clreq2.c [new file with mode: 0644]
cachegrind/tests/clreq2a.stderr.exp [new file with mode: 0644]
cachegrind/tests/clreq2a.vgtest [new file with mode: 0644]
cachegrind/tests/clreq2b.stderr.exp [new file with mode: 0644]
cachegrind/tests/clreq2b.vgtest [new file with mode: 0644]
cachegrind/tests/clreq3.stderr.exp [new file with mode: 0644]
cachegrind/tests/clreq3.vgtest [new file with mode: 0644]
cachegrind/tests/filter_clreq3 [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index da6f4f816ab70053d0308e6e4732030986a45a8f..b4a9dfd1e437c5f4c2a8dba7c818c2b445622612 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,12 @@ AMD64/macOS 10.13 and nanoMIPS/Linux.
   - bad size for functions that have implementation defined behaviour
     when the requested size is zero
 
+* Cachegrind:
+  - You can now profile part of a program's execution using the new
+    `CACHEGRIND_START_INSTRUMENTATION` and `CACHEGRIND_STOP_INSTRUMENTATION`
+    client requests, along with the new `--instr-at-start` option. The
+    behaviour is the same as Callgrind's equivalent functionality.
+
 * ==================== FIXED BUGS ====================
 
 The following bugs have been fixed or resolved.  Note that "n-i-bz"
index 0e0ef12b4d91714ce06b3072659491caedd57447..6ab8fbad90f5f4de9c2d152ae71ae07568a134f5 100644 (file)
@@ -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 (file)
index 0000000..ddc10ab
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+   ----------------------------------------------------------------
+
+   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 {
+      /* The `CG_` is required to distinguish these from the Callgrind
+       * client requests of the same name. Otherwise compile errors occur if
+       * you include both `cachegrind.h` and `callgrind.h`.
+       */
+      VG_USERREQ__CG_START_INSTRUMENTATION = VG_USERREQ_TOOL_BASE('C','G'),
+      VG_USERREQ__CG_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__CG_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__CG_STOP_INSTRUMENTATION, \
+                                  0, 0, 0, 0, 0)
+
+#endif /* __CACHEGRIND_H */
+
index d8e476adcbfc19656a93a0abe0fee6aa24008f15..d232e3d748e0ab2d1def861d61cf2a0c5fdcb1b1 100644 (file)
@@ -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
 #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=<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__CG_START_INSTRUMENTATION:
+      set_instr_enabled(True);
+      *ret = 0;
+      return True;
+
+   case VG_USERREQ__CG_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)
index a14cd7c9260f8d0e4ce7e7496d69d50f1867e1bd..711b537bb0259bd89c4fb58f9937444212f112a3 100644 (file)
@@ -876,6 +876,21 @@ Cachegrind-specific options are:
     </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.instr-at-start" xreflabel="--instr-at-start">
+    <term>
+      <option><![CDATA[--instr-at-start=no|yes [yes] ]]></option>
+    </term>
+    <listitem>
+      <para>
+      Enables or disables instrumentation at the start of execution.
+      Use this in combination with
+      <computeroutput>CACHEGRIND_START_INSTRUMENTATION</computeroutput> and
+      <computeroutput>CACHEGRIND_STOP_INSTRUMENTATION</computeroutput> to
+      measure only part of a client program's execution.
+      </para>
+    </listitem>
+  </varlistentry>
+
   <varlistentry id="cg.opt.I1" xreflabel="--I1">
     <term>
       <option><![CDATA[--I1=<size>,<associativity>,<line size> ]]></option>
@@ -1139,6 +1154,48 @@ Cachegrind-specific options are:
 </sect1>
 
 
+<sect1 id="cg-manual.clientrequests" xreflabel="Client requests">
+<title>Cachegrind Client Requests</title>
+
+<para>Cachegrind provides the following client requests in
+<filename>cachegrind.h</filename>.
+</para>
+
+<variablelist id="cg.clientrequests.list">
+
+  <varlistentry id="cg.cr.start-instr" xreflabel="CACHEGRIND_START_INSTRUMENTATION">
+    <term>
+      <computeroutput>CACHEGRIND_START_INSTRUMENTATION</computeroutput>
+    </term>
+    <listitem>
+      <para>Start Cachegrind instrumentation if not already enabled. Use this
+      in combination with
+      <computeroutput>CACHEGRIND_STOP_INSTRUMENTATION</computeroutput> and
+      <option><link linkend="opt.instr-at-start">--instr-at-start</link></option>
+      to measure only part of a client program's execution.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry id="cg.cr.stop-instr" xreflabel="CACHEGRIND_STOP_INSTRUMENTATION">
+    <term>
+      <computeroutput>CACHEGRIND_STOP_INSTRUMENTATION</computeroutput>
+    </term>
+    <listitem>
+      <para>Stop Cachegrind instrumentation if not already disabled. Use this
+      in combination with
+      <computeroutput>CACHEGRIND_START_INSTRUMENTATION</computeroutput> and
+      <option><link linkend="opt.instr-at-start">--instr-at-start</link></option>
+      to measure only part of a client program's execution.
+      </para>
+    </listitem>
+  </varlistentry>
+
+</variablelist>
+
+</sect1>
+
+
 <sect1 id="cg-manual.sim-details"
        xreflabel="Simulation Details">
 <title>Simulation Details</title>
index 9b977d58106d3d5a575803c8ef2b3602dfc94e15..33242dfb9d12a72bec823b0a8a81a26e2f7a3c74 100644 (file)
@@ -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 (file)
index 0000000..842ee2f
--- /dev/null
@@ -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 (file)
index 0000000..49527c8
--- /dev/null
@@ -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 (file)
index 0000000..e5fa8ef
--- /dev/null
@@ -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 (file)
index 0000000..3219696
--- /dev/null
@@ -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 (file)
index 0000000..8f77f3c
--- /dev/null
@@ -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 (file)
index 0000000..97f8c23
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+I refs:        0
diff --git a/cachegrind/tests/clreq3.vgtest b/cachegrind/tests/clreq3.vgtest
new file mode 100644 (file)
index 0000000..fc69947
--- /dev/null
@@ -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 (executable)
index 0000000..6c7f0ac
--- /dev/null
@@ -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 high-precision tracing profiler/ , /./ d"
This page took 0.053598 seconds and 5 git commands to generate.