[PFUNCT]: Do per CU inline statistics

Top five object files (CU, Compilation Unit) per number of inline expansions,
vmlinux being dissected is one built for QEMU, most things as modules, that
are not being taken into account as we're only looking at vmlinux:

[acme@newtoy guinea_pig-2.6]$ pfunct -C ../../acme/OUTPUT/qemu/net-2.6/vmlinux | sort -k2 -nr | head -5 | cut -c40-
net/ipv4/tcp_input.c: 274 20655
fs/buffer.c: 272 4597
kernel/sched.c: 214 3549
kernel/signal.c: 196 2730
fs/ext3/inode.c: 191 7961
[acme@newtoy guinea_pig-2.6]$

Top five object files (CU, Compilation Unit) per total size of inline expansions:

[acme@newtoy guinea_pig-2.6]$ pfunct -C ../../acme/OUTPUT/qemu/net-2.6/vmlinux | sort -k3 -nr | head -5 | cut -c40-
net/ipv4/tcp_input.c: 274 20655
net/xfrm/xfrm_policy.c: 173 11511
kernel/module.c: 95 10826
drivers/char/vt.c: 91 10050
net/xfrm/xfrm_user.c: 150 9682
[acme@newtoy guinea_pig-2.6]$

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2006-11-03 14:38:43 -03:00
parent 0330fb5d34
commit dcfe27a7ef
3 changed files with 51 additions and 14 deletions

View File

@ -34,12 +34,16 @@ static void cus__add(struct cu *cu)
list_add_tail(&cu->node, &cus__list);
}
static struct cu *cu__new(unsigned int cu)
static struct cu *cu__new(unsigned int cu, const char *name)
{
struct cu *self = malloc(sizeof(*self));
if (self != NULL)
if (self != NULL) {
INIT_LIST_HEAD(&self->classes);
self->name = name != NULL ? strdup(name) : NULL;
self->nr_inline_expansions = 0;
self->size_inline_expansions = 0;
}
return self;
}
@ -352,6 +356,17 @@ void class__find_holes(struct class *self, const struct cu *cu)
self->padding = self->size - (last->offset + last_size);
}
void cu__account_inline_expansions(struct cu *self)
{
struct class *pos;
list_for_each_entry(pos, &self->classes, node) {
self->nr_inline_expansions += pos->nr_inline_expansions;
self->size_inline_expansions += pos->size_inline_expansions;
}
}
void class__print_inline_expansions(struct class *self, const struct cu *cu)
{
char bf[256];
@ -776,7 +791,10 @@ int classes__load(const char *filename)
Dwarf_Die die;
if (dwarf_offdie(dwarf, last_offset + hdr_size, &die) != NULL) {
current_cu = cu__new(current_cu_id);
Dwarf_Attribute name;
current_cu = cu__new(current_cu_id,
attr_string(&die, DW_AT_name,
&name));
if (current_cu == NULL)
oom("cu__new");
++current_cu_id;

View File

@ -17,7 +17,10 @@
struct cu {
struct list_head node;
struct list_head classes;
const char *name;
unsigned int id;
unsigned long nr_inline_expansions;
unsigned long size_inline_expansions;
};
struct class {
@ -73,6 +76,7 @@ extern void classes__print(const unsigned int tag);
extern void class__print_inline_expansions(struct class *self,
const struct cu *cu);
extern struct class *cus__find_class_by_name(struct cu **cu, const char *name);
extern void cu__account_inline_expansions(struct cu *self);
extern int cu__for_each_class(struct cu *cu,
int (*iterator)(struct cu *cu,
struct class *class,

View File

@ -20,6 +20,7 @@ static int show_inline_expansions;
static struct option long_options[] = {
{ "class", required_argument, NULL, 'c' },
{ "cu_inline_expansions_stats", no_argument, NULL, 'C' },
{ "function_name_len", no_argument, NULL, 'N' },
{ "goto_labels", no_argument, NULL, 'g' },
{ "show_inline_expansions", no_argument, NULL, 'i' },
@ -36,15 +37,16 @@ static void usage(void)
fprintf(stderr,
"usage: pfunct [options] <file_name> {<function_name>}\n"
" where: \n"
" -c, --class=<class> functions that have <class> "
"pointer parameters\n"
" -g, --goto_labels show number of goto labels\n"
" -i, --show_inline_expansions show inline expansions\n"
" -s, --sizes show size of functions\n"
" -N, --function_name_len show size of functions\n"
" -p, --nr_parameters show number or parameters\n"
" -S, --variables show number of variables\n"
" -V, --verbose be verbose\n");
" -c, --class=<class> functions that have <class> "
"pointer parameters\n"
" -g, --goto_labels show number of goto labels\n"
" -i, --show_inline_expansions show inline expansions\n"
" -C, --cu_inline_expansions_stats show CU inline expansions stats\n"
" -s, --sizes show size of functions\n"
" -N, --function_name_len show size of functions\n"
" -p, --nr_parameters show number or parameters\n"
" -S, --variables show number of variables\n"
" -V, --verbose be verbose\n");
}
static int class__has_parameter_of_type(struct cu *cu, struct class *self,
@ -157,6 +159,15 @@ static int cu_function_iterator(struct cu *cu, void *cookie)
return cu__for_each_class(cu, function_iterator, cookie);
}
static int cu_inlines_iterator(struct cu *cu, void *cookie)
{
cu__account_inline_expansions(cu);
if (cu->nr_inline_expansions > 0)
printf("%s: %lu %lu\n", cu->name, cu->nr_inline_expansions,
cu->size_inline_expansions);
return 0;
}
static int nr_parameters_iterator(struct cu *cu, struct class *class, void *cookie)
{
if (class->tag != DW_TAG_subprogram || class->inlined)
@ -199,11 +210,13 @@ int main(int argc, char *argv[])
int show_nr_parameters = 0;
int show_function_name_len = 0;
int show_inline_expansions_stats = 0;
int show_inline_stats = 0;
while ((option = getopt_long(argc, argv, "c:giINpsSV",
while ((option = getopt_long(argc, argv, "c:CgiINpsSV",
long_options, &option_index)) >= 0)
switch (option) {
case 'c': class_name = optarg; break;
case 'C': show_inline_stats = 1; break;
case 's': show_sizes = 1; break;
case 'S': show_variables = 1; break;
case 'p': show_nr_parameters = 1; break;
@ -231,7 +244,9 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
if (show_nr_parameters)
if (show_inline_stats)
cus__for_each_cu(cu_inlines_iterator, NULL);
else if (show_nr_parameters)
cus__for_each_cu(cu_nr_parameters_iterator, NULL);
else if (show_variables)
cus__for_each_cu(cu_variables_iterator, NULL);