1 /*
2  * Copyright (c) 2024 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/linker/sections.h>
9 
10 #include <mmu.h> /* for k_mem_num_pagefaults_get() */
11 
12 /*
13  * We want to artificially create a huge body of code hence the volatile
14  * to prevent the compiler from optimizing everything down.
15  */
16 volatile long foo_val1;
17 volatile long foo_val2;
18 
19 /*
20  * This function is tagged with __ondemand_func to be placed in a special
21  * "ondemand" segment by the linker. This means it is not loaded into memory
22  * at boot time but rather page-by-page on demand when actually executed.
23  * It is also subject to being evicted when memory reclamation occurs.
24  */
huge_evictable_function(void)25 static void __ondemand_func huge_evictable_function(void)
26 {
27 	foo_val1 = 13131313;
28 	foo_val2 = 45454545;
29 
30 #define CODE \
31 	foo_val1 *= foo_val2; \
32 	foo_val2 += 1234567; \
33 	foo_val1 -= 9876543210; \
34 	__asm__ __volatile__ (".rep 1000; nop; .endr");
35 
36 #define REPEAT_10(x) x x x x x x x x x x
37 #define REPEAT_1000(x) REPEAT_10(REPEAT_10(REPEAT_10(x)))
38 
39 	REPEAT_1000(CODE)
40 
41 #undef REPEAT_1000
42 #undef REPEAT_10
43 #undef CODE
44 }
45 
main(void)46 int main(void)
47 {
48 	size_t free_pages_before, free_pages_after;
49 	unsigned long faults_before, faults_after;
50 
51 	printk("Calling huge body of code that doesn't fit in memory\n");
52 	free_pages_before = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE;
53 	faults_before = k_mem_num_pagefaults_get();
54 
55 	huge_evictable_function();
56 
57 	free_pages_after = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE;
58 	faults_after = k_mem_num_pagefaults_get();
59 	printk("free memory pages: from %zd to %zd, %ld page faults\n",
60 	       free_pages_before, free_pages_after, faults_after - faults_before);
61 
62 	printk("Calling it a second time\n");
63 	free_pages_before = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE;
64 	faults_before = k_mem_num_pagefaults_get();
65 
66 	huge_evictable_function();
67 
68 	free_pages_after = k_mem_free_get() / CONFIG_MMU_PAGE_SIZE;
69 	faults_after = k_mem_num_pagefaults_get();
70 	printk("free memory pages: from %zd to %zd, %ld page faults\n",
71 	       free_pages_before, free_pages_after, faults_after - faults_before);
72 
73 	printk("Done.\n");
74 	return 0;
75 }
76