Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

count.c 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
  3. * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
  4. * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
  5. * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
  6. * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  7. * Linux for s390 port by D.J. Barrow
  8. * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
  9. * Copyright (c) 2004 Roland McGrath <roland@redhat.com>
  10. * Copyright (c) 2006 Dmitry V. Levin <ldv@altlinux.org>
  11. * Copyright (c) 2006-2018 The strace developers.
  12. * All rights reserved.
  13. *
  14. * SPDX-License-Identifier: LGPL-2.1-or-later
  15. */
  16. #include "defs.h"
  17. /* Per-syscall stats structure */
  18. struct call_counts {
  19. /* time may be total latency or system time */
  20. struct timespec time;
  21. unsigned int calls, errors;
  22. };
  23. static struct call_counts *countv[SUPPORTED_PERSONALITIES];
  24. #define counts (countv[current_personality])
  25. static const struct timespec zero_ts;
  26. static struct timespec overhead;
  27. void
  28. count_syscall(struct tcb *tcp, const struct timespec *syscall_exiting_ts)
  29. {
  30. if (!scno_in_range(tcp->scno))
  31. return;
  32. if (!counts)
  33. counts = xcalloc(nsyscalls, sizeof(*counts));
  34. struct call_counts *cc = &counts[tcp->scno];
  35. cc->calls++;
  36. if (syserror(tcp))
  37. cc->errors++;
  38. struct timespec wts;
  39. if (count_wallclock) {
  40. /* wall clock time spent while in syscall */
  41. ts_sub(&wts, syscall_exiting_ts, &tcp->etime);
  42. } else {
  43. /* system CPU time spent while in syscall */
  44. ts_sub(&wts, &tcp->stime, &tcp->ltime);
  45. }
  46. ts_sub(&wts, &wts, &overhead);
  47. ts_add(&cc->time, &cc->time, ts_max(&wts, &zero_ts));
  48. }
  49. static int
  50. time_cmp(const void *a, const void *b)
  51. {
  52. const unsigned int *a_int = a;
  53. const unsigned int *b_int = b;
  54. return -ts_cmp(&counts[*a_int].time, &counts[*b_int].time);
  55. }
  56. static int
  57. syscall_cmp(const void *a, const void *b)
  58. {
  59. const unsigned int *a_int = a;
  60. const unsigned int *b_int = b;
  61. const char *a_name = sysent[*a_int].sys_name;
  62. const char *b_name = sysent[*b_int].sys_name;
  63. return strcmp(a_name ? a_name : "", b_name ? b_name : "");
  64. }
  65. static int
  66. count_cmp(const void *a, const void *b)
  67. {
  68. const unsigned int *a_int = a;
  69. const unsigned int *b_int = b;
  70. unsigned int m = counts[*a_int].calls;
  71. unsigned int n = counts[*b_int].calls;
  72. return (m < n) ? 1 : (m > n) ? -1 : 0;
  73. }
  74. static int
  75. error_cmp(const void *a, const void *b)
  76. {
  77. const unsigned int *a_int = a;
  78. const unsigned int *b_int = b;
  79. unsigned int m = counts[*a_int].errors;
  80. unsigned int n = counts[*b_int].errors;
  81. return (m < n) ? 1 : (m > n) ? -1 : 0;
  82. }
  83. static int (*sortfun)(const void *, const void *);
  84. void
  85. set_sortby(const char *sortby)
  86. {
  87. static const struct {
  88. int (*fn)(const void *, const void *);
  89. const char *name;
  90. } sort_fns[] = {
  91. { time_cmp, "time" },
  92. { time_cmp, "time_total" },
  93. { time_cmp, "total_time" },
  94. { count_cmp, "calls" },
  95. { count_cmp, "count" },
  96. { error_cmp, "error" },
  97. { error_cmp, "errors" },
  98. { syscall_cmp, "name" },
  99. { syscall_cmp, "syscall" },
  100. { syscall_cmp, "syscall_name" },
  101. { NULL, "none" },
  102. { NULL, "nothing" },
  103. };
  104. for (size_t i = 0; i < ARRAY_SIZE(sort_fns); ++i) {
  105. if (!strcmp(sort_fns[i].name, sortby)) {
  106. sortfun = sort_fns[i].fn;
  107. return;
  108. }
  109. }
  110. error_msg_and_help("invalid sortby: '%s'", sortby);
  111. }
  112. int
  113. set_overhead(const char *str)
  114. {
  115. return parse_ts(str, &overhead);
  116. }
  117. static void
  118. call_summary_pers(FILE *outf)
  119. {
  120. static const char dashes[] = "----------------";
  121. static const char header[] = "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n";
  122. static const char data[] = "%6.2f %11.6f %11lu %9u %9.u %s\n";
  123. static const char summary[] = "%6.6s %11.6f %11.11s %9u %9.u %s\n";
  124. unsigned int i;
  125. unsigned int call_cum, error_cum;
  126. struct timespec tv_cum, dtv;
  127. double float_tv_cum;
  128. double percent;
  129. unsigned int *sorted_count;
  130. fprintf(outf, header,
  131. "% time", "seconds", "usecs/call",
  132. "calls", "errors", "syscall");
  133. fprintf(outf, header, dashes, dashes, dashes, dashes, dashes, dashes);
  134. sorted_count = xcalloc(sizeof(sorted_count[0]), nsyscalls);
  135. call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_nsec = 0;
  136. for (i = 0; i < nsyscalls; i++) {
  137. sorted_count[i] = i;
  138. if (counts == NULL || counts[i].calls == 0)
  139. continue;
  140. call_cum += counts[i].calls;
  141. error_cum += counts[i].errors;
  142. ts_add(&tv_cum, &tv_cum, &counts[i].time);
  143. }
  144. float_tv_cum = ts_float(&tv_cum);
  145. if (counts) {
  146. if (sortfun)
  147. qsort((void *) sorted_count, nsyscalls,
  148. sizeof(sorted_count[0]), sortfun);
  149. for (i = 0; i < nsyscalls; i++) {
  150. double float_syscall_time;
  151. unsigned int idx = sorted_count[i];
  152. struct call_counts *cc = &counts[idx];
  153. if (cc->calls == 0)
  154. continue;
  155. ts_div(&dtv, &cc->time, cc->calls);
  156. float_syscall_time = ts_float(&cc->time);
  157. percent = (100.0 * float_syscall_time);
  158. if (percent != 0.0)
  159. percent /= float_tv_cum;
  160. /* else: float_tv_cum can be 0.0 too and we get 0/0 = NAN */
  161. fprintf(outf, data,
  162. percent, float_syscall_time,
  163. (long) (1000000 * dtv.tv_sec + dtv.tv_nsec / 1000),
  164. cc->calls, cc->errors, sysent[idx].sys_name);
  165. }
  166. }
  167. free(sorted_count);
  168. fprintf(outf, header, dashes, dashes, dashes, dashes, dashes, dashes);
  169. fprintf(outf, summary,
  170. "100.00", float_tv_cum, "",
  171. call_cum, error_cum, "total");
  172. }
  173. void
  174. call_summary(FILE *outf)
  175. {
  176. unsigned int i, old_pers = current_personality;
  177. for (i = 0; i < SUPPORTED_PERSONALITIES; ++i) {
  178. if (!countv[i])
  179. continue;
  180. if (current_personality != i)
  181. set_personality(i);
  182. if (i)
  183. fprintf(outf,
  184. "System call usage summary for %s mode:\n",
  185. personality_names[i]);
  186. call_summary_pers(outf);
  187. }
  188. if (old_pers != current_personality)
  189. set_personality(old_pers);
  190. }