kselftests: cgroup: add perpcu memory accounting test
authorRoman Gushchin <guro@fb.com>
Wed, 12 Aug 2020 01:30:29 +0000 (18:30 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Aug 2020 17:57:55 +0000 (10:57 -0700)
Add a simple test to check the percpu memory accounting.  The test creates
a cgroup tree with 1000 child cgroups and checks values of memory.current
and memory.stat::percpu.

Signed-off-by: Roman Gushchin <guro@fb.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Tobin C. Harding <tobin@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Waiman Long <longman@redhat.com>
Cc: Michal Koutný <mkoutny@suse.com>
Cc: Bixuan Cui <cuibixuan@huawei.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Link: http://lkml.kernel.org/r/20200608230819.832349-6-guro@fb.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
tools/testing/selftests/cgroup/test_kmem.c

index 5224dae..0941aa1 100644 (file)
 #include "cgroup_util.h"
 
 
+/*
+ * Memory cgroup charging and vmstat data aggregation is performed using
+ * percpu batches 32 pages big (look at MEMCG_CHARGE_BATCH). So the maximum
+ * discrepancy between charge and vmstat entries is number of cpus multiplied
+ * by 32 pages multiplied by 2.
+ */
+#define MAX_VMSTAT_ERROR (4096 * 32 * 2 * get_nprocs())
+
+
 static int alloc_dcache(const char *cgroup, void *arg)
 {
        unsigned long i;
@@ -180,7 +189,7 @@ static int test_kmem_memcg_deletion(const char *root)
                goto cleanup;
 
        sum = slab + anon + file + kernel_stack;
-       if (abs(sum - current) < 4096 * 32 * 2 * get_nprocs()) {
+       if (abs(sum - current) < MAX_VMSTAT_ERROR) {
                ret = KSFT_PASS;
        } else {
                printf("memory.current = %ld\n", current);
@@ -331,6 +340,64 @@ cleanup:
        return ret;
 }
 
+/*
+ * This test creates a sub-tree with 1000 memory cgroups.
+ * Then it checks that the memory.current on the parent level
+ * is greater than 0 and approximates matches the percpu value
+ * from memory.stat.
+ */
+static int test_percpu_basic(const char *root)
+{
+       int ret = KSFT_FAIL;
+       char *parent, *child;
+       long current, percpu;
+       int i;
+
+       parent = cg_name(root, "percpu_basic_test");
+       if (!parent)
+               goto cleanup;
+
+       if (cg_create(parent))
+               goto cleanup;
+
+       if (cg_write(parent, "cgroup.subtree_control", "+memory"))
+               goto cleanup;
+
+       for (i = 0; i < 1000; i++) {
+               child = cg_name_indexed(parent, "child", i);
+               if (!child)
+                       return -1;
+
+               if (cg_create(child))
+                       goto cleanup_children;
+
+               free(child);
+       }
+
+       current = cg_read_long(parent, "memory.current");
+       percpu = cg_read_key_long(parent, "memory.stat", "percpu ");
+
+       if (current > 0 && percpu > 0 && abs(current - percpu) <
+           MAX_VMSTAT_ERROR)
+               ret = KSFT_PASS;
+       else
+               printf("memory.current %ld\npercpu %ld\n",
+                      current, percpu);
+
+cleanup_children:
+       for (i = 0; i < 1000; i++) {
+               child = cg_name_indexed(parent, "child", i);
+               cg_destroy(child);
+               free(child);
+       }
+
+cleanup:
+       cg_destroy(parent);
+       free(parent);
+
+       return ret;
+}
+
 #define T(x) { x, #x }
 struct kmem_test {
        int (*fn)(const char *root);
@@ -341,6 +408,7 @@ struct kmem_test {
        T(test_kmem_proc_kpagecgroup),
        T(test_kmem_kernel_stacks),
        T(test_kmem_dead_cgroups),
+       T(test_percpu_basic),
 };
 #undef T