values.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <inttypes.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <linux/zalloc.h>
  8. #include "values.h"
  9. #include "debug.h"
  10. int perf_read_values_init(struct perf_read_values *values)
  11. {
  12. values->threads_max = 16;
  13. values->pid = malloc(values->threads_max * sizeof(*values->pid));
  14. values->tid = malloc(values->threads_max * sizeof(*values->tid));
  15. values->value = zalloc(values->threads_max * sizeof(*values->value));
  16. if (!values->pid || !values->tid || !values->value) {
  17. pr_debug("failed to allocate read_values threads arrays");
  18. goto out_free_pid;
  19. }
  20. values->threads = 0;
  21. values->counters_max = 16;
  22. values->counterrawid = malloc(values->counters_max
  23. * sizeof(*values->counterrawid));
  24. values->countername = malloc(values->counters_max
  25. * sizeof(*values->countername));
  26. if (!values->counterrawid || !values->countername) {
  27. pr_debug("failed to allocate read_values counters arrays");
  28. goto out_free_counter;
  29. }
  30. values->counters = 0;
  31. return 0;
  32. out_free_counter:
  33. zfree(&values->counterrawid);
  34. zfree(&values->countername);
  35. out_free_pid:
  36. zfree(&values->pid);
  37. zfree(&values->tid);
  38. zfree(&values->value);
  39. return -ENOMEM;
  40. }
  41. void perf_read_values_destroy(struct perf_read_values *values)
  42. {
  43. int i;
  44. if (!values->threads_max || !values->counters_max)
  45. return;
  46. for (i = 0; i < values->threads; i++)
  47. zfree(&values->value[i]);
  48. zfree(&values->value);
  49. zfree(&values->pid);
  50. zfree(&values->tid);
  51. zfree(&values->counterrawid);
  52. for (i = 0; i < values->counters; i++)
  53. zfree(&values->countername[i]);
  54. zfree(&values->countername);
  55. }
  56. static int perf_read_values__enlarge_threads(struct perf_read_values *values)
  57. {
  58. int nthreads_max = values->threads_max * 2;
  59. void *npid = realloc(values->pid, nthreads_max * sizeof(*values->pid)),
  60. *ntid = realloc(values->tid, nthreads_max * sizeof(*values->tid)),
  61. *nvalue = realloc(values->value, nthreads_max * sizeof(*values->value));
  62. if (!npid || !ntid || !nvalue)
  63. goto out_err;
  64. values->threads_max = nthreads_max;
  65. values->pid = npid;
  66. values->tid = ntid;
  67. values->value = nvalue;
  68. return 0;
  69. out_err:
  70. free(npid);
  71. free(ntid);
  72. free(nvalue);
  73. pr_debug("failed to enlarge read_values threads arrays");
  74. return -ENOMEM;
  75. }
  76. static int perf_read_values__findnew_thread(struct perf_read_values *values,
  77. u32 pid, u32 tid)
  78. {
  79. int i;
  80. for (i = 0; i < values->threads; i++)
  81. if (values->pid[i] == pid && values->tid[i] == tid)
  82. return i;
  83. if (values->threads == values->threads_max) {
  84. i = perf_read_values__enlarge_threads(values);
  85. if (i < 0)
  86. return i;
  87. }
  88. i = values->threads;
  89. values->value[i] = zalloc(values->counters_max * sizeof(**values->value));
  90. if (!values->value[i]) {
  91. pr_debug("failed to allocate read_values counters array");
  92. return -ENOMEM;
  93. }
  94. values->pid[i] = pid;
  95. values->tid[i] = tid;
  96. values->threads = i + 1;
  97. return i;
  98. }
  99. static int perf_read_values__enlarge_counters(struct perf_read_values *values)
  100. {
  101. char **countername;
  102. int i, counters_max = values->counters_max * 2;
  103. u64 *counterrawid = realloc(values->counterrawid, counters_max * sizeof(*values->counterrawid));
  104. if (!counterrawid) {
  105. pr_debug("failed to enlarge read_values rawid array");
  106. goto out_enomem;
  107. }
  108. countername = realloc(values->countername, counters_max * sizeof(*values->countername));
  109. if (!countername) {
  110. pr_debug("failed to enlarge read_values rawid array");
  111. goto out_free_rawid;
  112. }
  113. for (i = 0; i < values->threads; i++) {
  114. u64 *value = realloc(values->value[i], counters_max * sizeof(**values->value));
  115. int j;
  116. if (!value) {
  117. pr_debug("failed to enlarge read_values ->values array");
  118. goto out_free_name;
  119. }
  120. for (j = values->counters_max; j < counters_max; j++)
  121. value[j] = 0;
  122. values->value[i] = value;
  123. }
  124. values->counters_max = counters_max;
  125. values->counterrawid = counterrawid;
  126. values->countername = countername;
  127. return 0;
  128. out_free_name:
  129. free(countername);
  130. out_free_rawid:
  131. free(counterrawid);
  132. out_enomem:
  133. return -ENOMEM;
  134. }
  135. static int perf_read_values__findnew_counter(struct perf_read_values *values,
  136. u64 rawid, const char *name)
  137. {
  138. int i;
  139. for (i = 0; i < values->counters; i++)
  140. if (values->counterrawid[i] == rawid)
  141. return i;
  142. if (values->counters == values->counters_max) {
  143. i = perf_read_values__enlarge_counters(values);
  144. if (i)
  145. return i;
  146. }
  147. i = values->counters++;
  148. values->counterrawid[i] = rawid;
  149. values->countername[i] = strdup(name);
  150. return i;
  151. }
  152. int perf_read_values_add_value(struct perf_read_values *values,
  153. u32 pid, u32 tid,
  154. u64 rawid, const char *name, u64 value)
  155. {
  156. int tindex, cindex;
  157. tindex = perf_read_values__findnew_thread(values, pid, tid);
  158. if (tindex < 0)
  159. return tindex;
  160. cindex = perf_read_values__findnew_counter(values, rawid, name);
  161. if (cindex < 0)
  162. return cindex;
  163. values->value[tindex][cindex] += value;
  164. return 0;
  165. }
  166. static void perf_read_values__display_pretty(FILE *fp,
  167. struct perf_read_values *values)
  168. {
  169. int i, j;
  170. int pidwidth, tidwidth;
  171. int *counterwidth;
  172. counterwidth = malloc(values->counters * sizeof(*counterwidth));
  173. if (!counterwidth) {
  174. fprintf(fp, "INTERNAL ERROR: Failed to allocate counterwidth array\n");
  175. return;
  176. }
  177. tidwidth = 3;
  178. pidwidth = 3;
  179. for (j = 0; j < values->counters; j++)
  180. counterwidth[j] = strlen(values->countername[j]);
  181. for (i = 0; i < values->threads; i++) {
  182. int width;
  183. width = snprintf(NULL, 0, "%d", values->pid[i]);
  184. if (width > pidwidth)
  185. pidwidth = width;
  186. width = snprintf(NULL, 0, "%d", values->tid[i]);
  187. if (width > tidwidth)
  188. tidwidth = width;
  189. for (j = 0; j < values->counters; j++) {
  190. width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
  191. if (width > counterwidth[j])
  192. counterwidth[j] = width;
  193. }
  194. }
  195. fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
  196. for (j = 0; j < values->counters; j++)
  197. fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
  198. fprintf(fp, "\n");
  199. for (i = 0; i < values->threads; i++) {
  200. fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
  201. tidwidth, values->tid[i]);
  202. for (j = 0; j < values->counters; j++)
  203. fprintf(fp, " %*" PRIu64,
  204. counterwidth[j], values->value[i][j]);
  205. fprintf(fp, "\n");
  206. }
  207. free(counterwidth);
  208. }
  209. static void perf_read_values__display_raw(FILE *fp,
  210. struct perf_read_values *values)
  211. {
  212. int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
  213. int i, j;
  214. tidwidth = 3; /* TID */
  215. pidwidth = 3; /* PID */
  216. namewidth = 4; /* "Name" */
  217. rawwidth = 3; /* "Raw" */
  218. countwidth = 5; /* "Count" */
  219. for (i = 0; i < values->threads; i++) {
  220. width = snprintf(NULL, 0, "%d", values->pid[i]);
  221. if (width > pidwidth)
  222. pidwidth = width;
  223. width = snprintf(NULL, 0, "%d", values->tid[i]);
  224. if (width > tidwidth)
  225. tidwidth = width;
  226. }
  227. for (j = 0; j < values->counters; j++) {
  228. width = strlen(values->countername[j]);
  229. if (width > namewidth)
  230. namewidth = width;
  231. width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
  232. if (width > rawwidth)
  233. rawwidth = width;
  234. }
  235. for (i = 0; i < values->threads; i++) {
  236. for (j = 0; j < values->counters; j++) {
  237. width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
  238. if (width > countwidth)
  239. countwidth = width;
  240. }
  241. }
  242. fprintf(fp, "# %*s %*s %*s %*s %*s\n",
  243. pidwidth, "PID", tidwidth, "TID",
  244. namewidth, "Name", rawwidth, "Raw",
  245. countwidth, "Count");
  246. for (i = 0; i < values->threads; i++)
  247. for (j = 0; j < values->counters; j++)
  248. fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64,
  249. pidwidth, values->pid[i],
  250. tidwidth, values->tid[i],
  251. namewidth, values->countername[j],
  252. rawwidth, values->counterrawid[j],
  253. countwidth, values->value[i][j]);
  254. }
  255. void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw)
  256. {
  257. if (raw)
  258. perf_read_values__display_raw(fp, values);
  259. else
  260. perf_read_values__display_pretty(fp, values);
  261. }