// SPDX-License-Identifier: GPL-2.0-or-later
/*
* thp_swap_allocator_test
*
* The purpose of this test program is helping check if THP swpout
* can correctly get swap slots to swap out as a whole instead of
* being split . It randomly releases swap entries through madvise
* DONTNEED and swapin / out on two memory areas : a memory area for
* 64 KB THP and the other area for small folios . The second memory
* can be enabled by " - s " .
* Before running the program , we need to setup a zRAM or similar
* swap device by :
* echo lzo > / sys / block / zram0 / comp_algorithm
* echo 64 M > / sys / block / zram0 / disksize
* echo never > / sys / kernel / mm / transparent_hugepage / hugepages - 2048 kB / enabled
* echo always > / sys / kernel / mm / transparent_hugepage / hugepages - 64 kB / enabled
* mkswap / dev / zram0
* swapon / dev / zram0
* The expected result should be 0 % anon swpout fallback ratio w / or
* w / o " - s " .
*
* Author ( s ) : Barry Song < v - songbaohua @ oppo . com >
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <linux/mman.h>
#include <sys/mman.h>
#include <errno.h>
#include <time.h>
#define MEMSIZE_MTHP (60 * 1024 * 1024 )
#define MEMSIZE_SMALLFOLIO (4 * 1024 * 1024 )
#define ALIGNMENT_MTHP (64 * 1024 )
#define ALIGNMENT_SMALLFOLIO (4 * 1024 )
#define TOTAL_DONTNEED_MTHP (16 * 1024 * 1024 )
#define TOTAL_DONTNEED_SMALLFOLIO (1 * 1024 * 1024 )
#define MTHP_FOLIO_SIZE (64 * 1024 )
#define SWPOUT_PATH \
"/sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/swpout"
#define SWPOUT_FALLBACK_PATH \
"/sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/swpout_fallback"
static void *aligned_alloc_mem(size_t size, size_t alignment)
{
void *mem = NULL;
if (posix_memalign(&mem, alignment, size) != 0 ) {
perror("posix_memalign" );
return NULL;
}
return mem;
}
/*
* This emulates the behavior of native libc and Java heap ,
* as well as process exit and munmap . It helps generate mTHP
* and ensures that iterations can proceed with mTHP , as we
* currently don ' t support large folios swap - in .
*/
static void random_madvise_dontneed(void *mem, size_t mem_size,
size_t align_size, size_t total_dontneed_size)
{
size_t num_pages = total_dontneed_size / align_size;
size_t i;
size_t offset;
void *addr;
for (i = 0 ; i < num_pages; ++i) {
offset = (rand() % (mem_size / align_size)) * align_size;
addr = (char *)mem + offset;
if (madvise(addr, align_size, MADV_DONTNEED) != 0 )
perror("madvise dontneed" );
memset(addr, 0 x11, align_size);
}
}
static void random_swapin(void *mem, size_t mem_size,
size_t align_size, size_t total_swapin_size)
{
size_t num_pages = total_swapin_size / align_size;
size_t i;
size_t offset;
void *addr;
for (i = 0 ; i < num_pages; ++i) {
offset = (rand() % (mem_size / align_size)) * align_size;
addr = (char *)mem + offset;
memset(addr, 0 x11, align_size);
}
}
static unsigned long read_stat(const char *path)
{
FILE *file;
unsigned long value;
file = fopen(path, "r" );
if (!file) {
perror("fopen" );
return 0 ;
}
if (fscanf(file, "%lu" , &value) != 1 ) {
perror("fscanf" );
fclose(file);
return 0 ;
}
fclose(file);
return value;
}
int main(int argc, char *argv[])
{
int use_small_folio = 0 , aligned_swapin = 0 ;
void *mem1 = NULL, *mem2 = NULL;
int i;
for (i = 1 ; i < argc; ++i) {
if (strcmp(argv[i], "-s" ) == 0 )
use_small_folio = 1 ;
else if (strcmp(argv[i], "-a" ) == 0 )
aligned_swapin = 1 ;
}
mem1 = aligned_alloc_mem(MEMSIZE_MTHP, ALIGNMENT_MTHP);
if (mem1 == NULL) {
fprintf(stderr, "Failed to allocate large folios memory\n" );
return EXIT_FAILURE;
}
if (madvise(mem1, MEMSIZE_MTHP, MADV_HUGEPAGE) != 0 ) {
perror("madvise hugepage for mem1" );
free(mem1);
return EXIT_FAILURE;
}
if (use_small_folio) {
mem2 = aligned_alloc_mem(MEMSIZE_SMALLFOLIO, ALIGNMENT_MTHP);
if (mem2 == NULL) {
fprintf(stderr, "Failed to allocate small folios memory\n" );
free(mem1);
return EXIT_FAILURE;
}
if (madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_NOHUGEPAGE) != 0 ) {
perror("madvise nohugepage for mem2" );
free(mem1);
free(mem2);
return EXIT_FAILURE;
}
}
/* warm-up phase to occupy the swapfile */
memset(mem1, 0 x11, MEMSIZE_MTHP);
madvise(mem1, MEMSIZE_MTHP, MADV_PAGEOUT);
if (use_small_folio) {
memset(mem2, 0 x11, MEMSIZE_SMALLFOLIO);
madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_PAGEOUT);
}
/* iterations with newly created mTHP, swap-in, and swap-out */
for (i = 0 ; i < 100 ; ++i) {
unsigned long initial_swpout;
unsigned long initial_swpout_fallback;
unsigned long final_swpout;
unsigned long final_swpout_fallback;
unsigned long swpout_inc;
unsigned long swpout_fallback_inc;
double fallback_percentage;
initial_swpout = read_stat(SWPOUT_PATH);
initial_swpout_fallback = read_stat(SWPOUT_FALLBACK_PATH);
/*
* The following setup creates a 1 : 1 ratio of mTHP to small folios
* since large folio swap - in isn ' t supported yet . Once we support
* mTHP swap - in , we ' ll likely need to reduce MEMSIZE_MTHP and
* increase MEMSIZE_SMALLFOLIO to maintain the ratio .
*/
random_swapin(mem1, MEMSIZE_MTHP,
aligned_swapin ? ALIGNMENT_MTHP : ALIGNMENT_SMALLFOLIO,
TOTAL_DONTNEED_MTHP);
random_madvise_dontneed(mem1, MEMSIZE_MTHP, ALIGNMENT_MTHP,
TOTAL_DONTNEED_MTHP);
if (use_small_folio) {
random_swapin(mem2, MEMSIZE_SMALLFOLIO,
ALIGNMENT_SMALLFOLIO,
TOTAL_DONTNEED_SMALLFOLIO);
}
if (madvise(mem1, MEMSIZE_MTHP, MADV_PAGEOUT) != 0 ) {
perror("madvise pageout for mem1" );
free(mem1);
if (mem2 != NULL)
free(mem2);
return EXIT_FAILURE;
}
if (use_small_folio) {
if (madvise(mem2, MEMSIZE_SMALLFOLIO, MADV_PAGEOUT) != 0 ) {
perror("madvise pageout for mem2" );
free(mem1);
free(mem2);
return EXIT_FAILURE;
}
}
final_swpout = read_stat(SWPOUT_PATH);
final_swpout_fallback = read_stat(SWPOUT_FALLBACK_PATH);
swpout_inc = final_swpout - initial_swpout;
swpout_fallback_inc = final_swpout_fallback - initial_swpout_fallback;
fallback_percentage = (double )swpout_fallback_inc /
(swpout_fallback_inc + swpout_inc) * 100 ;
printf("Iteration %d: swpout inc: %lu, swpout fallback inc: %lu, Fallback percentage: %.2f%%\n" ,
i + 1 , swpout_inc, swpout_fallback_inc, fallback_percentage);
}
free(mem1);
if (mem2 != NULL)
free(mem2);
return EXIT_SUCCESS;
}
Messung V0.5 in Prozent C=85 H=90 G=87
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland