mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
Become a memory accounting amateur
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
/* Print hello to stdout ;-) */
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#c
|
||||
*
|
||||
* Print hello to stdout ;-) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -4,22 +4,26 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* We do this in a separate function just to illustrate that
|
||||
* this is allows for malloc memory! This is unlike regular stack
|
||||
* variables which may be deallocated when the function returns. */
|
||||
void *allocate_bytes(size_t nbytes) {
|
||||
return malloc(nbytes);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int *is;
|
||||
size_t nbytes, nints;
|
||||
|
||||
/* Decide how many ints to allocate. */
|
||||
/* Decide how many ints to allocate.
|
||||
* Unlike usual non-VLA arrays, the size is determined dynamically at runtime! */
|
||||
if (argc < 2) {
|
||||
nints = 2;
|
||||
} else {
|
||||
nints = strtoull(argv[1], NULL, 0);
|
||||
}
|
||||
nbytes = nints * sizeof(*is);
|
||||
|
||||
/* Allocate the ints.
|
||||
* Note that unlike traditional stack arrays (non-VLA)
|
||||
* this value does not have to be determined at compile time! */
|
||||
is = malloc(nbytes);
|
||||
is = allocate_bytes(nbytes);
|
||||
|
||||
/* This can happen for example if we ask for too much memory. */
|
||||
if (is == NULL) {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#malloc-maximum-size */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
char *ptr = NULL;
|
||||
size_t size = 1;
|
||||
while (1) {
|
||||
printf("0x%zx\n", size);
|
||||
ptr = realloc(ptr, size);
|
||||
if (ptr == NULL) {
|
||||
break;
|
||||
} else {
|
||||
size <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
userland/c/malloc_size.c
Normal file
26
userland/c/malloc_size.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#malloc
|
||||
*
|
||||
* Malloc n bytes as given from the command line.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *chars;
|
||||
size_t nbytes;
|
||||
|
||||
if (argc < 2) {
|
||||
nbytes = 2;
|
||||
} else {
|
||||
nbytes = strtoull(argv[1], NULL, 0);
|
||||
}
|
||||
chars = malloc(nbytes);
|
||||
if (chars == NULL) {
|
||||
perror("malloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
free(chars);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
54
userland/c/snprintf.c
Normal file
54
userland/c/snprintf.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#c
|
||||
*
|
||||
* Like `sprintf`, but writes at most n bytes, so it is safer,
|
||||
* because it may not be possible or easy to calculate the resulting
|
||||
* size of a formated string.
|
||||
*
|
||||
* The size given includes the null terminator. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void) {
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
/* Common usage when string fits.
|
||||
*
|
||||
* Ensures that there will be no out or bounds access on out. */
|
||||
{
|
||||
int in = 1234;
|
||||
char out[1024];
|
||||
int snprintf_return;
|
||||
snprintf_return = snprintf(out, sizeof(out), "ab%dcd", in);
|
||||
|
||||
/* The usual error checking. */
|
||||
if (snprintf_return < 0) {
|
||||
perror("snprintf");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
assert((size_t)snprintf_return < sizeof(out));
|
||||
|
||||
/* Assert because we know the return here. */
|
||||
assert(snprintf_return == 8);
|
||||
|
||||
/* What it actually copied. */
|
||||
assert(strcmp(out, "ab1234cd") == 0);
|
||||
}
|
||||
|
||||
/* Less common case where string does not fit. Error handling would
|
||||
* normally follow in a real program. */
|
||||
{
|
||||
int in = 1234;
|
||||
char out[6];
|
||||
/* The return here is the same as before.
|
||||
*
|
||||
* Because it is >= than the imposed limit of 6, we know that
|
||||
* the write failed to fully complete. */
|
||||
assert(snprintf(out, sizeof(out), "ab%dcd", in) == 8);
|
||||
assert(strcmp(out, "ab123") == 0);
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#mmap-map-anonymous */
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#mmap-map-anonymous
|
||||
*
|
||||
* Malloc n bytes as given from the command line.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -9,19 +11,18 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int *is;
|
||||
size_t nbytes, nints;
|
||||
char *chars;
|
||||
size_t nbytes;
|
||||
|
||||
/* Decide how many ints to allocate. */
|
||||
if (argc < 2) {
|
||||
nints = 2;
|
||||
nbytes = 2;
|
||||
} else {
|
||||
nints = strtoull(argv[1], NULL, 0);
|
||||
nbytes = strtoull(argv[1], NULL, 0);
|
||||
}
|
||||
nbytes = nints * sizeof(*is);
|
||||
|
||||
/* Allocate 2 ints. */
|
||||
is = mmap(
|
||||
/* Allocate the bytes. */
|
||||
chars = mmap(
|
||||
NULL,
|
||||
nbytes,
|
||||
PROT_READ | PROT_WRITE,
|
||||
@@ -31,19 +32,13 @@ int main(int argc, char **argv) {
|
||||
);
|
||||
|
||||
/* This can happen for example if we ask for too much memory. */
|
||||
if (is == NULL) {
|
||||
if (chars == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Write to and read from the allocated memory. */
|
||||
is[0] = 1;
|
||||
is[1] = 2;
|
||||
assert(is[0] == 1);
|
||||
assert(is[1] == 2);
|
||||
|
||||
/* Free the allocated memory. */
|
||||
munmap(is, nbytes);
|
||||
munmap(chars, nbytes);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
125
userland/linux/mmap_anonymous_touch.c
Normal file
125
userland/linux/mmap_anonymous_touch.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#malloc-maximum-size
|
||||
*
|
||||
* mmap memory, then write something to each page to ensure it is not just virtual.
|
||||
* We want to meet the OOM.
|
||||
*
|
||||
* ./prog [nbytes [print_interval]]
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned long size,resident,share,text,lib,data,dt;
|
||||
} ProcStatm;
|
||||
|
||||
/* https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c/7212248#7212248 */
|
||||
void ProcStat_init(ProcStatm *result) {
|
||||
const char* statm_path = "/proc/self/statm";
|
||||
FILE *f = fopen(statm_path, "r");
|
||||
if(!f) {
|
||||
perror(statm_path);
|
||||
abort();
|
||||
}
|
||||
if(7 != fscanf(
|
||||
f,
|
||||
"%ld %ld %ld %ld %ld %ld %ld",
|
||||
&(result->size),
|
||||
&(result->resident),
|
||||
&(result->share),
|
||||
&(result->text),
|
||||
&(result->lib),
|
||||
&(result->data),
|
||||
&(result->dt)
|
||||
)) {
|
||||
perror(statm_path);
|
||||
abort();
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
ProcStatm proc_statm;
|
||||
char *base, *p;
|
||||
char system_cmd[1024];
|
||||
long page_size;
|
||||
size_t i, nbytes, print_interval, bytes_since_last_print;
|
||||
int snprintf_return;
|
||||
|
||||
/* Decide how many ints to allocate. */
|
||||
if (argc < 2) {
|
||||
nbytes = 0x10000;
|
||||
} else {
|
||||
nbytes = strtoull(argv[1], NULL, 0);
|
||||
}
|
||||
if (argc < 3) {
|
||||
print_interval = 0x1000;
|
||||
} else {
|
||||
print_interval = strtoull(argv[2], NULL, 0);
|
||||
}
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
|
||||
/* Allocate the memory. */
|
||||
base = mmap(
|
||||
NULL,
|
||||
nbytes,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS,
|
||||
-1,
|
||||
0
|
||||
);
|
||||
if (base == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Write to all the allocated pages. */
|
||||
i = 0;
|
||||
p = base;
|
||||
bytes_since_last_print = 0;
|
||||
/* Produce the ps command that lists only our VSZ and RSS. */
|
||||
snprintf_return = snprintf(
|
||||
system_cmd,
|
||||
sizeof(system_cmd),
|
||||
"ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == \"%ju\") print}'",
|
||||
(uintmax_t)getpid()
|
||||
);
|
||||
assert(snprintf_return >= 0);
|
||||
assert((size_t)snprintf_return < sizeof(system_cmd));
|
||||
bytes_since_last_print = print_interval;
|
||||
do {
|
||||
/* Modify a byte in the page. */
|
||||
*p = i;
|
||||
p += page_size;
|
||||
bytes_since_last_print += page_size;
|
||||
/* Print process memory usage every print_interval bytes.
|
||||
* We count memory using a few techniques from:
|
||||
* https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c */
|
||||
if (bytes_since_last_print > print_interval) {
|
||||
bytes_since_last_print -= print_interval;
|
||||
printf("extra_memory_committed %lu KiB\n", (i * page_size) / 1024);
|
||||
ProcStat_init(&proc_statm);
|
||||
/* Check /proc/self/statm */
|
||||
printf(
|
||||
"/proc/self/statm size resident %lu %lu KiB\n",
|
||||
(proc_statm.size * page_size) / 1024,
|
||||
(proc_statm.resident * page_size) / 1024
|
||||
);
|
||||
/* Check ps. */
|
||||
puts(system_cmd);
|
||||
system(system_cmd);
|
||||
puts("");
|
||||
}
|
||||
i++;
|
||||
} while (p < base + nbytes);
|
||||
|
||||
/* Cleanup. */
|
||||
munmap(base, nbytes);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
30
userland/linux/total_memory.c
Normal file
30
userland/linux/total_memory.c
Normal file
@@ -0,0 +1,30 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#memory-size */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void) {
|
||||
/* PAGESIZE is POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/
|
||||
* but PHYS_PAGES and AVPHYS_PAGES are glibc extensions. I bet those are
|
||||
* parsed from /proc/meminfo. */
|
||||
printf(
|
||||
"sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lX\n",
|
||||
sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)
|
||||
);
|
||||
printf(
|
||||
"sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lX\n",
|
||||
sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE)
|
||||
);
|
||||
|
||||
/* glibc extensions. man says they are parsed from /proc/meminfo. */
|
||||
printf(
|
||||
"get_phys_pages() * sysconf(_SC_PAGESIZE) = 0x%lX\n",
|
||||
get_phys_pages() * sysconf(_SC_PAGESIZE)
|
||||
);
|
||||
printf(
|
||||
"get_avphys_pages() * sysconf(_SC_PAGESIZE) = 0x%lX\n",
|
||||
get_avphys_pages() * sysconf(_SC_PAGESIZE)
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user