Am 29.07.2016 um 13:03 schrieb Patrick Bos:
I can search for the patch and send it to you.

If it's not too much trouble, that would be wonderful! Looking forward to 
receiving it. I'm not too concerned about scaling, so anything you have would 
be great.

Attached. It should apply to current SVN version (probably also last VG release).

Note that this patch only uses "Int v = sp[sep->parnum];" (search for it in the patch) to access the parnum'th (4-byte) integer parameter of a function, with sp being the
stack pointer at function entry.

This only works with x86 (32bit). Look up the C ABI calling conventions to see how to get at parameters for amd64. amd64 uses registers to pass 1st 6 integer values. Register values can be found in the architecture state struct "ThreadArchState arch", which can be accessed via "VG_(threads)[tid].arch" in tool functions, tid is the current thread ID. For example, for amd64 and register RDI, which holds the first integer parameter (I would assume this to map to the "this" pointer with C++), this
should be
   VG_(threads)[tid].arch.vex.guest_RDI

This should make it very easy to accomplish what you want.

Cheers,
Josef


commit c491556702cc3e6f6ebf34c838ce44c91ef9c259
Author: Josef Weidendorfer <josef.weidendor...@gmx.de>
Date:   Thu Jun 11 16:13:36 2009 +0200

    Parameter sensitive profiling
    
    This works by creating a new fn_node with a name specifying the
    parameter condition when we match a configuration for parameter separation.
    Command line format is
    
     --separate-par=<fn_pattern>':'<intpar_num>[':'<intval>(','<intval>)*]
    
    If no value is given, separate by every different value
    Otherwise, this allows for multiple buckets:
    
       x < intval1, intval1 < x <= intval2, ... , intvalX <= x
    
    with x being the <intpar_num>s int parameter of functions
    matching fn_pattern.
    Multiple seppar requests for same function are allowed
    
    TODO: merge seppar for same parameter number, sort according par.number
    
    (originally written by Til Kuestner)

diff --git a/callgrind/bbcc.c b/callgrind/bbcc.c
index e9426e5..47342f8 100644
--- a/callgrind/bbcc.c
+++ b/callgrind/bbcc.c
@@ -781,7 +781,12 @@ void CLG_(setup_bbcc)(BB* bb)
   
   /* Change new context if needed, taking delayed_push into account */
   if ((delayed_push && !skip) || (CLG_(current_state).cxt == 0)) {
-    CLG_(push_cxt)(CLG_(get_fn_node)(bb));
+      fn_node* node = CLG_(get_fn_node)(bb);
+
+      if (node->separate_parameters)
+         node = CLG_(get_par_fn_node)(node, (Int*) sp);
+
+      CLG_(push_cxt)(node);
   }
   CLG_ASSERT(CLG_(current_fn_stack).top > CLG_(current_fn_stack).bottom);
   
