Advertisement
arter97

Untitled

Feb 25th, 2020
806
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 10.19 KB | None | 0 0
  1. From 43a81aebbcba11bfca75c84c0a497ff295e3a4b2 Mon Sep 17 00:00:00 2001
  2. From: Sultan Alsawaf <sultan@kerneltoast.com>
  3. Date: Wed, 3 Jul 2019 10:22:54 -0700
  4. Subject: [PATCH] alloc_stats
  5.  
  6. ---
  7. include/linux/mm_types.h |   1 +
  8.  include/linux/slab.h     | 128 ++++++++++++++++++++++++++++++++++++
  9.  mm/Makefile              |   1 +
  10.  mm/alloc_stats.c         | 137 +++++++++++++++++++++++++++++++++++++++
  11.  mm/slab_common.c         |   2 +-
  12.  mm/slub.c                |   6 +-
  13.  6 files changed, 271 insertions(+), 4 deletions(-)
  14.  create mode 100644 mm/alloc_stats.c
  15.  
  16. diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
  17. index fe6349928da2..7116f0aa68af 100644
  18. --- a/include/linux/mm_types.h
  19. +++ b/include/linux/mm_types.h
  20. @@ -223,6 +223,7 @@ struct page {
  21.  #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
  22.     int _last_cpupid;
  23.  #endif
  24. +   void *alloc_stats;
  25.  }
  26.  /*
  27.   * The struct page can be forced to be double word aligned so that atomic ops
  28. diff --git a/include/linux/slab.h b/include/linux/slab.h
  29. index 16dc1e4a91f3..4133bbbc324a 100644
  30. --- a/include/linux/slab.h
  31. +++ b/include/linux/slab.h
  32. @@ -634,4 +634,132 @@ static inline void *kzalloc_node(size_t size, gfp_t flags, int node)
  33.  unsigned int kmem_cache_size(struct kmem_cache *s);
  34.  void __init kmem_cache_init_late(void);
  35.  
  36. +#include <linux/mm.h>
  37. +#ifdef CONFIG_SLAB
  38. +#include <linux/slab_def.h>
  39. +#endif
  40. +#ifdef CONFIG_SLUB
  41. +#include <linux/slub_def.h>
  42. +#endif
  43. +void *alloc_stats_add(const char *file, const char *func, int line, size_t size);
  44. +void alloc_stats_free(void *stats_ptr, const char *func);
  45. +#define kzalloc(__size, __flags) \
  46. +({                                 \
  47. +   void *__objp;                           \
  48. +                                   \
  49. +   __objp = (kzalloc)(__size, __flags);                \
  50. +   if (__objp && virt_addr_valid(__objp)) {            \
  51. +       struct page *__page = virt_to_head_page(__objp);    \
  52. +                                   \
  53. +       __page->alloc_stats = alloc_stats_add(__FILE__,     \
  54. +                             __func__,     \
  55. +                             __LINE__,     \
  56. +                             __size);      \
  57. +   }                               \
  58. +                                   \
  59. +   __objp;                             \
  60. +})
  61. +
  62. +#define kmalloc(__size, __flags) \
  63. +({                                 \
  64. +   void *__objp;                           \
  65. +                                   \
  66. +   __objp = (kmalloc)(__size, __flags);                \
  67. +   if (__objp && virt_addr_valid(__objp)) {            \
  68. +       struct page *__page = virt_to_head_page(__objp);    \
  69. +                                   \
  70. +       __page->alloc_stats = alloc_stats_add(__FILE__,     \
  71. +                             __func__,     \
  72. +                             __LINE__,     \
  73. +                             __size);      \
  74. +   }                               \
  75. +                                   \
  76. +   __objp;                             \
  77. +})
  78. +
  79. +#define kcalloc(__n, __size, __flags) \
  80. +({                                 \
  81. +   void *__objp;                           \
  82. +                                   \
  83. +   __objp = (kcalloc)(__n, __size, __flags);           \
  84. +   if (__objp && virt_addr_valid(__objp)) {            \
  85. +       struct page *__page = virt_to_head_page(__objp);    \
  86. +                                   \
  87. +       __page->alloc_stats = alloc_stats_add(__FILE__,     \
  88. +                             __func__,     \
  89. +                             __LINE__,     \
  90. +                             (__n) * (__size));\
  91. +   }                               \
  92. +                                   \
  93. +   __objp;                             \
  94. +})
  95. +
  96. +#define kmem_cache_alloc(__cache, __flags) \
  97. +({                                 \
  98. +   void *__objp;                           \
  99. +                                   \
  100. +   __objp = kmem_cache_alloc(__cache, __flags);            \
  101. +   if (__objp && virt_addr_valid(__objp)) {            \
  102. +       struct page *__page = virt_to_head_page(__objp);    \
  103. +       struct kmem_cache *__c = (void *)(__cache);     \
  104. +                                   \
  105. +       __page->alloc_stats = alloc_stats_add(__FILE__,     \
  106. +                             __func__,     \
  107. +                             __LINE__,     \
  108. +                             __c->object_size);\
  109. +   }                               \
  110. +                                   \
  111. +   __objp;                             \
  112. +})
  113. +
  114. +#define kmem_cache_zalloc(__cache, __flags) \
  115. +({                                 \
  116. +   void *__objp;                           \
  117. +                                   \
  118. +   __objp = kmem_cache_zalloc(__cache, __flags);           \
  119. +   if (__objp && virt_addr_valid(__objp)) {            \
  120. +       struct page *__page = virt_to_head_page(__objp);    \
  121. +       struct kmem_cache *__c = (void *)(__cache);     \
  122. +                                   \
  123. +       __page->alloc_stats = alloc_stats_add(__FILE__,     \
  124. +                             __func__,     \
  125. +                             __LINE__,     \
  126. +                             __c->object_size);\
  127. +   }                               \
  128. +                                   \
  129. +   __objp;                             \
  130. +})
  131. +
  132. +#define kfree(__objp) \
  133. +({                                 \
  134. +   if (!ZERO_OR_NULL_PTR(__objp) && virt_addr_valid(__objp)) { \
  135. +       struct page *__page = virt_to_head_page(__objp);    \
  136. +                                   \
  137. +       alloc_stats_free(__page->alloc_stats, __func__);    \
  138. +   }                               \
  139. +                                   \
  140. +   (kfree)(__objp);                        \
  141. +})
  142. +
  143. +#define kzfree(__objp) \
  144. +({                                 \
  145. +   if (!ZERO_OR_NULL_PTR(__objp) && virt_addr_valid(__objp)) { \
  146. +       struct page *__page = virt_to_head_page(__objp);    \
  147. +                                   \
  148. +       alloc_stats_free(__page->alloc_stats, __func__);    \
  149. +   }                               \
  150. +                                   \
  151. +   (kzfree)(__objp);                       \
  152. +})
  153. +
  154. +#define kmem_cache_free(__cache, __objp) \
  155. +({                                 \
  156. +   struct page *__page = virt_to_head_page(__objp);        \
  157. +                                   \
  158. +   if (__page->slab_cache == (__cache))                \
  159. +       alloc_stats_free(__page->alloc_stats, __func__);    \
  160. +                                   \
  161. +   (kmem_cache_free)(__cache, __objp);             \
  162. +})
  163. +
  164.  #endif /* _LINUX_SLAB_H */
  165. diff --git a/mm/Makefile b/mm/Makefile
  166. index 2d44b2cb6908..8bb7eb20f38b 100644
  167. --- a/mm/Makefile
  168. +++ b/mm/Makefile
  169. @@ -103,3 +103,4 @@ obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
  170.  obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
  171.  obj-$(CONFIG_PROCESS_RECLAIM)  += process_reclaim.o
  172.  obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o
  173. +obj-y += alloc_stats.o
  174. diff --git a/mm/alloc_stats.c b/mm/alloc_stats.c
  175. new file mode 100644
  176. index 000000000000..87c49e3e78c2
  177. --- /dev/null
  178. +++ b/mm/alloc_stats.c
  179. @@ -0,0 +1,137 @@
  180. +#include <linux/atomic.h>
  181. +#include <linux/kernel.h>
  182. +#include <linux/proc_fs.h>
  183. +#include <linux/seq_file.h>
  184. +#include <linux/sort.h>
  185. +
  186. +struct alloc_stats {
  187. +   const char *file;
  188. +   const char *func;
  189. +   size_t min_size;
  190. +   size_t max_size;
  191. +   int line;
  192. +   atomic_t freed_samefunc;
  193. +   atomic_t count;
  194. +} __aligned(8);
  195. +
  196. +static struct alloc_stats alloc_stats_g[SZ_32M / sizeof(struct alloc_stats)];
  197. +static DEFINE_SPINLOCK(stats_lock);
  198. +
  199. +void *alloc_stats_add(const char *file, const char *func, int line, size_t size)
  200. +{
  201. +   struct alloc_stats *stats;
  202. +   bool success = false;
  203. +   unsigned long flags;
  204. +   int i;
  205. +
  206. +   spin_lock_irqsave(&stats_lock, flags);
  207. +   for (i = 0; i < ARRAY_SIZE(alloc_stats_g); i++) {
  208. +       stats = alloc_stats_g + i;
  209. +
  210. +       if (!stats->file) {
  211. +           stats->file = file;
  212. +           stats->func = func;
  213. +           stats->line = line;
  214. +           stats->min_size = stats->max_size = size;
  215. +           atomic_set(&stats->count, 1);
  216. +           success = true;
  217. +           break;
  218. +       }
  219. +
  220. +       if (stats->file == file && stats->line == line) {
  221. +           if (size < stats->min_size)
  222. +               stats->min_size = size;
  223. +           if (size > stats->max_size)
  224. +               stats->max_size = size;
  225. +           atomic_inc(&stats->count);
  226. +           success = true;
  227. +           break;
  228. +       }
  229. +   }
  230. +   spin_unlock_irqrestore(&stats_lock, flags);
  231. +
  232. +   return success ? stats : NULL;
  233. +}
  234. +
  235. +void alloc_stats_free(void *stats_ptr, const char *func)
  236. +{
  237. +   struct alloc_stats *stats = stats_ptr;
  238. +
  239. +   if (stats < alloc_stats_g ||
  240. +       stats > &alloc_stats_g[ARRAY_SIZE(alloc_stats_g) - 1])
  241. +       return;
  242. +
  243. +   if (stats->func == func)
  244. +       atomic_inc(&stats->freed_samefunc);
  245. +}
  246. +
  247. +static int alloc_count_cmp(const void *lhs_ptr, const void *rhs_ptr)
  248. +{
  249. +   const struct alloc_stats *lhs = (typeof(lhs))lhs_ptr;
  250. +   const struct alloc_stats *rhs = (typeof(rhs))rhs_ptr;
  251. +
  252. +   return atomic_read(&rhs->count) - atomic_read(&lhs->count);
  253. +}
  254. +
  255. +static int alloc_stats_show(struct seq_file *m, void *unused)
  256. +{
  257. +   unsigned long flags;
  258. +   int i, count;
  259. +
  260. +   spin_lock_irqsave(&stats_lock, flags);
  261. +   for (count = 0; count < ARRAY_SIZE(alloc_stats_g); count++) {
  262. +       struct alloc_stats *stats = alloc_stats_g + count;
  263. +
  264. +       if (!stats->file)
  265. +           break;
  266. +   }
  267. +   if (count)
  268. +       sort(alloc_stats_g, count, sizeof(*alloc_stats_g),
  269. +            alloc_count_cmp, NULL);
  270. +   spin_unlock_irqrestore(&stats_lock, flags);
  271. +
  272. +   seq_printf(m, "[freed same func] [count] [size (range)] [file:line]\n");
  273. +   for (i = 0; i < count; i++) {
  274. +       struct alloc_stats *stats = alloc_stats_g + i;
  275. +       char size_str[SZ_128];
  276. +
  277. +       if (stats->min_size == stats->max_size)
  278. +           snprintf(size_str, sizeof(size_str), "%luB",
  279. +                stats->min_size);
  280. +       else
  281. +           snprintf(size_str, sizeof(size_str), "[%luB, %luB]",
  282. +                stats->min_size, stats->max_size);
  283. +
  284. +       if (atomic_read(&stats->freed_samefunc))
  285. +           seq_printf(m, "%10dx %10dx %20s at %s:%d\n",
  286. +                  atomic_read(&stats->freed_samefunc),
  287. +                  atomic_read(&stats->count), size_str,
  288. +                  stats->file, stats->line);
  289. +       else
  290. +           seq_printf(m, "            %10dx %20s at %s:%d\n",
  291. +                  atomic_read(&stats->count), size_str,
  292. +                  stats->file, stats->line);
  293. +   }
  294. +
  295. +   return 0;
  296. +}
  297. +
  298. +static int alloc_stats_open(struct inode *inode, struct file *file)
  299. +{
  300. +   return single_open(file, alloc_stats_show, NULL);
  301. +}
  302. +
  303. +static const struct file_operations alloc_stats_fops = {
  304. +   .owner = THIS_MODULE,
  305. +   .open = alloc_stats_open,
  306. +   .read = seq_read,
  307. +   .llseek = seq_lseek,
  308. +   .release = single_release
  309. +};
  310. +
  311. +static int __init alloc_stats_init(void)
  312. +{
  313. +   proc_create("alloc_stats", S_IRUGO, NULL, &alloc_stats_fops);
  314. +   return 0;
  315. +}
  316. +late_initcall(alloc_stats_init);
  317. diff --git a/mm/slab_common.c b/mm/slab_common.c
  318. index 7315b368e834..f8d7186fc649 100644
  319. --- a/mm/slab_common.c
  320. +++ b/mm/slab_common.c
  321. @@ -1316,7 +1316,7 @@ EXPORT_SYMBOL(krealloc);
  322.   * deal bigger than the requested buffer size passed to kmalloc(). So be
  323.   * careful when using this function in performance sensitive code.
  324.   */
  325. -void kzfree(const void *p)
  326. +void (kzfree)(const void *p)
  327.  {
  328.     size_t ks;
  329.     void *mem = (void *)p;
  330. diff --git a/mm/slub.c b/mm/slub.c
  331. index 447a2f1b0b4d..b1b01580ad79 100644
  332. --- a/mm/slub.c
  333. +++ b/mm/slub.c
  334. @@ -2681,7 +2681,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
  335.     return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
  336.  }
  337.  
  338. -void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
  339. +void *(kmem_cache_alloc)(struct kmem_cache *s, gfp_t gfpflags)
  340.  {
  341.     void *ret = slab_alloc(s, gfpflags, _RET_IP_);
  342.  
  343. @@ -2931,7 +2931,7 @@ void ___cache_free(struct kmem_cache *cache, void *x, unsigned long addr)
  344.  }
  345.  #endif
  346.  
  347. -void kmem_cache_free(struct kmem_cache *s, void *x)
  348. +void (kmem_cache_free)(struct kmem_cache *s, void *x)
  349.  {
  350.     s = cache_from_obj(s, x);
  351.     if (!s)
  352. @@ -3799,7 +3799,7 @@ size_t ksize(const void *object)
  353.  }
  354.  EXPORT_SYMBOL(ksize);
  355.  
  356. -void kfree(const void *x)
  357. +void (kfree)(const void *x)
  358.  {
  359.     struct page *page;
  360.     void *object = (void *)x;
  361. --
  362. 2.22.0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement