mm_event.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include <linux/mm.h>
  2. #include <linux/mm_event.h>
  3. #include <linux/sched.h>
  4. #include <linux/vmalloc.h>
  5. #include <linux/seq_file.h>
  6. #include <linux/debugfs.h>
  7. #define CREATE_TRACE_POINTS
  8. #include <trace/events/mm_event.h>
  9. /* msec */
  10. static unsigned long period_ms __read_mostly = 500;
  11. static unsigned long vmstat_period_ms __read_mostly = 1000;
  12. static unsigned long vmstat_next_period;
  13. static DEFINE_SPINLOCK(vmstat_lock);
  14. static DEFINE_RWLOCK(period_lock);
  15. void mm_event_task_init(struct task_struct *tsk)
  16. {
  17. memset(tsk->mm_event, 0, sizeof(tsk->mm_event));
  18. tsk->next_period = 0;
  19. }
  20. static void record_vmstat(void)
  21. {
  22. int cpu;
  23. struct mm_event_vmstat vmstat;
  24. if (time_is_after_jiffies(vmstat_next_period))
  25. return;
  26. /* Need double check under the lock */
  27. spin_lock(&vmstat_lock);
  28. if (time_is_after_jiffies(vmstat_next_period)) {
  29. spin_unlock(&vmstat_lock);
  30. return;
  31. }
  32. vmstat_next_period = jiffies + msecs_to_jiffies(vmstat_period_ms);
  33. spin_unlock(&vmstat_lock);
  34. memset(&vmstat, 0, sizeof(vmstat));
  35. vmstat.free = global_page_state(NR_FREE_PAGES);
  36. vmstat.slab = global_page_state(NR_SLAB_RECLAIMABLE) +
  37. global_page_state(NR_SLAB_UNRECLAIMABLE);
  38. vmstat.file = global_node_page_state(NR_ACTIVE_FILE) +
  39. global_node_page_state(NR_INACTIVE_FILE);
  40. vmstat.anon = global_node_page_state(NR_ACTIVE_ANON) +
  41. global_node_page_state(NR_INACTIVE_ANON);
  42. vmstat.ion = global_node_page_state(NR_ION_HEAP);
  43. vmstat.ws_refault = global_node_page_state(WORKINGSET_REFAULT);
  44. vmstat.ws_activate = global_node_page_state(WORKINGSET_ACTIVATE);
  45. vmstat.mapped = global_node_page_state(NR_FILE_MAPPED);
  46. for_each_online_cpu(cpu) {
  47. struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
  48. /* sectors to kbytes for PGPGIN/PGPGOUT */
  49. vmstat.pgin += this->event[PGPGIN] / 2;
  50. vmstat.pgout += this->event[PGPGOUT] / 2;
  51. vmstat.swpin += this->event[PSWPIN];
  52. vmstat.swpout += this->event[PSWPOUT];
  53. vmstat.reclaim_steal += this->event[PGSTEAL_DIRECT] +
  54. this->event[PGSTEAL_KSWAPD];
  55. vmstat.reclaim_scan += this->event[PGSCAN_DIRECT] +
  56. this->event[PGSCAN_KSWAPD];
  57. vmstat.compact_scan += this->event[COMPACTFREE_SCANNED] +
  58. this->event[COMPACTMIGRATE_SCANNED];
  59. }
  60. trace_mm_event_vmstat_record(&vmstat);
  61. }
  62. static void record_stat(void)
  63. {
  64. int i;
  65. bool need_vmstat = false;
  66. if (time_is_after_jiffies(current->next_period))
  67. return;
  68. read_lock(&period_lock);
  69. current->next_period = jiffies + msecs_to_jiffies(period_ms);
  70. read_unlock(&period_lock);
  71. for (i = 0; i < MM_TYPE_NUM; i++) {
  72. if (current->mm_event[i].count == 0)
  73. continue;
  74. if (i == MM_COMPACTION || i == MM_RECLAIM)
  75. need_vmstat = true;
  76. trace_mm_event_record(i, &current->mm_event[i]);
  77. memset(&current->mm_event[i], 0,
  78. sizeof(struct mm_event_task));
  79. }
  80. if (need_vmstat)
  81. record_vmstat();
  82. }
  83. void mm_event_start(ktime_t *time)
  84. {
  85. *time = ktime_get();
  86. }
  87. void mm_event_end(enum mm_event_type event, ktime_t start)
  88. {
  89. s64 elapsed = ktime_us_delta(ktime_get(), start);
  90. current->mm_event[event].count++;
  91. current->mm_event[event].accm_lat += elapsed;
  92. if (elapsed > current->mm_event[event].max_lat)
  93. current->mm_event[event].max_lat = elapsed;
  94. record_stat();
  95. }
  96. void mm_event_count(enum mm_event_type event, int count)
  97. {
  98. current->mm_event[event].count += count;
  99. record_stat();
  100. }
  101. static struct dentry *mm_event_root;
  102. static int period_ms_set(void *data, u64 val)
  103. {
  104. if (val < 1 || val > ULONG_MAX)
  105. return -EINVAL;
  106. write_lock(&period_lock);
  107. period_ms = (unsigned long)val;
  108. write_unlock(&period_lock);
  109. return 0;
  110. }
  111. static int period_ms_get(void *data, u64 *val)
  112. {
  113. read_lock(&period_lock);
  114. *val = period_ms;
  115. read_unlock(&period_lock);
  116. return 0;
  117. }
  118. static int vmstat_period_ms_set(void *data, u64 val)
  119. {
  120. if (val < 1 || val > ULONG_MAX)
  121. return -EINVAL;
  122. spin_lock(&vmstat_lock);
  123. vmstat_period_ms = (unsigned long)val;
  124. spin_unlock(&vmstat_lock);
  125. return 0;
  126. }
  127. static int vmstat_period_ms_get(void *data, u64 *val)
  128. {
  129. spin_lock(&vmstat_lock);
  130. *val = vmstat_period_ms;
  131. spin_unlock(&vmstat_lock);
  132. return 0;
  133. }
  134. DEFINE_SIMPLE_ATTRIBUTE(period_ms_operations, period_ms_get,
  135. period_ms_set, "%llu\n");
  136. DEFINE_SIMPLE_ATTRIBUTE(vmstat_period_ms_operations, vmstat_period_ms_get,
  137. vmstat_period_ms_set, "%llu\n");
  138. static int __init mm_event_init(void)
  139. {
  140. struct dentry *entry;
  141. mm_event_root = debugfs_create_dir("mm_event", NULL);
  142. if (!mm_event_root) {
  143. pr_warn("debugfs dir <mm_event> creation failed\n");
  144. return PTR_ERR(mm_event_root);
  145. }
  146. entry = debugfs_create_file("period_ms", 0644,
  147. mm_event_root, NULL, &period_ms_operations);
  148. if (IS_ERR(entry)) {
  149. pr_warn("debugfs file mm_event_task creation failed\n");
  150. debugfs_remove_recursive(mm_event_root);
  151. return PTR_ERR(entry);
  152. }
  153. entry = debugfs_create_file("vmstat_period_ms", 0644,
  154. mm_event_root, NULL, &vmstat_period_ms_operations);
  155. if (IS_ERR(entry)) {
  156. pr_warn("debugfs file vmstat_mm_event_task creation failed\n");
  157. debugfs_remove_recursive(mm_event_root);
  158. return PTR_ERR(entry);
  159. }
  160. return 0;
  161. }
  162. subsys_initcall(mm_event_init);