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