~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/mm/thp_swap_allocator_test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * thp_swap_allocator_test
  4  *
  5  * The purpose of this test program is helping check if THP swpout
  6  * can correctly get swap slots to swap out as a whole instead of
  7  * being split. It randomly releases swap entries through madvise
  8  * DONTNEED and swapin/out on two memory areas: a memory area for
  9  * 64KB THP and the other area for small folios. The second memory
 10  * can be enabled by "-s".
 11  * Before running the program, we need to setup a zRAM or similar
 12  * swap device by:
 13  *  echo lzo > /sys/block/zram0/comp_algorithm
 14  *  echo 64M > /sys/block/zram0/disksize
 15  *  echo never > /sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
 16  *  echo always > /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled
 17  *  mkswap /dev/zram0
 18  *  swapon /dev/zram0
 19  * The expected result should be 0% anon swpout fallback ratio w/ or
 20  * w/o "-s".
 21  *
 22  * Author(s): Barry Song <v-songbaohua@oppo.com>
 23  */
 24 
 25 #define _GNU_SOURCE
 26 #include <stdio.h>
 27 #include <stdlib.h>
 28 #include <unistd.h>
 29 #include <string.h>
 30 #include <linux/mman.h>
 31 #include <sys/mman.h>
 32 #include <errno.h>
 33 #include <time.h>
 34 
 35 #define MEMSIZE_MTHP (60 * 1024 * 1024)
 36 #define MEMSIZE_SMALLFOLIO (4 * 1024 * 1024)
 37 #define ALIGNMENT_MTHP (64 * 1024)
 38 #define ALIGNMENT_SMALLFOLIO (4 * 1024)
 39 #define TOTAL_DONTNEED_MTHP (16 * 1024 * 1024)
 40 #define TOTAL_DONTNEED_SMALLFOLIO (1 * 1024 * 1024)
 41 #define MTHP_FOLIO_SIZE (64 * 1024)
 42 
 43 #define SWPOUT_PATH \
 44         "/sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/swpout"
 45 #define SWPOUT_FALLBACK_PATH \
 46         "/sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/swpout_fallback"
 47 
 48 static void *aligned_alloc_mem(size_t size, size_t alignment)
 49 {
 50         void *mem = NULL;
 51 
 52         if (posix_memalign(&mem, alignment, size) != 0) {
 53                 perror("posix_memalign");
 54                 return NULL;
 55         }
 56         return mem;
 57 }
 58 
 59 /*
 60  * This emulates the behavior of native libc and Java heap,
 61  * as well as process exit and munmap. It helps generate mTHP
 62  * and ensures that iterations can proceed with mTHP, as we
 63  * currently don't support large folios swap-in.
 64  */
 65 static void random_madvise_dontneed(void *mem, size_t mem_size,
 66                 size_t align_size, size_t total_dontneed_size)
 67 {
 68         size_t num_pages = total_dontneed_size / align_size;
 69         size_t i;
 70         size_t offset;
 71         void *addr;
 72 
 73         for (i = 0; i < num_pages; ++i) {
 74                 offset = (rand() % (mem_size / align_size)) * align_size;
 75                 addr = (char *)mem + offset;
 76                 if (madvise(addr, align_size, MADV_DONTNEED) != 0)
 77                         perror("madvise dontneed");
 78 
 79                 memset(addr, 0x11, align_size);
 80         }
 81 }
 82 
 83 static void random_swapin(void *mem, size_t mem_size,
 84                 size_t align_size, size_t total_swapin_size)
 85 {
 86         size_t num_pages = total_swapin_size / align_size;
 87         size_t i;
 88         size_t offset;
 89         void *addr;
 90 
 91         for (i = 0; i < num_pages; ++i) {
 92                 offset = (rand() % (mem_size / align_size)) * align_size;
 93                 addr = (char *)mem + offset;
 94                 memset(addr, 0x11, align_size);
 95         }
 96 }
 97 
 98 static unsigned long read_stat(const char *path)
 99 {
100         FILE *file;
101         unsigned long value;
102 
103         file = fopen(path, "r");
104         if (!file) {
105                 perror("fopen");
106                 return 0;
107         }
108 
109         if (fscanf(file, "%lu", &value) != 1) {
110                 perror("fscanf");
111                 fclose(file);
112                 return 0;
113         }
114 
115         fclose(file);
116         return value;
117 }
118 
119 int main(int argc, char *argv[])
120 {
121         int use_small_folio = 0, aligned_swapin = 0;
122         void *mem1 = NULL, *mem2 = NULL;
123         int i;
124 
125         for (i = 1; i < argc; ++i) {
126                 if (strcmp(argv[i], "-s") == 0)
127                         use_small_folio = 1;
128                 else if (strcmp(argv[i], "-a") == 0)
129                         aligned_swapin = 1;
130         }
131 
132         mem1 = aligned_alloc_mem(MEMSIZE_MTHP, ALIGNMENT_MTHP);
133         if (mem1 == NULL) {
134                 fprintf(stderr, "Failed to allocate large folios memory\n");
135                 return EXIT_FAILURE;
136         }
137 
138         if (madvise(mem1, MEMSIZE_MTHP, MADV_HUGEPAGE) != 0) {
139                 perror("madvise hugepage for mem1");
140                 free(mem1);
141                 return EXIT_FAILURE;
142         }
143 
144         if (use_small_folio) {
145                 mem2 = aligned_alloc_mem(MEMSIZE_SMALLFOLIO, ALIGNMENT_MTHP);
146                 if (mem2 == NULL) {
147                         fprintf(stderr, "Failed to allocate small folios memory\n");
148                         free(mem1);
149                         return EXIT_FAILURE;
150                 }
151 
152                 if (madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_NOHUGEPAGE) != 0) {
153                         perror("madvise nohugepage for mem2");
154                         free(mem1);
155                         free(mem2);
156                         return EXIT_FAILURE;
157                 }
158         }
159 
160         /* warm-up phase to occupy the swapfile */
161         memset(mem1, 0x11, MEMSIZE_MTHP);
162         madvise(mem1, MEMSIZE_MTHP, MADV_PAGEOUT);
163         if (use_small_folio) {
164                 memset(mem2, 0x11, MEMSIZE_SMALLFOLIO);
165                 madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_PAGEOUT);
166         }
167 
168         /* iterations with newly created mTHP, swap-in, and swap-out */
169         for (i = 0; i < 100; ++i) {
170                 unsigned long initial_swpout;
171                 unsigned long initial_swpout_fallback;
172                 unsigned long final_swpout;
173                 unsigned long final_swpout_fallback;
174                 unsigned long swpout_inc;
175                 unsigned long swpout_fallback_inc;
176                 double fallback_percentage;
177 
178                 initial_swpout = read_stat(SWPOUT_PATH);
179                 initial_swpout_fallback = read_stat(SWPOUT_FALLBACK_PATH);
180 
181                 /*
182                  * The following setup creates a 1:1 ratio of mTHP to small folios
183                  * since large folio swap-in isn't supported yet. Once we support
184                  * mTHP swap-in, we'll likely need to reduce MEMSIZE_MTHP and
185                  * increase MEMSIZE_SMALLFOLIO to maintain the ratio.
186                  */
187                 random_swapin(mem1, MEMSIZE_MTHP,
188                                 aligned_swapin ? ALIGNMENT_MTHP : ALIGNMENT_SMALLFOLIO,
189                                 TOTAL_DONTNEED_MTHP);
190                 random_madvise_dontneed(mem1, MEMSIZE_MTHP, ALIGNMENT_MTHP,
191                                 TOTAL_DONTNEED_MTHP);
192 
193                 if (use_small_folio) {
194                         random_swapin(mem2, MEMSIZE_SMALLFOLIO,
195                                         ALIGNMENT_SMALLFOLIO,
196                                         TOTAL_DONTNEED_SMALLFOLIO);
197                 }
198 
199                 if (madvise(mem1, MEMSIZE_MTHP, MADV_PAGEOUT) != 0) {
200                         perror("madvise pageout for mem1");
201                         free(mem1);
202                         if (mem2 != NULL)
203                                 free(mem2);
204                         return EXIT_FAILURE;
205                 }
206 
207                 if (use_small_folio) {
208                         if (madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_PAGEOUT) != 0) {
209                                 perror("madvise pageout for mem2");
210                                 free(mem1);
211                                 free(mem2);
212                                 return EXIT_FAILURE;
213                         }
214                 }
215 
216                 final_swpout = read_stat(SWPOUT_PATH);
217                 final_swpout_fallback = read_stat(SWPOUT_FALLBACK_PATH);
218 
219                 swpout_inc = final_swpout - initial_swpout;
220                 swpout_fallback_inc = final_swpout_fallback - initial_swpout_fallback;
221 
222                 fallback_percentage = (double)swpout_fallback_inc /
223                         (swpout_fallback_inc + swpout_inc) * 100;
224 
225                 printf("Iteration %d: swpout inc: %lu, swpout fallback inc: %lu, Fallback percentage: %.2f%%\n",
226                                 i + 1, swpout_inc, swpout_fallback_inc, fallback_percentage);
227         }
228 
229         free(mem1);
230         if (mem2 != NULL)
231                 free(mem2);
232 
233         return EXIT_SUCCESS;
234 }
235 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php