Home | History | Annotate | Download | only in ltrace
      1 /*
      2  * This file is part of ltrace.
      3  * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
      4  * Copyright (C) 2003,2008,2009 Juan Cespedes
      5  * Copyright (C) 2006 Ian Wienand
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2 of the
     10  * License, or (at your option) any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but
     13  * WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License
     18  * along with this program; if not, write to the Free Software
     19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
     20  * 02110-1301 USA
     21  */
     22 
     23 #include "config.h"
     24 
     25 #include <sys/time.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 
     30 #include "summary.h"
     31 #include "dict.h"
     32 #include "library.h"
     33 #include "options.h"
     34 
     35 struct entry_st {
     36 	const char *name;
     37 	unsigned count;
     38 	struct timeval tv;
     39 };
     40 
     41 struct fill_struct_data {
     42 	struct vect entries;
     43 	unsigned tot_count;
     44 	unsigned long tot_usecs;
     45 };
     46 
     47 struct opt_c_struct {
     48 	int count;
     49 	struct timeval tv;
     50 };
     51 
     52 static struct dict *dict_opt_c;
     53 
     54 struct timedelta
     55 calc_time_spent(struct timeval start)
     56 {
     57 	struct timeval tv;
     58 	gettimeofday(&tv, NULL);
     59 
     60 	struct timeval diff;
     61 	diff.tv_sec = tv.tv_sec - start.tv_sec;
     62 	if (tv.tv_usec >= start.tv_usec) {
     63 		diff.tv_usec = tv.tv_usec - start.tv_usec;
     64 	} else {
     65 		diff.tv_sec--;
     66 		diff.tv_usec = 1000000 + tv.tv_usec - start.tv_usec;
     67 	}
     68 
     69 	struct timedelta ret = { diff };
     70 	return ret;
     71 }
     72 
     73 static enum callback_status
     74 fill_struct(const char **namep, struct opt_c_struct *st, void *u)
     75 {
     76 	struct fill_struct_data *data = u;
     77 	struct entry_st entry = { *namep, st->count, st->tv };
     78 	if (VECT_PUSHBACK(&data->entries, &entry) < 0)
     79 		return CBS_STOP;
     80 
     81 	data->tot_count += st->count;
     82 	data->tot_usecs += 1000000 * st->tv.tv_sec;
     83 	data->tot_usecs += st->tv.tv_usec;
     84 	return CBS_CONT;
     85 }
     86 
     87 static int
     88 compar(const struct entry_st *en1, const struct entry_st *en2)
     89 {
     90 	if (en2->tv.tv_sec - en1->tv.tv_sec)
     91 		return en2->tv.tv_sec - en1->tv.tv_sec;
     92 	else
     93 		return en2->tv.tv_usec - en1->tv.tv_usec;
     94 }
     95 
     96 static enum callback_status
     97 dump_one(struct entry_st *entry, void *u)
     98 {
     99 	struct fill_struct_data *data = u;
    100 	unsigned long long int c;
    101 	unsigned long long int p;
    102 	c = 1000000 * (int)entry->tv.tv_sec +
    103 		(int)entry->tv.tv_usec;
    104 	p = 100000 * c / data->tot_usecs + 5;
    105 	fprintf(options.output, "%3lu.%02lu %4d.%06d %11lu %9d %s\n",
    106 		(unsigned long int)(p / 1000),
    107 		(unsigned long int)((p / 10) % 100),
    108 		(int)entry->tv.tv_sec, (int)entry->tv.tv_usec,
    109 		(unsigned long int)(c / entry->count),
    110 		entry->count,
    111 #ifdef USE_DEMANGLE
    112 		options.demangle ? my_demangle(entry->name) :
    113 #endif
    114 		entry->name);
    115 
    116 	return CBS_CONT;
    117 }
    118 
    119 void
    120 show_summary(void)
    121 {
    122 	struct fill_struct_data cdata = {};
    123 	VECT_INIT(&cdata.entries, struct entry_st);
    124 
    125 	if (dict_opt_c != NULL) {
    126 		DICT_EACH(dict_opt_c, const char *, struct opt_c_struct, NULL,
    127 			  fill_struct, &cdata);
    128 
    129 		VECT_QSORT(&cdata.entries, struct entry_st, &compar);
    130 	}
    131 
    132 	fprintf(options.output,
    133 		"%% time     seconds  usecs/call     calls      function\n");
    134 	fprintf(options.output,
    135 		"------ ----------- ----------- --------- --------------------\n");
    136 
    137 	VECT_EACH(&cdata.entries, struct entry_st, NULL, dump_one, &cdata);
    138 
    139 	fprintf(options.output,
    140 		"------ ----------- ----------- --------- --------------------\n");
    141 	fprintf(options.output, "100.00 %4lu.%06lu             %9d total\n",
    142 		cdata.tot_usecs / 1000000,
    143 		cdata.tot_usecs % 1000000, cdata.tot_count);
    144 
    145 	vect_destroy(&cdata.entries, NULL, NULL);
    146 }
    147 
    148 static void
    149 free_stringp_cb(const char **stringp, void *data)
    150 {
    151 	free((char *)*stringp);
    152 }
    153 
    154 void
    155 summary_account_call(struct library_symbol *libsym, struct timedelta spent)
    156 {
    157 	assert(options.summary);
    158 
    159 	if (dict_opt_c == NULL) {
    160 		dict_opt_c = malloc(sizeof(*dict_opt_c));
    161 		if (dict_opt_c == NULL) {
    162 		oom:
    163 			fprintf(stderr,
    164 				"Can't allocate memory for "
    165 				"keeping track of -c.\n");
    166 			free(dict_opt_c);
    167 			options.summary = 0;
    168 			return;
    169 		}
    170 		DICT_INIT(dict_opt_c, char *, struct opt_c_struct,
    171 			  dict_hash_string, dict_eq_string, NULL);
    172 	}
    173 
    174 	struct opt_c_struct *st = DICT_FIND_REF(dict_opt_c, &libsym->name,
    175 						struct opt_c_struct);
    176 	if (st == NULL) {
    177 		const char *na = strdup(libsym->name);
    178 		struct opt_c_struct new_st = {.count = 0, .tv = {0, 0}};
    179 		if (na == NULL
    180 		    || DICT_INSERT(dict_opt_c, &na, &new_st) < 0) {
    181 			free((char *) na);
    182 			DICT_DESTROY(dict_opt_c, const char *,
    183 				     struct opt_c_struct,
    184 				     free_stringp_cb, NULL, NULL);
    185 			goto oom;
    186 		}
    187 		st = DICT_FIND_REF(dict_opt_c, &libsym->name,
    188 				   struct opt_c_struct);
    189 		assert(st != NULL);
    190 	}
    191 
    192 	if (st->tv.tv_usec + spent.tm.tv_usec > 1000000) {
    193 		st->tv.tv_usec += spent.tm.tv_usec - 1000000;
    194 		st->tv.tv_sec++;
    195 	} else {
    196 		st->tv.tv_usec += spent.tm.tv_usec;
    197 	}
    198 	st->count++;
    199 	st->tv.tv_sec += spent.tm.tv_sec;
    200 	return;
    201 }
    202