brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · 83afc52 Raw
235 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * thp_swap_allocator_test4 *5 * The purpose of this test program is helping check if THP swpout6 * can correctly get swap slots to swap out as a whole instead of7 * being split. It randomly releases swap entries through madvise8 * DONTNEED and swapin/out on two memory areas: a memory area for9 * 64KB THP and the other area for small folios. The second memory10 * can be enabled by "-s".11 * Before running the program, we need to setup a zRAM or similar12 * swap device by:13 *  echo lzo > /sys/block/zram0/comp_algorithm14 *  echo 64M > /sys/block/zram0/disksize15 *  echo never > /sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled16 *  echo always > /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled17 *  mkswap /dev/zram018 *  swapon /dev/zram019 * The expected result should be 0% anon swpout fallback ratio w/ or20 * w/o "-s".21 *22 * Author(s): Barry Song <v-songbaohua@oppo.com>23 */24 25#define _GNU_SOURCE26#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 48static 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 mTHP62 * and ensures that iterations can proceed with mTHP, as we63 * currently don't support large folios swap-in.64 */65static 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 83static 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 98static 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 119int 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 folios183		 * since large folio swap-in isn't supported yet. Once we support184		 * mTHP swap-in, we'll likely need to reduce MEMSIZE_MTHP and185		 * 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