aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-11-26 01:34:59 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-11-26 01:34:59 -0500
commitfb6da03ff6ed69c9d9a750212cf109f6d5325a72 (patch)
tree52caecd86009272dc3b9ddefa6e6a009e4e668ab
parentd390b203bff9851385b461a4206d756d5ac1ee60 (diff)
Make function graph a special override
The function graph tracer is a special case in libparsevent. It is also the reason for the work arounds in tracecmd with the callback to trace_read_data() and trace_peek_data(). This patch moves the function graph tracer as a override and out of the libparsevent. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--parse-events.c403
-rw-r--r--parse-events.h8
-rw-r--r--trace-ftrace.c315
3 files changed, 315 insertions, 411 deletions
diff --git a/parse-events.c b/parse-events.c
index 08f2417..4ae337c 100644
--- a/parse-events.c
+++ b/parse-events.c
@@ -2039,8 +2039,8 @@ static int event_read_print(struct event *event)
2039 return -1; 2039 return -1;
2040} 2040}
2041 2041
2042static struct format_field * 2042struct format_field *
2043find_common_field(struct event *event, const char *name) 2043pevent_find_common_field(struct event *event, const char *name)
2044{ 2044{
2045 struct format_field *format; 2045 struct format_field *format;
2046 2046
@@ -2067,12 +2067,12 @@ pevent_find_field(struct event *event, const char *name)
2067 return format; 2067 return format;
2068} 2068}
2069 2069
2070static struct format_field * 2070struct format_field *
2071find_any_field(struct event *event, const char *name) 2071pevent_find_any_field(struct event *event, const char *name)
2072{ 2072{
2073 struct format_field *format; 2073 struct format_field *format;
2074 2074
2075 format = find_common_field(event, name); 2075 format = pevent_find_common_field(event, name);
2076 if (format) 2076 if (format)
2077 return format; 2077 return format;
2078 return pevent_find_field(event, name); 2078 return pevent_find_field(event, name);
@@ -2123,7 +2123,7 @@ static int get_common_info(const char *type, int *offset, int *size)
2123 die("no event_list!"); 2123 die("no event_list!");
2124 2124
2125 event = event_list; 2125 event = event_list;
2126 field = find_common_field(event, type); 2126 field = pevent_find_common_field(event, type);
2127 if (!field) 2127 if (!field)
2128 die("field '%s' not found", type); 2128 die("field '%s' not found", type);
2129 2129
@@ -2196,7 +2196,7 @@ static int parse_common_lock_depth(void *data)
2196 return ret; 2196 return ret;
2197} 2197}
2198 2198
2199static struct event *trace_find_event(int id) 2199struct event *pevent_find_event(int id)
2200{ 2200{
2201 struct event *event; 2201 struct event *event;
2202 2202
@@ -2207,8 +2207,8 @@ static struct event *trace_find_event(int id)
2207 return event; 2207 return event;
2208} 2208}
2209 2209
2210static struct event * 2210struct event *
2211trace_find_event_by_name(const char *sys, const char *name) 2211pevent_find_event_by_name(const char *sys, const char *name)
2212{ 2212{
2213 struct event *event; 2213 struct event *event;
2214 2214
@@ -2240,7 +2240,7 @@ static unsigned long long eval_num_arg(void *data, int size,
2240 return strtoull(arg->atom.atom, NULL, 0); 2240 return strtoull(arg->atom.atom, NULL, 0);
2241 case PRINT_FIELD: 2241 case PRINT_FIELD:
2242 if (!arg->field.field) { 2242 if (!arg->field.field) {
2243 arg->field.field = find_any_field(event, arg->field.name); 2243 arg->field.field = pevent_find_any_field(event, arg->field.name);
2244 if (!arg->field.field) 2244 if (!arg->field.field)
2245 die("field %s not found", arg->field.name); 2245 die("field %s not found", arg->field.name);
2246 } 2246 }
@@ -2288,7 +2288,7 @@ static unsigned long long eval_num_arg(void *data, int size,
2288 case PRINT_FIELD: 2288 case PRINT_FIELD:
2289 if (!larg->field.field) { 2289 if (!larg->field.field) {
2290 larg->field.field = 2290 larg->field.field =
2291 find_any_field(event, larg->field.name); 2291 pevent_find_any_field(event, larg->field.name);
2292 if (!larg->field.field) 2292 if (!larg->field.field)
2293 die("field %s not found", larg->field.name); 2293 die("field %s not found", larg->field.name);
2294 } 2294 }
@@ -2429,7 +2429,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
2429 return; 2429 return;
2430 case PRINT_FIELD: 2430 case PRINT_FIELD:
2431 if (!arg->field.field) { 2431 if (!arg->field.field) {
2432 arg->field.field = find_any_field(event, arg->field.name); 2432 arg->field.field = pevent_find_any_field(event, arg->field.name);
2433 if (!arg->field.field) 2433 if (!arg->field.field)
2434 die("field %s not found", arg->field.name); 2434 die("field %s not found", arg->field.name);
2435 } 2435 }
@@ -2490,7 +2490,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
2490 if (arg->string.offset == -1) { 2490 if (arg->string.offset == -1) {
2491 struct format_field *f; 2491 struct format_field *f;
2492 2492
2493 f = find_any_field(event, arg->string.string); 2493 f = pevent_find_any_field(event, arg->string.string);
2494 arg->string.offset = f->offset; 2494 arg->string.offset = f->offset;
2495 } 2495 }
2496 str_offset = *(int *)(data + arg->string.offset); 2496 str_offset = *(int *)(data + arg->string.offset);
@@ -2763,7 +2763,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
2763 fmt = "%.2x%.2x%.2x%.2x%.2x%.2x"; 2763 fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
2764 if (!arg->field.field) { 2764 if (!arg->field.field) {
2765 arg->field.field = 2765 arg->field.field =
2766 find_any_field(event, arg->field.name); 2766 pevent_find_any_field(event, arg->field.name);
2767 if (!arg->field.field) 2767 if (!arg->field.field)
2768 die("field %s not found", arg->field.name); 2768 die("field %s not found", arg->field.name);
2769 } 2769 }
@@ -2845,15 +2845,6 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
2845 } 2845 }
2846} 2846}
2847 2847
2848static inline int log10_cpu(int nb)
2849{
2850 if (nb / 100)
2851 return 3;
2852 if (nb / 10)
2853 return 2;
2854 return 1;
2855}
2856
2857static void print_lat_fmt(struct trace_seq *s, void *data, int size __unused) 2848static void print_lat_fmt(struct trace_seq *s, void *data, int size __unused)
2858{ 2849{
2859 unsigned int lat_flags; 2850 unsigned int lat_flags;
@@ -2889,354 +2880,6 @@ static void print_lat_fmt(struct trace_seq *s, void *data, int size __unused)
2889 trace_seq_printf(s, "%d", lock_depth); 2880 trace_seq_printf(s, "%d", lock_depth);
2890} 2881}
2891 2882
2892/* taken from Linux, written by Frederic Weisbecker */
2893static void print_graph_cpu(struct trace_seq *s, int cpu)
2894{
2895 int i;
2896 int log10_this = log10_cpu(cpu);
2897 int log10_all = log10_cpu(cpus);
2898
2899
2900 /*
2901 * Start with a space character - to make it stand out
2902 * to the right a bit when trace output is pasted into
2903 * email:
2904 */
2905 trace_seq_putc(s, ' ');
2906
2907 /*
2908 * Tricky - we space the CPU field according to the max
2909 * number of online CPUs. On a 2-cpu system it would take
2910 * a maximum of 1 digit - on a 128 cpu system it would
2911 * take up to 3 digits:
2912 */
2913 for (i = 0; i < log10_all - log10_this; i++)
2914 trace_seq_putc(s, ' ');
2915
2916 trace_seq_printf(s, "%d) ", cpu);
2917}
2918
2919#define TRACE_GRAPH_PROCINFO_LENGTH 14
2920#define TRACE_GRAPH_INDENT 2
2921
2922static void print_graph_proc(struct trace_seq *s, int pid, const char *comm)
2923{
2924 /* sign + log10(MAX_INT) + '\0' */
2925 char pid_str[11];
2926 int spaces = 0;
2927 int len;
2928 int i;
2929
2930 sprintf(pid_str, "%d", pid);
2931
2932 /* 1 stands for the "-" character */
2933 len = strlen(comm) + strlen(pid_str) + 1;
2934
2935 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2936 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2937
2938 /* First spaces to align center */
2939 for (i = 0; i < spaces / 2; i++)
2940 trace_seq_putc(s, ' ');
2941
2942 trace_seq_printf(s, "%s-%s", comm, pid_str);
2943
2944 /* Last spaces to align center */
2945 for (i = 0; i < spaces - (spaces / 2); i++)
2946 trace_seq_putc(s, ' ');
2947}
2948
2949static struct record *
2950get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2951 struct record *next)
2952{
2953 struct format_field *field;
2954 struct event *event;
2955 unsigned long val;
2956 int type;
2957 int pid;
2958
2959 type = trace_parse_common_type(next->data);
2960 event = trace_find_event(type);
2961 if (!event)
2962 return NULL;
2963
2964 if (!(event->flags & EVENT_FL_ISFUNCRET))
2965 return NULL;
2966
2967 pid = parse_common_pid(next->data);
2968 field = pevent_find_field(event, "func");
2969 if (!field)
2970 die("function return does not have field func");
2971
2972 val = pevent_read_number(next->data + field->offset, field->size);
2973
2974 if (cur_pid != pid || cur_func != val)
2975 return NULL;
2976
2977 /* this is a leaf, now advance the iterator */
2978 return trace_read_data(cpu);
2979}
2980
2981/* Signal a overhead of time execution to the output */
2982static void print_graph_overhead(struct trace_seq *s,
2983 unsigned long long duration)
2984{
2985 /* Non nested entry or return */
2986 if (duration == ~0ULL)
2987 return (void)trace_seq_printf(s, " ");
2988
2989 /* Duration exceeded 100 msecs */
2990 if (duration > 100000ULL)
2991 return (void)trace_seq_printf(s, "! ");
2992
2993 /* Duration exceeded 10 msecs */
2994 if (duration > 10000ULL)
2995 return (void)trace_seq_printf(s, "+ ");
2996
2997 trace_seq_printf(s, " ");
2998}
2999
3000static void print_graph_duration(struct trace_seq *s, unsigned long long duration)
3001{
3002 unsigned long usecs = duration / 1000;
3003 unsigned long nsecs_rem = duration % 1000;
3004 /* log10(ULONG_MAX) + '\0' */
3005 char msecs_str[21];
3006 char nsecs_str[5];
3007 int len;
3008 int i;
3009
3010 sprintf(msecs_str, "%lu", usecs);
3011
3012 /* Print msecs */
3013 len = s->len;
3014 trace_seq_printf(s, "%lu", usecs);
3015
3016 /* Print nsecs (we don't want to exceed 7 numbers) */
3017 if ((s->len - len) < 7) {
3018 snprintf(nsecs_str, 8 - (s->len - len), "%03lu", nsecs_rem);
3019 trace_seq_printf(s, ".%s", nsecs_str);
3020 }
3021
3022 len = s->len - len;
3023
3024 trace_seq_puts(s, " us ");
3025
3026 /* Print remaining spaces to fit the row's width */
3027 for (i = len; i < 7; i++)
3028 trace_seq_putc(s, ' ');
3029
3030 trace_seq_puts(s, "| ");
3031}
3032
3033static void
3034print_graph_entry_leaf(struct trace_seq *s,
3035 struct event *event, void *data, struct record *ret_rec)
3036{
3037 unsigned long long rettime, calltime;
3038 unsigned long long duration, depth;
3039 unsigned long long val;
3040 struct format_field *field;
3041 struct func_map *func;
3042 struct event *ret_event;
3043 int type;
3044 int i;
3045
3046 type = trace_parse_common_type(ret_rec->data);
3047 ret_event = trace_find_event(type);
3048
3049 field = pevent_find_field(ret_event, "rettime");
3050 if (!field)
3051 die("can't find rettime in return graph");
3052 rettime = pevent_read_number(ret_rec->data + field->offset, field->size);
3053
3054 field = pevent_find_field(ret_event, "calltime");
3055 if (!field)
3056 die("can't find rettime in return graph");
3057 calltime = pevent_read_number(ret_rec->data + field->offset, field->size);
3058
3059 duration = rettime - calltime;
3060
3061 /* Overhead */
3062 print_graph_overhead(s, duration);
3063
3064 /* Duration */
3065 print_graph_duration(s, duration);
3066
3067 field = pevent_find_field(event, "depth");
3068 if (!field)
3069 die("can't find depth in entry graph");
3070 depth = pevent_read_number(data + field->offset, field->size);
3071
3072 /* Function */
3073 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
3074 trace_seq_putc(s, ' ');
3075
3076 field = pevent_find_field(event, "func");
3077 if (!field)
3078 die("can't find func in entry graph");
3079 val = pevent_read_number(data + field->offset, field->size);
3080 func = find_func(val);
3081
3082 if (func)
3083 trace_seq_printf(s, "%s();", func->func);
3084 else
3085 trace_seq_printf(s, "%llx();", val);
3086}
3087
3088static void print_graph_nested(struct trace_seq *s,
3089 struct event *event, void *data)
3090{
3091 struct format_field *field;
3092 unsigned long long depth;
3093 unsigned long long val;
3094 struct func_map *func;
3095 int i;
3096
3097 /* No overhead */
3098 print_graph_overhead(s, -1);
3099
3100 /* No time */
3101 trace_seq_puts(s, " | ");
3102
3103 field = pevent_find_field(event, "depth");
3104 if (!field)
3105 die("can't find depth in entry graph");
3106 depth = pevent_read_number(data + field->offset, field->size);
3107
3108 /* Function */
3109 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
3110 trace_seq_putc(s, ' ');
3111
3112 field = pevent_find_field(event, "func");
3113 if (!field)
3114 die("can't find func in entry graph");
3115 val = pevent_read_number(data + field->offset, field->size);
3116 func = find_func(val);
3117
3118 if (func)
3119 trace_seq_printf(s, "%s() {", func->func);
3120 else
3121 trace_seq_printf(s, "%llx() {", val);
3122}
3123
3124static void
3125pretty_print_func_ent(struct trace_seq *s,
3126 void *data, int size, struct event *event,
3127 int cpu, int pid, const char *comm,
3128 unsigned long secs, unsigned long usecs)
3129{
3130 struct format_field *field;
3131 struct record *rec;
3132 void *copy_data;
3133 unsigned long val;
3134
3135 trace_seq_printf(s, "%5lu.%06lu | ", secs, usecs);
3136
3137 print_graph_cpu(s, cpu);
3138 print_graph_proc(s, pid, comm);
3139
3140 trace_seq_puts(s, " | ");
3141
3142 if (latency_format) {
3143 print_lat_fmt(s, data, size);
3144 trace_seq_puts(s, " | ");
3145 }
3146
3147 field = pevent_find_field(event, "func");
3148 if (!field)
3149 die("function entry does not have func field");
3150
3151 val = pevent_read_number(data + field->offset, field->size);
3152
3153 /*
3154 * peek_data may unmap the data pointer. Copy it first.
3155 */
3156 copy_data = malloc_or_die(size);
3157 memcpy(copy_data, data, size);
3158 data = copy_data;
3159
3160 rec = trace_peek_data(cpu);
3161 if (rec) {
3162 rec = get_return_for_leaf(cpu, pid, val, rec);
3163 if (rec) {
3164 print_graph_entry_leaf(s, event, data, rec);
3165 goto out_free;
3166 }
3167 }
3168 print_graph_nested(s, event, data);
3169out_free:
3170 free(data);
3171}
3172
3173static void
3174pretty_print_func_ret(struct trace_seq *s,
3175 void *data, int size __unused, struct event *event,
3176 int cpu, int pid, const char *comm,
3177 unsigned long secs, unsigned long usecs)
3178{
3179 unsigned long long rettime, calltime;
3180 unsigned long long duration, depth;
3181 struct format_field *field;
3182 int i;
3183
3184 trace_seq_printf(s, "%5lu.%06lu | ", secs, usecs);
3185
3186 print_graph_cpu(s, cpu);
3187 print_graph_proc(s, pid, comm);
3188
3189 trace_seq_puts(s, " | ");
3190
3191 if (latency_format) {
3192 print_lat_fmt(s, data, size);
3193 trace_seq_puts(s, " | ");
3194 }
3195
3196 field = pevent_find_field(event, "rettime");
3197 if (!field)
3198 die("can't find rettime in return graph");
3199 rettime = pevent_read_number(data + field->offset, field->size);
3200
3201 field = pevent_find_field(event, "calltime");
3202 if (!field)
3203 die("can't find calltime in return graph");
3204 calltime = pevent_read_number(data + field->offset, field->size);
3205
3206 duration = rettime - calltime;
3207
3208 /* Overhead */
3209 print_graph_overhead(s, duration);
3210
3211 /* Duration */
3212 print_graph_duration(s, duration);
3213
3214 field = pevent_find_field(event, "depth");
3215 if (!field)
3216 die("can't find depth in entry graph");
3217 depth = pevent_read_number(data + field->offset, field->size);
3218
3219 /* Function */
3220 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
3221 trace_seq_putc(s, ' ');
3222
3223 trace_seq_putc(s, '}');
3224}
3225
3226static void
3227pretty_print_func_graph(struct trace_seq *s,
3228 void *data, int size, struct event *event,
3229 int cpu, int pid, const char *comm,
3230 unsigned long secs, unsigned long usecs)
3231{
3232 if (event->flags & EVENT_FL_ISFUNCENT)
3233 pretty_print_func_ent(s, data, size, event,
3234 cpu, pid, comm, secs, usecs);
3235 else if (event->flags & EVENT_FL_ISFUNCRET)
3236 pretty_print_func_ret(s, data, size, event,
3237 cpu, pid, comm, secs, usecs);
3238}
3239
3240void pevent_print_event(struct trace_seq *s, 2883void pevent_print_event(struct trace_seq *s,
3241 int cpu, void *data, int size, unsigned long long nsecs) 2884 int cpu, void *data, int size, unsigned long long nsecs)
3242{ 2885{
@@ -3253,7 +2896,7 @@ void pevent_print_event(struct trace_seq *s,
3253 2896
3254 type = trace_parse_common_type(data); 2897 type = trace_parse_common_type(data);
3255 2898
3256 event = trace_find_event(type); 2899 event = pevent_find_event(type);
3257 if (!event) { 2900 if (!event) {
3258 warning("ug! no event found for type %d", type); 2901 warning("ug! no event found for type %d", type);
3259 return; 2902 return;
@@ -3262,10 +2905,6 @@ void pevent_print_event(struct trace_seq *s,
3262 pid = parse_common_pid(data); 2905 pid = parse_common_pid(data);
3263 comm = find_cmdline(pid); 2906 comm = find_cmdline(pid);
3264 2907
3265 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
3266 return pretty_print_func_graph(s, data, size, event, cpu,
3267 pid, comm, secs, usecs);
3268
3269 if (latency_format) { 2908 if (latency_format) {
3270 trace_seq_printf(s, "%8.8s-%-5d %3d", 2909 trace_seq_printf(s, "%8.8s-%-5d %3d",
3271 comm, pid, cpu); 2910 comm, pid, cpu);
@@ -3464,13 +3103,7 @@ int pevent_parse_event(char *buf, unsigned long size, char *sys)
3464 3103
3465 event->flags |= EVENT_FL_ISFTRACE; 3104 event->flags |= EVENT_FL_ISFTRACE;
3466 3105
3467 if (strcmp(event->name, "funcgraph_entry") == 0) 3106 if (strcmp(event->name, "bprint") == 0)
3468 event->flags |= EVENT_FL_ISFUNCENT;
3469
3470 else if (strcmp(event->name, "funcgraph_exit") == 0)
3471 event->flags |= EVENT_FL_ISFUNCRET;
3472
3473 else if (strcmp(event->name, "bprint") == 0)
3474 event->flags |= EVENT_FL_ISBPRINT; 3107 event->flags |= EVENT_FL_ISBPRINT;
3475 } 3108 }
3476 3109
@@ -3533,7 +3166,7 @@ int pevent_register_event_handler(int id, char *sys_name, char *event_name,
3533 3166
3534 if (id >= 0) { 3167 if (id >= 0) {
3535 /* search by id */ 3168 /* search by id */
3536 event = trace_find_event(id); 3169 event = pevent_find_event(id);
3537 if (!event) 3170 if (!event)
3538 return -1; 3171 return -1;
3539 if (event_name && (strcmp(event_name, event->name) != 0)) 3172 if (event_name && (strcmp(event_name, event->name) != 0))
@@ -3541,7 +3174,7 @@ int pevent_register_event_handler(int id, char *sys_name, char *event_name,
3541 if (sys_name && (strcmp(sys_name, event->system) != 0)) 3174 if (sys_name && (strcmp(sys_name, event->system) != 0))
3542 return -1; 3175 return -1;
3543 } else { 3176 } else {
3544 event = trace_find_event_by_name(sys_name, event_name); 3177 event = pevent_find_event_by_name(sys_name, event_name);
3545 if (!event) 3178 if (!event)
3546 return -1; 3179 return -1;
3547 } 3180 }
diff --git a/parse-events.h b/parse-events.h
index 20c8aec..074adb1 100644
--- a/parse-events.h
+++ b/parse-events.h
@@ -301,12 +301,20 @@ int pevent_parse_event(char *buf, unsigned long size, char *sys);
301int pevent_register_event_handler(int id, char *sys_name, char *event_name, 301int pevent_register_event_handler(int id, char *sys_name, char *event_name,
302 pevent_event_handler_func func); 302 pevent_event_handler_func func);
303 303
304struct format_field *pevent_find_common_field(struct event *event, const char *name);
304struct format_field *pevent_find_field(struct event *event, const char *name); 305struct format_field *pevent_find_field(struct event *event, const char *name);
306struct format_field *pevent_find_any_field(struct event *event, const char *name);
307
305const char *pevent_find_function(unsigned long long addr); 308const char *pevent_find_function(unsigned long long addr);
306unsigned long long pevent_read_number(const void *ptr, int size); 309unsigned long long pevent_read_number(const void *ptr, int size);
307int pevent_read_number_field(struct format_field *field, const void *data, 310int pevent_read_number_field(struct format_field *field, const void *data,
308 unsigned long long *value); 311 unsigned long long *value);
309 312
313struct event *pevent_find_event(int id);
314
315struct event *
316pevent_find_event_by_name(const char *sys, const char *name);
317
310 318
311/* for debugging */ 319/* for debugging */
312void pevent_print_funcs(void); 320void pevent_print_funcs(void);
diff --git a/trace-ftrace.c b/trace-ftrace.c
index 07de014..16b012e 100644
--- a/trace-ftrace.c
+++ b/trace-ftrace.c
@@ -4,48 +4,311 @@
4 4
5#include "parse-events.h" 5#include "parse-events.h"
6 6
7static struct event *fgraph_ret_event;
8static int fgraph_ret_id;
9
10static int get_field_val(struct trace_seq *s, void *data,
11 struct event *event, const char *name,
12 unsigned long long *val)
13{
14 struct format_field *field;
15
16 field = pevent_find_any_field(event, name);
17 if (!field) {
18 trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
19 return -1;
20 }
21
22 if (pevent_read_number_field(field, data, val)) {
23 trace_seq_printf(s, " %s=INVALID", name);
24 return -1;
25 }
26
27 return 0;
28}
29
7static int function_handler(struct trace_seq *s, void *data, int size, 30static int function_handler(struct trace_seq *s, void *data, int size,
8 struct event *event, int cpu, 31 struct event *event, int cpu,
9 unsigned long long nsecs) 32 unsigned long long nsecs)
10{ 33{
11 struct format_field *ip = pevent_find_field(event, "ip");
12 struct format_field *pip = pevent_find_field(event, "parent_ip");
13 unsigned long long function; 34 unsigned long long function;
14 const char *func; 35 const char *func;
15 36
16 if (!ip) 37 if (get_field_val(s, data, event, "ip", &function))
17 return trace_seq_printf(s, "CANT FIND FIELD IP"); 38 return trace_seq_putc(s, '!');
18
19 if (pevent_read_number_field(ip, data, &function))
20 trace_seq_printf(s, " function=INVALID");
21 else {
22 func = pevent_find_function(function);
23 if (func)
24 trace_seq_printf(s, "%s <-- ", func);
25 else
26 trace_seq_printf(s, "0x%llx", function);
27 }
28 39
29 if (!pip) 40 func = pevent_find_function(function);
30 return trace_seq_printf(s, "CANT FIND FIELD PARENT_IP"); 41 if (func)
31 42 trace_seq_printf(s, "%s <-- ", func);
32 if (pevent_read_number_field(pip, data, &function)) 43 else
33 trace_seq_printf(s, " function=INVALID"); 44 trace_seq_printf(s, "0x%llx", function);
34 else { 45
35 func = pevent_find_function(function); 46 if (get_field_val(s, data, event, "parent_ip", &function))
36 if (func) 47 return trace_seq_putc(s, '!');
37 trace_seq_printf(s, "%s", func); 48
38 else 49 func = pevent_find_function(function);
39 trace_seq_printf(s, "0x%llx", function); 50 if (func)
40 } 51 trace_seq_printf(s, "%s", func);
52 else
53 trace_seq_printf(s, "0x%llx", function);
41 54
42 return 0; 55 return 0;
43} 56}
44 57
58#define TRACE_GRAPH_INDENT 2
59
60static struct record *
61get_return_for_leaf(struct trace_seq *s, int cpu, int cur_pid,
62 unsigned long long cur_func, struct record *next)
63{
64 unsigned long long val;
65 unsigned long long type;
66 unsigned long long pid;
67
68 /* Searching a common field, can use any event */
69 if (get_field_val(s, next->data, fgraph_ret_event, "common_type", &type))
70 return NULL;
71
72 if (type != fgraph_ret_id)
73 return NULL;
74
75 if (get_field_val(s, next->data, fgraph_ret_event, "common_pid", &pid))
76 return NULL;
77
78 if (cur_pid != pid)
79 return NULL;
80
81 /* We aleady know this is a funcgraph_ret_event */
82 if (get_field_val(s, next->data, fgraph_ret_event, "func", &val))
83 return NULL;
84
85 if (cur_func != val)
86 return NULL;
87
88 /* this is a leaf, now advance the iterator */
89 return trace_read_data(cpu);
90}
91
92/* Signal a overhead of time execution to the output */
93static void print_graph_overhead(struct trace_seq *s,
94 unsigned long long duration)
95{
96 /* Non nested entry or return */
97 if (duration == ~0ULL)
98 return (void)trace_seq_printf(s, " ");
99
100 /* Duration exceeded 100 msecs */
101 if (duration > 100000ULL)
102 return (void)trace_seq_printf(s, "! ");
103
104 /* Duration exceeded 10 msecs */
105 if (duration > 10000ULL)
106 return (void)trace_seq_printf(s, "+ ");
107
108 trace_seq_printf(s, " ");
109}
110
111static void print_graph_duration(struct trace_seq *s, unsigned long long duration)
112{
113 unsigned long usecs = duration / 1000;
114 unsigned long nsecs_rem = duration % 1000;
115 /* log10(ULONG_MAX) + '\0' */
116 char msecs_str[21];
117 char nsecs_str[5];
118 int len;
119 int i;
120
121 sprintf(msecs_str, "%lu", usecs);
122
123 /* Print msecs */
124 len = s->len;
125 trace_seq_printf(s, "%lu", usecs);
126
127 /* Print nsecs (we don't want to exceed 7 numbers) */
128 if ((s->len - len) < 7) {
129 snprintf(nsecs_str, 8 - (s->len - len), "%03lu", nsecs_rem);
130 trace_seq_printf(s, ".%s", nsecs_str);
131 }
132
133 len = s->len - len;
134
135 trace_seq_puts(s, " us ");
136
137 /* Print remaining spaces to fit the row's width */
138 for (i = len; i < 7; i++)
139 trace_seq_putc(s, ' ');
140
141 trace_seq_puts(s, "| ");
142}
143
144static int
145print_graph_entry_leaf(struct trace_seq *s,
146 struct event *event, void *data, struct record *ret_rec)
147{
148 unsigned long long rettime, calltime;
149 unsigned long long duration, depth;
150 unsigned long long val;
151 const char *func;
152 int i;
153
154
155 if (get_field_val(s, ret_rec->data, fgraph_ret_event, "rettime", &rettime))
156 return trace_seq_putc(s, '!');
157
158 if (get_field_val(s, ret_rec->data, fgraph_ret_event, "calltime", &calltime))
159 return trace_seq_putc(s, '!');
160
161 duration = rettime - calltime;
162
163 /* Overhead */
164 print_graph_overhead(s, duration);
165
166 /* Duration */
167 print_graph_duration(s, duration);
168
169 if (get_field_val(s, data, event, "depth", &depth))
170 return trace_seq_putc(s, '!');
171
172 /* Function */
173 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
174 trace_seq_putc(s, ' ');
175
176 if (get_field_val(s, data, event, "func", &val))
177 return trace_seq_putc(s, '!');
178 func = pevent_find_function(val);
179
180 if (func)
181 return trace_seq_printf(s, "%s();", func);
182 else
183 return trace_seq_printf(s, "%llx();", val);
184}
185
186static int print_graph_nested(struct trace_seq *s,
187 struct event *event, void *data)
188{
189 unsigned long long depth;
190 unsigned long long val;
191 const char *func;
192 int i;
193
194 /* No overhead */
195 print_graph_overhead(s, -1);
196
197 /* No time */
198 trace_seq_puts(s, " | ");
199
200 if (get_field_val(s, data, event, "depth", &depth))
201 return trace_seq_putc(s, '!');
202
203 /* Function */
204 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
205 trace_seq_putc(s, ' ');
206
207 if (get_field_val(s, data, event, "func", &val))
208 return trace_seq_putc(s, '!');
209
210 func = pevent_find_function(val);
211
212 if (func)
213 return trace_seq_printf(s, "%s() {", func);
214 else
215 return trace_seq_printf(s, "%llx() {", val);
216}
217
218static int
219fgraph_ent_handler(struct trace_seq *s, void *data, int size,
220 struct event *event, int cpu,
221 unsigned long long nsecs)
222{
223 struct record *rec;
224 void *copy_data;
225 unsigned long long val, pid;
226 int ret;
227
228 if (get_field_val(s, data, event, "common_pid", &pid))
229 return trace_seq_putc(s, '!');
230
231 if (get_field_val(s, data, event, "func", &val))
232 return trace_seq_putc(s, '!');
233
234 /*
235 * peek_data may unmap the data pointer. Copy it first.
236 */
237 copy_data = malloc(size);
238 if (!copy_data)
239 return trace_seq_printf(s, " <FAILED TO ALLOCATE MEMORY!>");
240
241 memcpy(copy_data, data, size);
242 data = copy_data;
243
244 rec = trace_peek_data(cpu);
245 if (rec)
246 rec = get_return_for_leaf(s, cpu, pid, val, rec);
247 if (rec)
248 ret = print_graph_entry_leaf(s, event, data, rec);
249 else
250 ret = print_graph_nested(s, event, data);
251
252 free(data);
253 return ret;
254}
255
256static int
257fgraph_ret_handler(struct trace_seq *s, void *data, int size,
258 struct event *event, int cpu,
259 unsigned long long nsecs)
260{
261 unsigned long long rettime, calltime;
262 unsigned long long duration, depth;
263 int i;
264
265 /* Compensate that exit is one char less than entry */
266 trace_seq_putc(s, ' ');
267
268 if (get_field_val(s, data, event, "rettime", &rettime))
269 return trace_seq_putc(s, '!');
270
271 if (get_field_val(s, data, event, "calltime", &calltime))
272 return trace_seq_putc(s, '!');
273
274 duration = rettime - calltime;
275
276 /* Overhead */
277 print_graph_overhead(s, duration);
278
279 /* Duration */
280 print_graph_duration(s, duration);
281
282 if (get_field_val(s, data, event, "depth", &depth))
283 return trace_seq_putc(s, '!');
284
285 /* Function */
286 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
287 trace_seq_putc(s, ' ');
288
289 return trace_seq_putc(s, '}');
290}
291
45int tracecmd_ftrace_overrides(void) 292int tracecmd_ftrace_overrides(void)
46{ 293{
294 struct event *event;
295
47 pevent_register_event_handler(-1, "ftrace", "function", 296 pevent_register_event_handler(-1, "ftrace", "function",
48 function_handler); 297 function_handler);
49 298
299 pevent_register_event_handler(-1, "ftrace", "funcgraph_entry",
300 fgraph_ent_handler);
301
302 pevent_register_event_handler(-1, "ftrace", "funcgraph_exit",
303 fgraph_ret_handler);
304
305 /* Store the func ret id and event for later use */
306 event = pevent_find_event_by_name("ftrace", "funcgraph_exit");
307 if (!event)
308 return 0;
309
310 fgraph_ret_id = event->id;
311 fgraph_ret_event = event;
312
50 return 0; 313 return 0;
51} 314}