values.c 7.7 KB

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