diff --git a/callgrind/clo.c b/callgrind/clo.c
index fa76f1e..852951e 100644
--- a/callgrind/clo.c
+++ b/callgrind/clo.c
@@ -56,6 +56,9 @@ struct _fn_config {
     Int separate_callers;    /* separate logging dependent on caller  */
     Int separate_recursions; /* separate logging of rec. levels       */
 
+    /* separate logging dependent on function parameters */
+    fn_sep_param* separate_parameters;
+
 #if CLG_ENABLE_DEBUG
     Int verbosity; /* Change debug verbosity level while in function */
 #endif
@@ -71,7 +74,7 @@ struct _fn_config {
  *  - "*::print(" matches C++ methods "print" in all classes
  *    without namespace. I.e. "*" doesn't match a "::".
  *
- * We build a trie from patterns, and for a given function, we
+ * We build a hash trie from patterns, and for a given function, we
  * go down the tree and apply all non-default configurations.
  */
 
@@ -110,6 +113,7 @@ fn_config* new_fnc(void)
    fnc->group        = CONFIG_DEFAULT;
    fnc->separate_callers    = CONFIG_DEFAULT;
    fnc->separate_recursions = CONFIG_DEFAULT;
+   fnc->separate_parameters = NULL;
 
 #if CLG_ENABLE_DEBUG
    fnc->verbosity    = CONFIG_DEFAULT;
@@ -313,7 +317,12 @@ static fn_config* get_fnc(const HChar* name)
   return fnc;
 }
 
-  
+static void append_seppar(fn_sep_param** list,
+			  fn_sep_param* config)
+{
+    // FIXME: should do a deep copy of config and append to list
+    *list = config;
+}
 
 static void update_fn_config1(fn_node* fn, fn_config* fnc)
 {
@@ -344,6 +353,10 @@ static void update_fn_config1(fn_node* fn, fn_config* fnc)
     if (fnc->separate_recursions != CONFIG_DEFAULT)
 	fn->separate_recursions = fnc->separate_recursions;
 
+    if (fnc->separate_parameters)
+	append_seppar(&fn->separate_parameters,
+		      fnc->separate_parameters);
+
 #if CLG_ENABLE_DEBUG
     if (fnc->verbosity != CONFIG_DEFAULT)
 	fn->verbosity = fnc->verbosity;
@@ -510,6 +523,77 @@ Bool CLG_(process_cmd_line_option)(const HChar* arg)
        fnc->separate_recursions = n;
    }
 
+   else if VG_STREQN(15, arg, "--separate-par=") {
+       // separation by function parameters: format is
+       // --separate-par=<fn_pattern>':'<intpar_num>[':'<intval>(','<intval>)*]
+       UInt vcount;
+       fn_sep_param* sep_param;
+       fn_config* fnc;
+       const HChar *s, *start, *vals;
+       HChar *fpattern;
+       UInt parnum;
+
+       s = arg+15;
+       start = s;
+       // search for number after colon as end of function pattern
+       while(*s) {
+	   if ((s[0] == ':') && (s[1]>='0') && (s[1]<='9')) break;
+	   s++;
+       }
+       if (*s == 0) return False;
+
+       fpattern = (HChar*) CLG_MALLOC("cl.clo.seppar.1", (s - start) + 1);
+       VG_(strncpy)(fpattern, start, (s - start));
+       fpattern[s-start] = 0;
+
+       parnum = VG_(strtoll10)(s+1, (HChar**) &s);
+       if (parnum == 0) return False; /* first parameter is #1 */
+       if (*s == 0)
+	   vcount = 0;
+       else {
+	   if (*s != ':') return False;
+	   vals = ++s;
+	   vcount = 1;
+	   while(*s) {
+	       if (s[0] == ',') vcount++;
+	       s++;
+	   }
+       }
+
+       sep_param = (fn_sep_param*) CLG_MALLOC("cl.clo.seppar.2",
+					      sizeof(fn_sep_param) +
+					      vcount * sizeof(int));
+       sep_param->parnum = parnum;
+       sep_param->vcount = vcount;
+       sep_param->next = 0;
+       if (vcount>0) {
+	   vcount = 0;
+	   while(*vals) {
+	       // value of 0 is acceptable
+	       sep_param->val[vcount++] = VG_(strtoll10)(vals, (HChar**) &s);
+	       while(*s && (s[0]!=',')) s++;
+	       if (*s == 0) break;
+	       vals = s+1;
+	   }
+	   CLG_ASSERT(vcount == sep_param->vcount);
+       }
+       fnc = get_fnc(fpattern);
+       // FIXME: Merge borders for same parameter, sort according parnum
+       sep_param->next = fnc->separate_parameters;
+       fnc->separate_parameters = sep_param;
+
+       CLG_DEBUGIF(1) {
+	   CLG_DEBUG(1, "  seppar: fnpat '%s', number %d, vcount %d (",
+		     fpattern, parnum, vcount);
+	   if (vcount>0) {
+	       VG_(printf)("%d", sep_param->val[0]);
+	       for(vcount=1; vcount<sep_param->vcount; vcount++)
+		   VG_(printf)(", %d", sep_param->val[vcount]);
+	   }
+	   VG_(printf)(")\n");
+       }
+   }
+
    else if VG_STR_CLO(arg, "--callgrind-out-file", CLG_(clo).out_format) {}
 
    else if VG_BOOL_CLO(arg, "--mangle-names", CLG_(clo).mangle_names) {}
@@ -591,6 +675,8 @@ void CLG_(print_usage)(void)
 "    --separate-recs=<n>       Separate function recursions up to level [2]\n"
 "    --separate-recs<n>=<f>    Separate <n> recursions for function <f>\n"
 "    --skip-plt=no|yes         Ignore calls to/from PLT sections? [yes]\n"
+"    --separate-par=<f>:<par>[:<v1>,...] Separate function <f> by integer\n"
+"                              parameter <par>, optionally by bucket borders\n"
 "    --skip-direct-rec=no|yes  Ignore direct recursions? [yes]\n"
 "    --fn-skip=<function>      Ignore calls to/from function?\n"
 #if CLG_EXPERIMENTAL
@@ -653,7 +739,7 @@ void CLG_(set_clo_defaults)(void)
 
   CLG_(clo).skip_plt         = True;
   CLG_(clo).separate_callers = 0;
-  CLG_(clo).separate_recursions = 2;
+  CLG_(clo).separate_recursions = 1;
   CLG_(clo).skip_direct_recursion = False;
 
   /* Instrumentation */
diff --git a/callgrind/fn.c b/callgrind/fn.c
index 2434941..9b9e457 100644
--- a/callgrind/fn.c
+++ b/callgrind/fn.c
@@ -365,6 +365,7 @@ fn_node* new_fn_node(const HChar *fnname,
     fn->group        = 0;
     fn->separate_callers    = CLG_(clo).separate_callers;
     fn->separate_recursions = CLG_(clo).separate_recursions;
+    fn->separate_parameters = NULL;
 
 #if CLG_ENABLE_DEBUG
     fn->verbosity    = -1;
@@ -598,6 +599,51 @@ fn_node* CLG_(get_fn_node)(BB* bb)
     return fn;
 }
 
+#define FN_NAME_MAXLEN 1024
+
+fn_node* CLG_(get_par_fn_node)(fn_node* node, Int* sp)
+{
+    static HChar fnname[FN_NAME_MAXLEN];
+    static Int pos;
+    fn_sep_param* sep;
+    fn_node* new_node;
+
+    // TODO: 100 bytes hopefully enough for requested parameters
+    CLG_ASSERT(VG_(strlen)(node->name) +100 < FN_NAME_MAXLEN);
+    pos = VG_(sprintf)(fnname, "%s", node->name);
+    sep = node->separate_parameters;
+
+    while(sep) {
+	Int v = sp[sep->parnum];
+	if (sep->vcount == 0)
+	    pos += VG_(sprintf)(fnname+pos,":p%d=%d",
+				sep->parnum, v);
+	else {
+	    Int bucket = 0;
+	    while((bucket<sep->vcount) && (v>=sep->val[bucket]))
+		bucket++;
+	    if (bucket==0)
+		pos += VG_(sprintf)(fnname+pos,":p%d<%d",
+				    sep->parnum, sep->val[0]);
+	    else if (bucket == sep->vcount)
+		pos += VG_(sprintf)(fnname+pos,":p%d>%d",
+				    sep->parnum, sep->val[bucket-1]-1);
+	    else
+		pos += VG_(sprintf)(fnname+pos,":%d<p%d<%d",
+				    sep->val[bucket-1]-1,
+				    sep->parnum, sep->val[bucket]);
+	}
+	sep=sep->next;
+    }
+
+    new_node = get_fn_node_infile(node->file, fnname);
+    if (new_node->pure_cxt == 0) {
+	new_node->pure_cxt = node->pure_cxt;
+	new_node->skip = node->skip;
+    }
+    return new_node;
+}
+
 
 /*------------------------------------------------------------*/
 /*--- Active function array operations                     ---*/
diff --git a/callgrind/global.h b/callgrind/global.h
index bf511f7..4f158af 100644
--- a/callgrind/global.h
+++ b/callgrind/global.h
@@ -189,6 +189,7 @@ typedef struct _obj_node    obj_node;
 typedef struct _fn_config   fn_config;
 typedef struct _call_entry  call_entry;
 typedef struct _thread_info thread_info;
+typedef struct _fn_sep_param fn_sep_param;
 
 /* Costs of event sets. Aliases to arrays of 64-bit values */
 typedef ULong* SimCost;  /* All events the simulator can produce */
@@ -383,6 +384,16 @@ struct _BBCC {
     JmpData  jmp[0];
 };
 
+/*
+  struct holding information on function that should be logged separately
+  depending on its parameters
+*/
+struct _fn_sep_param {
+    UInt parnum;  /* nr of parameter to test */
+    UInt vcount;
+    fn_sep_param* next;
+    Int val[0];
+};
 
 /* the <number> of fn_node, file_node and obj_node are for compressed dumping
  * and a index into the dump boolean table and fn_info_table
@@ -410,6 +421,8 @@ struct _fn_node {
   Int  group;
   Int  separate_callers;
   Int  separate_recursions;
+  fn_sep_param* separate_parameters;
+
 #if CLG_ENABLE_DEBUG
   Int  verbosity; /* Stores old verbosity level while in function */
 #endif
@@ -710,12 +723,12 @@ void CLG_(copy_current_fn_array)(fn_array* dst);
 fn_array* CLG_(get_current_fn_array)(void);
 void CLG_(set_current_fn_array)(fn_array*);
 UInt* CLG_(get_fn_entry)(Int n);
-
 void      CLG_(init_obj_table)(void);
 obj_node* CLG_(get_obj_node)(DebugInfo* si);
 file_node* CLG_(get_file_node)(obj_node*, const HChar *dirname,
                                const HChar* filename);
 fn_node*  CLG_(get_fn_node)(BB* bb);
+fn_node* CLG_(get_par_fn_node)(fn_node* node, Int* sp);
 
 /* from bbcc.c */
 void CLG_(init_bbcc_hash)(bbcc_hash* bbccs);
------------------------------------------------------------------------------
_______________________________________________
Valgrind-users mailing list
Valgrind-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/valgrind-users

Reply via email to