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.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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 struct timespec overhead;
  26. void
  27. count_syscall(struct tcb *tcp, const struct timespec *syscall_exiting_ts)
  28. {
  29. if (!scno_in_range(tcp->scno))
  30. return;
  31. if (!counts)
  32. counts = xcalloc(nsyscalls, sizeof(*counts));
  33. struct call_counts *cc = &counts[tcp->scno];
  34. cc->calls++;
  35. if (syserror(tcp))
  36. cc->errors++;
  37. if (count_wallclock) {
  38. /* wall clock time spent while in syscall */
  39. struct timespec wts;
  40. ts_sub(&wts, syscall_exiting_ts, &tcp->etime);
  41. ts_add(&cc->time, &cc->time, &wts);
  42. } else {
  43. /* system CPU time spent while in syscall */
  44. ts_add(&cc->time, &cc->time, &tcp->dtime);
  45. }
  46. }
  47. static int
  48. time_cmp(void *a, void *b)
  49. {
  50. return -ts_cmp(&counts[*((int *) a)].time,
  51. &counts[*((int *) b)].time);
  52. }
  53. static int
  54. syscall_cmp(void *a, void *b)
  55. {
  56. const char *a_name = sysent[*((int *) a)].sys_name;
  57. const char *b_name = sysent[*((int *) b)].sys_name;
  58. return strcmp(a_name ? a_name : "", b_name ? b_name : "");
  59. }
  60. static int
  61. count_cmp(void *a, void *b)
  62. {
  63. int m = counts[*((int *) a)].calls;
  64. int n = counts[*((int *) b)].calls;
  65. return (m < n) ? 1 : (m > n) ? -1 : 0;
  66. }
  67. static int (*sortfun)();
  68. void
  69. set_sortby(const char *sortby)
  70. {
  71. if (strcmp(sortby, "time") == 0)
  72. sortfun = time_cmp;
  73. else if (strcmp(sortby, "calls") == 0)
  74. sortfun = count_cmp;
  75. else if (strcmp(sortby, "name") == 0)
  76. sortfun = syscall_cmp;
  77. else if (strcmp(sortby, "nothing") == 0)
  78. sortfun = NULL;
  79. else {
  80. error_msg_and_help("invalid sortby: '%s'", sortby);
  81. }
  82. }
  83. void set_overhead(int n)
  84. {
  85. overhead.tv_sec = n / 1000000;
  86. overhead.tv_nsec = n % 1000000 * 1000;
  87. }
  88. static void
  89. call_summary_pers(FILE *outf)
  90. {
  91. static const char dashes[] = "----------------";
  92. static const char header[] = "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n";
  93. static const char data[] = "%6.2f %11.6f %11lu %9u %9.u %s\n";
  94. static const char summary[] = "%6.6s %11.6f %11.11s %9u %9.u %s\n";
  95. unsigned int i;
  96. unsigned int call_cum, error_cum;
  97. struct timespec tv_cum, dtv;
  98. double float_tv_cum;
  99. double percent;
  100. unsigned int *sorted_count;
  101. fprintf(outf, header,
  102. "% time", "seconds", "usecs/call",
  103. "calls", "errors", "syscall");
  104. fprintf(outf, header, dashes, dashes, dashes, dashes, dashes, dashes);
  105. sorted_count = xcalloc(sizeof(sorted_count[0]), nsyscalls);
  106. call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_nsec = 0;
  107. for (i = 0; i < nsyscalls; i++) {
  108. sorted_count[i] = i;
  109. if (counts == NULL || counts[i].calls == 0)
  110. continue;
  111. ts_mul(&dtv, &overhead, counts[i].calls);
  112. ts_sub(&counts[i].time, &counts[i].time, &dtv);
  113. if (counts[i].time.tv_sec < 0 || counts[i].time.tv_nsec < 0)
  114. counts[i].time.tv_sec = counts[i].time.tv_nsec = 0;
  115. call_cum += counts[i].calls;
  116. error_cum += counts[i].errors;
  117. ts_add(&tv_cum, &tv_cum, &counts[i].time);
  118. }
  119. float_tv_cum = ts_float(&tv_cum);
  120. if (counts) {
  121. if (sortfun)
  122. qsort((void *) sorted_count, nsyscalls,
  123. sizeof(sorted_count[0]), sortfun);
  124. for (i = 0; i < nsyscalls; i++) {
  125. double float_syscall_time;
  126. unsigned int idx = sorted_count[i];
  127. struct call_counts *cc = &counts[idx];
  128. if (cc->calls == 0)
  129. continue;
  130. ts_div(&dtv, &cc->time, cc->calls);
  131. float_syscall_time = ts_float(&cc->time);
  132. percent = (100.0 * float_syscall_time);
  133. if (percent != 0.0)
  134. percent /= float_tv_cum;
  135. /* else: float_tv_cum can be 0.0 too and we get 0/0 = NAN */
  136. fprintf(outf, data,
  137. percent, float_syscall_time,
  138. (long) (1000000 * dtv.tv_sec + dtv.tv_nsec / 1000),
  139. cc->calls, cc->errors, sysent[idx].sys_name);
  140. }
  141. }
  142. free(sorted_count);
  143. fprintf(outf, header, dashes, dashes, dashes, dashes, dashes, dashes);
  144. fprintf(outf, summary,
  145. "100.00", float_tv_cum, "",
  146. call_cum, error_cum, "total");
  147. }
  148. void
  149. call_summary(FILE *outf)
  150. {
  151. unsigned int i, old_pers = current_personality;
  152. for (i = 0; i < SUPPORTED_PERSONALITIES; ++i) {
  153. if (!countv[i])
  154. continue;
  155. if (current_personality != i)
  156. set_personality(i);
  157. if (i)
  158. fprintf(outf,
  159. "System call usage summary for %s mode:\n",
  160. personality_names[i]);
  161. call_summary_pers(outf);
  162. }
  163. if (old_pers != current_personality)
  164. set_personality(old_pers);
  165. }