mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
kselftests: cgroup: add perpcu memory accounting test
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>
This commit is contained in:
parent
3e38e0aaca
commit
90631e1dea
|
|
@ -18,6 +18,15 @@
|
||||||
#include "cgroup_util.h"
|
#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)
|
static int alloc_dcache(const char *cgroup, void *arg)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
@ -180,7 +189,7 @@ static int test_kmem_memcg_deletion(const char *root)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
sum = slab + anon + file + kernel_stack;
|
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;
|
ret = KSFT_PASS;
|
||||||
} else {
|
} else {
|
||||||
printf("memory.current = %ld\n", current);
|
printf("memory.current = %ld\n", current);
|
||||||
|
|
@ -331,6 +340,64 @@ static int test_kmem_dead_cgroups(const char *root)
|
||||||
return ret;
|
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 }
|
#define T(x) { x, #x }
|
||||||
struct kmem_test {
|
struct kmem_test {
|
||||||
int (*fn)(const char *root);
|
int (*fn)(const char *root);
|
||||||
|
|
@ -341,6 +408,7 @@ struct kmem_test {
|
||||||
T(test_kmem_proc_kpagecgroup),
|
T(test_kmem_proc_kpagecgroup),
|
||||||
T(test_kmem_kernel_stacks),
|
T(test_kmem_kernel_stacks),
|
||||||
T(test_kmem_dead_cgroups),
|
T(test_kmem_dead_cgroups),
|
||||||
|
T(test_percpu_basic),
|
||||||
};
|
};
|
||||||
#undef T
|
#undef T
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user