--- title: Slow memhog for testing cgroups date: !!timestamp '2016-10-04 00:00:00' tags: - teaching --- Testing the cgroup memory is not something as easy as we can think. It can't be only question of `malloc(100000)` in a loop, as the Linux kernel overcommit memory allocation: so even if we get effectively a 100000 bytes long memory space, this doesn't decrease the physical available memory. To do so, this space need to be changed pages by pages, that can be tedious to do. And quite uncertain, because the kernel can take advantage of the swap partition... To facilitate memory testing, there is `memhog`, part of `numactl` tools. It aims to allocate large memory block for testing, directly in the physical memory. If we ask memhog to allocate 100M, 1G, 5G, 10G, ... it'll actually ask the kernel for such amont of memory, in no time. If there is enough memory available, we got our 100M, 1G, 5G, ... and the available memory is really decreased by such volume. In my demos, I need a slightly different behaviour, to demonstrate what happens as a function of time. I slightly modify `memhog` to introduce a timer between slice allocation. ```c /* Derivative work of memhog.c from the numactl repository, hosted at https://github.com/numactl/numactl.git Copyright (C) 2016 Pierre-Olivier Mercier, EPITA. Copyright (C) 2003,2004 Andi Kleen, SuSE Labs. numactl is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2. numactl is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should find a copy of v2 of the GNU General Public License somewhere on your Linux system; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include char * alloc_workbuf(size_t size) { char *ptr; /* allocate some memory */ ptr = malloc(size); /* return NULL on failure */ if (ptr == NULL) { fprintf(stderr, "Unable to malloc %zuk: %s\n", size / 1024, strerror(errno)); return NULL; } /* lock this buffer into RAM */ if (mlock(ptr, size)) { free(ptr); if (errno == ENOMEM) fprintf(stderr, "Unable to lock memory: not enough permissions\n"); else perror("Unable to lock memory"); return NULL; } return ptr; } int main(int argc, char *argv[]) { size_t size; size_t steps = 32; /* parse arguments */ if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: memhog [nb steps]\n"); return EXIT_FAILURE; } size = atoi(argv[1]); if (argc > 2) steps = atoi(argv[2]); size = size / steps; /* Do stuff */ for (size_t i = 0; i < steps; i++) { if (!alloc_workbuf(size * 1000000UL)) break; printf("."); fflush(stdout); usleep(80000); } printf("\n"); return EXIT_SUCCESS; } ``` You can compile those C lines with just `make`, stating your file is named `memhog.c`: ```shell make memhog ```