mem-events.c 4.8 KB

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