mem-events.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #include <stddef.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <unistd.h>
  8. #include <api/fs/fs.h>
  9. #include "mem-events.h"
  10. #include "debug.h"
  11. #include "symbol.h"
  12. unsigned int perf_mem_events__loads_ldlat = 30;
  13. #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
  14. struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
  15. E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
  16. E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
  17. };
  18. #undef E
  19. #undef E
  20. static char mem_loads_name[100];
  21. static bool mem_loads_name__init;
  22. char *perf_mem_events__name(int i)
  23. {
  24. if (i == PERF_MEM_EVENTS__LOAD) {
  25. if (!mem_loads_name__init) {
  26. mem_loads_name__init = true;
  27. scnprintf(mem_loads_name, sizeof(mem_loads_name),
  28. perf_mem_events[i].name,
  29. perf_mem_events__loads_ldlat);
  30. }
  31. return mem_loads_name;
  32. }
  33. return (char *)perf_mem_events[i].name;
  34. }
  35. int perf_mem_events__parse(const char *str)
  36. {
  37. char *tok, *saveptr = NULL;
  38. bool found = false;
  39. char *buf;
  40. int j;
  41. /* We need buffer that we know we can write to. */
  42. buf = malloc(strlen(str) + 1);
  43. if (!buf)
  44. return -ENOMEM;
  45. strcpy(buf, str);
  46. tok = strtok_r((char *)buf, ",", &saveptr);
  47. while (tok) {
  48. for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
  49. struct perf_mem_event *e = &perf_mem_events[j];
  50. if (strstr(e->tag, tok))
  51. e->record = found = true;
  52. }
  53. tok = strtok_r(NULL, ",", &saveptr);
  54. }
  55. free(buf);
  56. if (found)
  57. return 0;
  58. pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
  59. return -1;
  60. }
  61. int perf_mem_events__init(void)
  62. {
  63. const char *mnt = sysfs__mount();
  64. bool found = false;
  65. int j;
  66. if (!mnt)
  67. return -ENOENT;
  68. for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
  69. char path[PATH_MAX];
  70. struct perf_mem_event *e = &perf_mem_events[j];
  71. struct stat st;
  72. scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
  73. mnt, e->sysfs_name);
  74. if (!stat(path, &st))
  75. e->supported = found = true;
  76. }
  77. return found ? 0 : -ENOENT;
  78. }
  79. static const char * const tlb_access[] = {
  80. "N/A",
  81. "HIT",
  82. "MISS",
  83. "L1",
  84. "L2",
  85. "Walker",
  86. "Fault",
  87. };
  88. int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
  89. {
  90. size_t l = 0, i;
  91. u64 m = PERF_MEM_TLB_NA;
  92. u64 hit, miss;
  93. sz -= 1; /* -1 for null termination */
  94. out[0] = '\0';
  95. if (mem_info)
  96. m = mem_info->data_src.mem_dtlb;
  97. hit = m & PERF_MEM_TLB_HIT;
  98. miss = m & PERF_MEM_TLB_MISS;
  99. /* already taken care of */
  100. m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
  101. for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
  102. if (!(m & 0x1))
  103. continue;
  104. if (l) {
  105. strcat(out, " or ");
  106. l += 4;
  107. }
  108. l += scnprintf(out + l, sz - l, tlb_access[i]);
  109. }
  110. if (*out == '\0')
  111. l += scnprintf(out, sz - l, "N/A");
  112. if (hit)
  113. l += scnprintf(out + l, sz - l, " hit");
  114. if (miss)
  115. l += scnprintf(out + l, sz - l, " miss");
  116. return l;
  117. }
  118. static const char * const mem_lvl[] = {
  119. "N/A",
  120. "HIT",
  121. "MISS",
  122. "L1",
  123. "LFB",
  124. "L2",
  125. "L3",
  126. "Local RAM",
  127. "Remote RAM (1 hop)",
  128. "Remote RAM (2 hops)",
  129. "Remote Cache (1 hop)",
  130. "Remote Cache (2 hops)",
  131. "I/O",
  132. "Uncached",
  133. };
  134. int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
  135. {
  136. size_t i, l = 0;
  137. u64 m = PERF_MEM_LVL_NA;
  138. u64 hit, miss;
  139. if (mem_info)
  140. m = mem_info->data_src.mem_lvl;
  141. sz -= 1; /* -1 for null termination */
  142. out[0] = '\0';
  143. hit = m & PERF_MEM_LVL_HIT;
  144. miss = m & PERF_MEM_LVL_MISS;
  145. /* already taken care of */
  146. m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
  147. for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
  148. if (!(m & 0x1))
  149. continue;
  150. if (l) {
  151. strcat(out, " or ");
  152. l += 4;
  153. }
  154. l += scnprintf(out + l, sz - l, mem_lvl[i]);
  155. }
  156. if (*out == '\0')
  157. l += scnprintf(out, sz - l, "N/A");
  158. if (hit)
  159. l += scnprintf(out + l, sz - l, " hit");
  160. if (miss)
  161. l += scnprintf(out + l, sz - l, " miss");
  162. return l;
  163. }
  164. static const char * const snoop_access[] = {
  165. "N/A",
  166. "None",
  167. "Miss",
  168. "Hit",
  169. "HitM",
  170. };
  171. int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
  172. {
  173. size_t i, l = 0;
  174. u64 m = PERF_MEM_SNOOP_NA;
  175. sz -= 1; /* -1 for null termination */
  176. out[0] = '\0';
  177. if (mem_info)
  178. m = mem_info->data_src.mem_snoop;
  179. for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
  180. if (!(m & 0x1))
  181. continue;
  182. if (l) {
  183. strcat(out, " or ");
  184. l += 4;
  185. }
  186. l += scnprintf(out + l, sz - l, snoop_access[i]);
  187. }
  188. if (*out == '\0')
  189. l += scnprintf(out, sz - l, "N/A");
  190. return l;
  191. }
  192. int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
  193. {
  194. u64 mask = PERF_MEM_LOCK_NA;
  195. int l;
  196. if (mem_info)
  197. mask = mem_info->data_src.mem_lock;
  198. if (mask & PERF_MEM_LOCK_NA)
  199. l = scnprintf(out, sz, "N/A");
  200. else if (mask & PERF_MEM_LOCK_LOCKED)
  201. l = scnprintf(out, sz, "Yes");
  202. else
  203. l = scnprintf(out, sz, "No");
  204. return l;
  205. }
  206. int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
  207. {
  208. int i = 0;
  209. i += perf_mem__lvl_scnprintf(out, sz, mem_info);
  210. i += scnprintf(out + i, sz - i, "|SNP ");
  211. i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
  212. i += scnprintf(out + i, sz - i, "|TLB ");
  213. i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
  214. i += scnprintf(out + i, sz - i, "|LCK ");
  215. i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
  216. return i;
  217. }