2006-10-28 18:45:59 +02:00
|
|
|
#ifndef _PAHOLE_CLASSES_H_
|
|
|
|
#define _PAHOLE_CLASSES_H_ 1
|
|
|
|
/*
|
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of version 2 of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
struct cus {
|
|
|
|
struct list_head cus;
|
|
|
|
const char *filename;
|
|
|
|
};
|
|
|
|
|
2006-10-31 20:12:42 +01:00
|
|
|
struct cu {
|
|
|
|
struct list_head node;
|
|
|
|
struct list_head classes;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct list_head variables;
|
2006-11-03 18:38:43 +01:00
|
|
|
const char *name;
|
2006-10-31 20:12:42 +01:00
|
|
|
unsigned int id;
|
2006-11-03 18:38:43 +01:00
|
|
|
unsigned long nr_inline_expansions;
|
|
|
|
unsigned long size_inline_expansions;
|
2006-11-11 19:31:04 +01:00
|
|
|
unsigned int nr_functions_changed;
|
|
|
|
size_t max_len_changed_function;
|
|
|
|
size_t function_bytes_added;
|
|
|
|
size_t function_bytes_removed;
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct class {
|
|
|
|
struct list_head node;
|
|
|
|
struct list_head members;
|
2006-11-03 16:41:19 +01:00
|
|
|
struct list_head inline_expansions;
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct list_head variables;
|
2006-11-02 17:48:35 +01:00
|
|
|
const char *name;
|
2006-11-03 18:32:32 +01:00
|
|
|
uint64_t size;
|
2006-11-05 03:46:22 +01:00
|
|
|
uint64_t id;
|
|
|
|
uint64_t type;
|
2006-11-03 18:32:32 +01:00
|
|
|
uint64_t low_pc;
|
|
|
|
uint64_t high_pc;
|
2006-11-11 17:15:50 +01:00
|
|
|
uint64_t nr_entries; /* For arrays */
|
2006-11-05 03:46:22 +01:00
|
|
|
unsigned int tag; /* struct, union, base type, etc */
|
2006-10-28 18:45:59 +02:00
|
|
|
const char *decl_file;
|
|
|
|
unsigned int decl_line;
|
2006-11-01 14:34:42 +01:00
|
|
|
unsigned short nr_members;
|
2006-10-28 23:10:47 +02:00
|
|
|
unsigned short nr_holes;
|
2006-11-01 14:18:01 +01:00
|
|
|
unsigned short nr_labels;
|
|
|
|
unsigned short nr_variables;
|
2006-10-28 23:10:47 +02:00
|
|
|
unsigned short padding;
|
2006-10-29 02:40:35 +02:00
|
|
|
unsigned short inlined;
|
2006-11-03 16:41:19 +01:00
|
|
|
unsigned short nr_inline_expansions;
|
2006-11-10 22:19:58 +01:00
|
|
|
unsigned int refcnt;
|
2006-11-03 16:41:19 +01:00
|
|
|
unsigned int size_inline_expansions;
|
2006-11-11 19:31:04 +01:00
|
|
|
signed int diff;
|
[PFUNCT]: Improve --cu_inline_expansions_stats
Now it shows the number that each of the inline functions were expanded in an
object file:
Top 10 inline functions expanded more than once in kernel/sched.o, by total
size of inline expansions:
[acme@newtoy guinea_pig-2.6]$ pfunct --cu_inline_expansions_stats kernel/sched.o | sort -k3 -nr | grep -v ': 1 ' | head -11
kernel/sched.c: 318 10217
get_current: 38 325
finish_task_switch: 2 238
normal_prio: 2 167
__cpus_and: 14 164
find_process_by_pid: 6 152
current_thread_info: 21 149
sched_find_first_bit: 2 148
update_cpu_clock: 2 140
task_rq_unlock: 14 137
variable_test_bit: 14 121
[acme@newtoy guinea_pig-2.6]$
Now we have these options:
[acme@newtoy guinea_pig-2.6]$ pfunct --help
usage: pfunct [options] <file_name> {<function_name>}
where:
-c, --class=<class> functions that have <class> pointer parameters
-g, --goto_labels show number of goto labels
-i, --show_inline_expansions show inline expansions
-C, --cu_inline_expansions_stats show CU inline expansions stats
-s, --sizes show size of functions
-N, --function_name_len show size of functions
-p, --nr_parameters show number or parameters
-S, --variables show number of variables
-V, --verbose be verbose
[acme@newtoy guinea_pig-2.6]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-03 19:22:12 +01:00
|
|
|
unsigned int cu_total_nr_inline_expansions;
|
|
|
|
unsigned long cu_total_size_inline_expansions;
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct class_member {
|
|
|
|
struct list_head node;
|
2006-11-02 17:48:35 +01:00
|
|
|
char *name;
|
2006-11-05 03:46:22 +01:00
|
|
|
uint64_t type;
|
|
|
|
uint64_t offset;
|
2006-10-28 18:45:59 +02:00
|
|
|
unsigned int bit_size;
|
|
|
|
unsigned int bit_offset;
|
2006-11-10 22:19:58 +01:00
|
|
|
unsigned char visited:1;
|
2006-10-28 23:10:47 +02:00
|
|
|
unsigned short hole; /* If there is a hole before the next
|
|
|
|
one (or the end of the struct) */
|
2006-10-28 18:45:59 +02:00
|
|
|
};
|
|
|
|
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
struct variable {
|
|
|
|
struct list_head cu_node;
|
|
|
|
struct list_head class_node;
|
|
|
|
char *name;
|
|
|
|
uint64_t id;
|
|
|
|
uint64_t type;
|
|
|
|
uint64_t abstract_origin;
|
|
|
|
};
|
|
|
|
|
2006-11-03 16:41:19 +01:00
|
|
|
struct inline_expansion {
|
|
|
|
struct list_head node;
|
2006-11-05 03:46:22 +01:00
|
|
|
uint64_t type;
|
2006-11-03 18:32:32 +01:00
|
|
|
uint64_t size;
|
2006-11-03 16:41:19 +01:00
|
|
|
};
|
|
|
|
|
2006-11-05 18:34:54 +01:00
|
|
|
#define DEFAULT_CACHELINE_SIZE 32
|
|
|
|
|
2006-10-31 20:12:42 +01:00
|
|
|
extern void class__find_holes(struct class *self, const struct cu *cu);
|
|
|
|
extern void class__print(struct class *self, const struct cu *cu);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
extern struct cus *cus__new(const char *filename);
|
|
|
|
extern int cus__load(struct cus *self);
|
|
|
|
extern struct cu *cus__find_cu_by_name(struct cus *self, const char *name);
|
2006-10-31 21:23:16 +01:00
|
|
|
extern struct class *cu__find_class_by_id(const struct cu *cu,
|
2006-11-05 03:46:22 +01:00
|
|
|
const uint64_t type);
|
2006-10-31 21:23:16 +01:00
|
|
|
extern struct class *cu__find_class_by_name(struct cu *cu, const char *name);
|
2006-11-05 05:17:19 +01:00
|
|
|
extern int class__is_struct(const struct class *self,
|
|
|
|
struct cu *cu,
|
|
|
|
struct class **typedef_alias);
|
2006-11-11 19:31:04 +01:00
|
|
|
extern void cus__print_classes(struct cus *cus,
|
|
|
|
const unsigned int tag);
|
2006-11-03 16:41:19 +01:00
|
|
|
extern void class__print_inline_expansions(struct class *self,
|
|
|
|
const struct cu *cu);
|
[CLASSES]: Introduce struct variable
To represent DW_TAG_variable, for now all the variables in all the lexical
blocks, in addition to the top level function variables are in this list, next
step is to add support for DW_TAG_lexical_block, with support for nesting, and
to associate variables to the right place, be it the function itself (first,
implicit lexical block) or to the lexical blocks they belong too, this will be
useful for calculating stack usage.
So, with what we have now pfunct can do this:
[acme@newtoy guinea_pig-2.6]$ pfunct --variables net/ipv4/built-in.o tcp_v4_remember_stamp
/* net/ipv4/tcp_ipv4.c:1197 */
int tcp_v4_remember_stamp(struct sock * sk);
{
/* variables in tcp_v4_remember_stamp: */
struct inet_sock * inet;
struct tcp_sock * tp;
struct rtable * rt;
struct inet_peer * peer;
int release_it;
}
[acme@newtoy guinea_pig-2.6]$
That is already useful when you don't have the sources, huh? :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-05 04:31:41 +01:00
|
|
|
extern void class__print_variables(struct class *self,
|
|
|
|
const struct cu *cu);
|
2006-11-11 19:31:04 +01:00
|
|
|
extern struct class *cus__find_class_by_name(struct cus *self, struct cu **cu,
|
|
|
|
const char *name);
|
2006-11-03 18:38:43 +01:00
|
|
|
extern void cu__account_inline_expansions(struct cu *self);
|
2006-10-31 21:23:16 +01:00
|
|
|
extern int cu__for_each_class(struct cu *cu,
|
|
|
|
int (*iterator)(struct cu *cu,
|
|
|
|
struct class *class,
|
|
|
|
void *cookie),
|
|
|
|
void *cookie);
|
2006-11-11 19:31:04 +01:00
|
|
|
extern void cus__for_each_cu(struct cus *self,
|
|
|
|
int (*iterator)(struct cu *cu,
|
2006-10-31 21:23:16 +01:00
|
|
|
void *cookie),
|
2006-10-29 03:55:56 +01:00
|
|
|
void *cookie);
|
2006-10-28 23:22:42 +02:00
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
static inline uint32_t class__function_size(const struct class *self)
|
|
|
|
{
|
|
|
|
return self->high_pc - self->low_pc;
|
|
|
|
}
|
|
|
|
|
2006-11-05 18:34:54 +01:00
|
|
|
extern unsigned int cacheline_size;
|
|
|
|
|
2006-10-28 18:45:59 +02:00
|
|
|
#endif /* _PAHOLE_CLASSES_H_ */
|