mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 07:18:51 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
16
tools/testing/selftests/vm/Makefile
Normal file
16
tools/testing/selftests/vm/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Makefile for vm selftests
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CFLAGS = -Wall
|
||||
BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest
|
||||
BINARIES += transhuge-stress
|
||||
|
||||
all: $(BINARIES)
|
||||
%: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
run_tests: all
|
||||
@/bin/sh ./run_vmtests || (echo "vmtests: [FAIL]"; exit 1)
|
||||
|
||||
clean:
|
||||
$(RM) $(BINARIES)
|
||||
92
tools/testing/selftests/vm/hugepage-mmap.c
Normal file
92
tools/testing/selftests/vm/hugepage-mmap.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* hugepage-mmap:
|
||||
*
|
||||
* Example of using huge page memory in a user application using the mmap
|
||||
* system call. Before running this application, make sure that the
|
||||
* administrator has mounted the hugetlbfs filesystem (on some directory
|
||||
* like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
|
||||
* example, the app is requesting memory of size 256MB that is backed by
|
||||
* huge pages.
|
||||
*
|
||||
* For the ia64 architecture, the Linux kernel reserves Region number 4 for
|
||||
* huge pages. That means that if one requires a fixed address, a huge page
|
||||
* aligned address starting with 0x800000... will be required. If a fixed
|
||||
* address is not required, the kernel will select an address in the proper
|
||||
* range.
|
||||
* Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FILE_NAME "huge/hugepagefile"
|
||||
#define LENGTH (256UL*1024*1024)
|
||||
#define PROTECTION (PROT_READ | PROT_WRITE)
|
||||
|
||||
/* Only ia64 requires this */
|
||||
#ifdef __ia64__
|
||||
#define ADDR (void *)(0x8000000000000000UL)
|
||||
#define FLAGS (MAP_SHARED | MAP_FIXED)
|
||||
#else
|
||||
#define ADDR (void *)(0x0UL)
|
||||
#define FLAGS (MAP_SHARED)
|
||||
#endif
|
||||
|
||||
static void check_bytes(char *addr)
|
||||
{
|
||||
printf("First hex is %x\n", *((unsigned int *)addr));
|
||||
}
|
||||
|
||||
static void write_bytes(char *addr)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < LENGTH; i++)
|
||||
*(addr + i) = (char)i;
|
||||
}
|
||||
|
||||
static int read_bytes(char *addr)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
check_bytes(addr);
|
||||
for (i = 0; i < LENGTH; i++)
|
||||
if (*(addr + i) != (char)i) {
|
||||
printf("Mismatch at %lu\n", i);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void *addr;
|
||||
int fd, ret;
|
||||
|
||||
fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
|
||||
if (fd < 0) {
|
||||
perror("Open failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
unlink(FILE_NAME);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Returned address is %p\n", addr);
|
||||
check_bytes(addr);
|
||||
write_bytes(addr);
|
||||
ret = read_bytes(addr);
|
||||
|
||||
munmap(addr, LENGTH);
|
||||
close(fd);
|
||||
unlink(FILE_NAME);
|
||||
|
||||
return ret;
|
||||
}
|
||||
100
tools/testing/selftests/vm/hugepage-shm.c
Normal file
100
tools/testing/selftests/vm/hugepage-shm.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* hugepage-shm:
|
||||
*
|
||||
* Example of using huge page memory in a user application using Sys V shared
|
||||
* memory system calls. In this example the app is requesting 256MB of
|
||||
* memory that is backed by huge pages. The application uses the flag
|
||||
* SHM_HUGETLB in the shmget system call to inform the kernel that it is
|
||||
* requesting huge pages.
|
||||
*
|
||||
* For the ia64 architecture, the Linux kernel reserves Region number 4 for
|
||||
* huge pages. That means that if one requires a fixed address, a huge page
|
||||
* aligned address starting with 0x800000... will be required. If a fixed
|
||||
* address is not required, the kernel will select an address in the proper
|
||||
* range.
|
||||
* Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
|
||||
*
|
||||
* Note: The default shared memory limit is quite low on many kernels,
|
||||
* you may need to increase it via:
|
||||
*
|
||||
* echo 268435456 > /proc/sys/kernel/shmmax
|
||||
*
|
||||
* This will increase the maximum size per shared memory segment to 256MB.
|
||||
* The other limit that you will hit eventually is shmall which is the
|
||||
* total amount of shared memory in pages. To set it to 16GB on a system
|
||||
* with a 4kB pagesize do:
|
||||
*
|
||||
* echo 4194304 > /proc/sys/kernel/shmall
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef SHM_HUGETLB
|
||||
#define SHM_HUGETLB 04000
|
||||
#endif
|
||||
|
||||
#define LENGTH (256UL*1024*1024)
|
||||
|
||||
#define dprintf(x) printf(x)
|
||||
|
||||
/* Only ia64 requires this */
|
||||
#ifdef __ia64__
|
||||
#define ADDR (void *)(0x8000000000000000UL)
|
||||
#define SHMAT_FLAGS (SHM_RND)
|
||||
#else
|
||||
#define ADDR (void *)(0x0UL)
|
||||
#define SHMAT_FLAGS (0)
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int shmid;
|
||||
unsigned long i;
|
||||
char *shmaddr;
|
||||
|
||||
shmid = shmget(2, LENGTH, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
|
||||
if (shmid < 0) {
|
||||
perror("shmget");
|
||||
exit(1);
|
||||
}
|
||||
printf("shmid: 0x%x\n", shmid);
|
||||
|
||||
shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
|
||||
if (shmaddr == (char *)-1) {
|
||||
perror("Shared memory attach failure");
|
||||
shmctl(shmid, IPC_RMID, NULL);
|
||||
exit(2);
|
||||
}
|
||||
printf("shmaddr: %p\n", shmaddr);
|
||||
|
||||
dprintf("Starting the writes:\n");
|
||||
for (i = 0; i < LENGTH; i++) {
|
||||
shmaddr[i] = (char)(i);
|
||||
if (!(i % (1024 * 1024)))
|
||||
dprintf(".");
|
||||
}
|
||||
dprintf("\n");
|
||||
|
||||
dprintf("Starting the Check...");
|
||||
for (i = 0; i < LENGTH; i++)
|
||||
if (shmaddr[i] != (char)i) {
|
||||
printf("\nIndex %lu mismatched\n", i);
|
||||
exit(3);
|
||||
}
|
||||
dprintf("Done.\n");
|
||||
|
||||
if (shmdt((const void *)shmaddr) != 0) {
|
||||
perror("Detach failure");
|
||||
shmctl(shmid, IPC_RMID, NULL);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
shmctl(shmid, IPC_RMID, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
84
tools/testing/selftests/vm/hugetlbfstest.c
Normal file
84
tools/testing/selftests/vm/hugetlbfstest.c
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef unsigned long long u64;
|
||||
|
||||
static size_t length = 1 << 24;
|
||||
|
||||
static u64 read_rss(void)
|
||||
{
|
||||
char buf[4096], *s = buf;
|
||||
int i, fd;
|
||||
u64 rss;
|
||||
|
||||
fd = open("/proc/self/statm", O_RDONLY);
|
||||
assert(fd > 2);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
read(fd, buf, sizeof(buf) - 1);
|
||||
for (i = 0; i < 1; i++)
|
||||
s = strchr(s, ' ') + 1;
|
||||
rss = strtoull(s, NULL, 10);
|
||||
return rss << 12; /* assumes 4k pagesize */
|
||||
}
|
||||
|
||||
static void do_mmap(int fd, int extra_flags, int unmap)
|
||||
{
|
||||
int *p;
|
||||
int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags;
|
||||
u64 before, after;
|
||||
|
||||
before = read_rss();
|
||||
p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0);
|
||||
assert(p != MAP_FAILED ||
|
||||
!"mmap returned an unexpected error");
|
||||
after = read_rss();
|
||||
assert(llabs(after - before - length) < 0x40000 ||
|
||||
!"rss didn't grow as expected");
|
||||
if (!unmap)
|
||||
return;
|
||||
munmap(p, length);
|
||||
after = read_rss();
|
||||
assert(llabs(after - before) < 0x40000 ||
|
||||
!"rss didn't shrink as expected");
|
||||
}
|
||||
|
||||
static int open_file(const char *path)
|
||||
{
|
||||
int fd, err;
|
||||
|
||||
unlink(path);
|
||||
fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL
|
||||
| O_LARGEFILE | O_CLOEXEC, 0600);
|
||||
assert(fd > 2);
|
||||
unlink(path);
|
||||
err = ftruncate(fd, length);
|
||||
assert(!err);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int hugefd, fd;
|
||||
|
||||
fd = open_file("/dev/shm/hugetlbhog");
|
||||
hugefd = open_file("/hugepages/hugetlbhog");
|
||||
|
||||
system("echo 100 > /proc/sys/vm/nr_hugepages");
|
||||
do_mmap(-1, MAP_ANONYMOUS, 1);
|
||||
do_mmap(fd, 0, 1);
|
||||
do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 1);
|
||||
do_mmap(hugefd, 0, 1);
|
||||
do_mmap(hugefd, MAP_HUGETLB, 1);
|
||||
/* Leak the last one to test do_exit() */
|
||||
do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 0);
|
||||
printf("oll korrekt.\n");
|
||||
return 0;
|
||||
}
|
||||
79
tools/testing/selftests/vm/map_hugetlb.c
Normal file
79
tools/testing/selftests/vm/map_hugetlb.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Example of using hugepage memory in a user application using the mmap
|
||||
* system call with MAP_HUGETLB flag. Before running this program make
|
||||
* sure the administrator has allocated enough default sized huge pages
|
||||
* to cover the 256 MB allocation.
|
||||
*
|
||||
* For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
|
||||
* That means the addresses starting with 0x800000... will need to be
|
||||
* specified. Specifying a fixed address is not required on ppc64, i386
|
||||
* or x86_64.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define LENGTH (256UL*1024*1024)
|
||||
#define PROTECTION (PROT_READ | PROT_WRITE)
|
||||
|
||||
#ifndef MAP_HUGETLB
|
||||
#define MAP_HUGETLB 0x40000 /* arch specific */
|
||||
#endif
|
||||
|
||||
/* Only ia64 requires this */
|
||||
#ifdef __ia64__
|
||||
#define ADDR (void *)(0x8000000000000000UL)
|
||||
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
|
||||
#else
|
||||
#define ADDR (void *)(0x0UL)
|
||||
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
|
||||
#endif
|
||||
|
||||
static void check_bytes(char *addr)
|
||||
{
|
||||
printf("First hex is %x\n", *((unsigned int *)addr));
|
||||
}
|
||||
|
||||
static void write_bytes(char *addr)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < LENGTH; i++)
|
||||
*(addr + i) = (char)i;
|
||||
}
|
||||
|
||||
static int read_bytes(char *addr)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
check_bytes(addr);
|
||||
for (i = 0; i < LENGTH; i++)
|
||||
if (*(addr + i) != (char)i) {
|
||||
printf("Mismatch at %lu\n", i);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void *addr;
|
||||
int ret;
|
||||
|
||||
addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Returned address is %p\n", addr);
|
||||
check_bytes(addr);
|
||||
write_bytes(addr);
|
||||
ret = read_bytes(addr);
|
||||
|
||||
munmap(addr, LENGTH);
|
||||
|
||||
return ret;
|
||||
}
|
||||
93
tools/testing/selftests/vm/run_vmtests
Normal file
93
tools/testing/selftests/vm/run_vmtests
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#!/bin/bash
|
||||
#please run as root
|
||||
|
||||
#we need 256M, below is the size in kB
|
||||
needmem=262144
|
||||
mnt=./huge
|
||||
exitcode=0
|
||||
|
||||
#get pagesize and freepages from /proc/meminfo
|
||||
while read name size unit; do
|
||||
if [ "$name" = "HugePages_Free:" ]; then
|
||||
freepgs=$size
|
||||
fi
|
||||
if [ "$name" = "Hugepagesize:" ]; then
|
||||
pgsize=$size
|
||||
fi
|
||||
done < /proc/meminfo
|
||||
|
||||
#set proper nr_hugepages
|
||||
if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
|
||||
nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
|
||||
needpgs=`expr $needmem / $pgsize`
|
||||
if [ $freepgs -lt $needpgs ]; then
|
||||
lackpgs=$(( $needpgs - $freepgs ))
|
||||
echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Please run this test as root"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "no hugetlbfs support in kernel?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir $mnt
|
||||
mount -t hugetlbfs none $mnt
|
||||
|
||||
echo "--------------------"
|
||||
echo "running hugepage-mmap"
|
||||
echo "--------------------"
|
||||
./hugepage-mmap
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[FAIL]"
|
||||
exitcode=1
|
||||
else
|
||||
echo "[PASS]"
|
||||
fi
|
||||
|
||||
shmmax=`cat /proc/sys/kernel/shmmax`
|
||||
shmall=`cat /proc/sys/kernel/shmall`
|
||||
echo 268435456 > /proc/sys/kernel/shmmax
|
||||
echo 4194304 > /proc/sys/kernel/shmall
|
||||
echo "--------------------"
|
||||
echo "running hugepage-shm"
|
||||
echo "--------------------"
|
||||
./hugepage-shm
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[FAIL]"
|
||||
exitcode=1
|
||||
else
|
||||
echo "[PASS]"
|
||||
fi
|
||||
echo $shmmax > /proc/sys/kernel/shmmax
|
||||
echo $shmall > /proc/sys/kernel/shmall
|
||||
|
||||
echo "--------------------"
|
||||
echo "running map_hugetlb"
|
||||
echo "--------------------"
|
||||
./map_hugetlb
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[FAIL]"
|
||||
exitcode=1
|
||||
else
|
||||
echo "[PASS]"
|
||||
fi
|
||||
|
||||
echo "--------------------"
|
||||
echo "running hugetlbfstest"
|
||||
echo "--------------------"
|
||||
./hugetlbfstest
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[FAIL]"
|
||||
exitcode=1
|
||||
else
|
||||
echo "[PASS]"
|
||||
fi
|
||||
|
||||
#cleanup
|
||||
umount $mnt
|
||||
rm -rf $mnt
|
||||
echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
|
||||
exit $exitcode
|
||||
254
tools/testing/selftests/vm/thuge-gen.c
Normal file
254
tools/testing/selftests/vm/thuge-gen.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/* Test selecting other page sizes for mmap/shmget.
|
||||
|
||||
Before running this huge pages for each huge page size must have been
|
||||
reserved.
|
||||
For large pages beyond MAX_ORDER (like 1GB on x86) boot options must be used.
|
||||
Also shmmax must be increased.
|
||||
And you need to run as root to work around some weird permissions in shm.
|
||||
And nothing using huge pages should run in parallel.
|
||||
When the program aborts you may need to clean up the shm segments with
|
||||
ipcrm -m by hand, like this
|
||||
sudo ipcs | awk '$1 == "0x00000000" {print $2}' | xargs -n1 sudo ipcrm -m
|
||||
(warning this will remove all if someone else uses them) */
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <sys/mman.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <glob.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#define err(x) perror(x), exit(1)
|
||||
|
||||
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
|
||||
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
|
||||
#define MAP_HUGE_SHIFT 26
|
||||
#define MAP_HUGE_MASK 0x3f
|
||||
#define MAP_HUGETLB 0x40000
|
||||
|
||||
#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */
|
||||
#define SHM_HUGE_SHIFT 26
|
||||
#define SHM_HUGE_MASK 0x3f
|
||||
#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
|
||||
#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
|
||||
|
||||
#define NUM_PAGESIZES 5
|
||||
|
||||
#define NUM_PAGES 4
|
||||
|
||||
#define Dprintf(fmt...) // printf(fmt)
|
||||
|
||||
unsigned long page_sizes[NUM_PAGESIZES];
|
||||
int num_page_sizes;
|
||||
|
||||
int ilog2(unsigned long v)
|
||||
{
|
||||
int l = 0;
|
||||
while ((1UL << l) < v)
|
||||
l++;
|
||||
return l;
|
||||
}
|
||||
|
||||
void find_pagesizes(void)
|
||||
{
|
||||
glob_t g;
|
||||
int i;
|
||||
glob("/sys/kernel/mm/hugepages/hugepages-*kB", 0, NULL, &g);
|
||||
assert(g.gl_pathc <= NUM_PAGESIZES);
|
||||
for (i = 0; i < g.gl_pathc; i++) {
|
||||
sscanf(g.gl_pathv[i], "/sys/kernel/mm/hugepages/hugepages-%lukB",
|
||||
&page_sizes[i]);
|
||||
page_sizes[i] <<= 10;
|
||||
printf("Found %luMB\n", page_sizes[i] >> 20);
|
||||
}
|
||||
num_page_sizes = g.gl_pathc;
|
||||
globfree(&g);
|
||||
}
|
||||
|
||||
unsigned long default_huge_page_size(void)
|
||||
{
|
||||
unsigned long hps = 0;
|
||||
char *line = NULL;
|
||||
size_t linelen = 0;
|
||||
FILE *f = fopen("/proc/meminfo", "r");
|
||||
if (!f)
|
||||
return 0;
|
||||
while (getline(&line, &linelen, f) > 0) {
|
||||
if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
|
||||
hps <<= 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
return hps;
|
||||
}
|
||||
|
||||
void show(unsigned long ps)
|
||||
{
|
||||
char buf[100];
|
||||
if (ps == getpagesize())
|
||||
return;
|
||||
printf("%luMB: ", ps >> 20);
|
||||
fflush(stdout);
|
||||
snprintf(buf, sizeof buf,
|
||||
"cat /sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
|
||||
ps >> 10);
|
||||
system(buf);
|
||||
}
|
||||
|
||||
unsigned long read_sysfs(int warn, char *fmt, ...)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t linelen = 0;
|
||||
char buf[100];
|
||||
FILE *f;
|
||||
va_list ap;
|
||||
unsigned long val = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
f = fopen(buf, "r");
|
||||
if (!f) {
|
||||
if (warn)
|
||||
printf("missing %s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
if (getline(&line, &linelen, f) > 0) {
|
||||
sscanf(line, "%lu", &val);
|
||||
}
|
||||
fclose(f);
|
||||
free(line);
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned long read_free(unsigned long ps)
|
||||
{
|
||||
return read_sysfs(ps != getpagesize(),
|
||||
"/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
|
||||
ps >> 10);
|
||||
}
|
||||
|
||||
void test_mmap(unsigned long size, unsigned flags)
|
||||
{
|
||||
char *map;
|
||||
unsigned long before, after;
|
||||
int err;
|
||||
|
||||
before = read_free(size);
|
||||
map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, 0, 0);
|
||||
|
||||
if (map == (char *)-1) err("mmap");
|
||||
memset(map, 0xff, size*NUM_PAGES);
|
||||
after = read_free(size);
|
||||
Dprintf("before %lu after %lu diff %ld size %lu\n",
|
||||
before, after, before - after, size);
|
||||
assert(size == getpagesize() || (before - after) == NUM_PAGES);
|
||||
show(size);
|
||||
err = munmap(map, size);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void test_shmget(unsigned long size, unsigned flags)
|
||||
{
|
||||
int id;
|
||||
unsigned long before, after;
|
||||
int err;
|
||||
|
||||
before = read_free(size);
|
||||
id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags);
|
||||
if (id < 0) err("shmget");
|
||||
|
||||
struct shm_info i;
|
||||
if (shmctl(id, SHM_INFO, (void *)&i) < 0) err("shmctl");
|
||||
Dprintf("alloc %lu res %lu\n", i.shm_tot, i.shm_rss);
|
||||
|
||||
|
||||
Dprintf("id %d\n", id);
|
||||
char *map = shmat(id, NULL, 0600);
|
||||
if (map == (char*)-1) err("shmat");
|
||||
|
||||
shmctl(id, IPC_RMID, NULL);
|
||||
|
||||
memset(map, 0xff, size*NUM_PAGES);
|
||||
after = read_free(size);
|
||||
|
||||
Dprintf("before %lu after %lu diff %ld size %lu\n",
|
||||
before, after, before - after, size);
|
||||
assert(size == getpagesize() || (before - after) == NUM_PAGES);
|
||||
show(size);
|
||||
err = shmdt(map);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void sanity_checks(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long largest = getpagesize();
|
||||
|
||||
for (i = 0; i < num_page_sizes; i++) {
|
||||
if (page_sizes[i] > largest)
|
||||
largest = page_sizes[i];
|
||||
|
||||
if (read_free(page_sizes[i]) < NUM_PAGES) {
|
||||
printf("Not enough huge pages for page size %lu MB, need %u\n",
|
||||
page_sizes[i] >> 20,
|
||||
NUM_PAGES);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest) {
|
||||
printf("Please do echo %lu > /proc/sys/kernel/shmmax", largest * NUM_PAGES);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
if (largest != 1U<<30) {
|
||||
printf("No GB pages available on x86-64\n"
|
||||
"Please boot with hugepagesz=1G hugepages=%d\n", NUM_PAGES);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
unsigned default_hps = default_huge_page_size();
|
||||
|
||||
find_pagesizes();
|
||||
|
||||
sanity_checks();
|
||||
|
||||
for (i = 0; i < num_page_sizes; i++) {
|
||||
unsigned long ps = page_sizes[i];
|
||||
int arg = ilog2(ps) << MAP_HUGE_SHIFT;
|
||||
printf("Testing %luMB mmap with shift %x\n", ps >> 20, arg);
|
||||
test_mmap(ps, MAP_HUGETLB | arg);
|
||||
}
|
||||
printf("Testing default huge mmap\n");
|
||||
test_mmap(default_hps, SHM_HUGETLB);
|
||||
|
||||
puts("Testing non-huge shmget");
|
||||
test_shmget(getpagesize(), 0);
|
||||
|
||||
for (i = 0; i < num_page_sizes; i++) {
|
||||
unsigned long ps = page_sizes[i];
|
||||
int arg = ilog2(ps) << SHM_HUGE_SHIFT;
|
||||
printf("Testing %luMB shmget with shift %x\n", ps >> 20, arg);
|
||||
test_shmget(ps, SHM_HUGETLB | arg);
|
||||
}
|
||||
puts("default huge shmget");
|
||||
test_shmget(default_hps, SHM_HUGETLB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
144
tools/testing/selftests/vm/transhuge-stress.c
Normal file
144
tools/testing/selftests/vm/transhuge-stress.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Stress test for transparent huge pages, memory compaction and migration.
|
||||
*
|
||||
* Authors: Konstantin Khlebnikov <koct9i@gmail.com>
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <err.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define PAGE_SHIFT 12
|
||||
#define HPAGE_SHIFT 21
|
||||
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
#define HPAGE_SIZE (1 << HPAGE_SHIFT)
|
||||
|
||||
#define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0)
|
||||
#define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1))
|
||||
|
||||
int pagemap_fd;
|
||||
|
||||
int64_t allocate_transhuge(void *ptr)
|
||||
{
|
||||
uint64_t ent[2];
|
||||
|
||||
/* drop pmd */
|
||||
if (mmap(ptr, HPAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_ANONYMOUS |
|
||||
MAP_NORESERVE | MAP_PRIVATE, -1, 0) != ptr)
|
||||
errx(2, "mmap transhuge");
|
||||
|
||||
if (madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE))
|
||||
err(2, "MADV_HUGEPAGE");
|
||||
|
||||
/* allocate transparent huge page */
|
||||
*(volatile void **)ptr = ptr;
|
||||
|
||||
if (pread(pagemap_fd, ent, sizeof(ent),
|
||||
(uintptr_t)ptr >> (PAGE_SHIFT - 3)) != sizeof(ent))
|
||||
err(2, "read pagemap");
|
||||
|
||||
if (PAGEMAP_PRESENT(ent[0]) && PAGEMAP_PRESENT(ent[1]) &&
|
||||
PAGEMAP_PFN(ent[0]) + 1 == PAGEMAP_PFN(ent[1]) &&
|
||||
!(PAGEMAP_PFN(ent[0]) & ((1 << (HPAGE_SHIFT - PAGE_SHIFT)) - 1)))
|
||||
return PAGEMAP_PFN(ent[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t ram, len;
|
||||
void *ptr, *p;
|
||||
struct timespec a, b;
|
||||
double s;
|
||||
uint8_t *map;
|
||||
size_t map_len;
|
||||
|
||||
ram = sysconf(_SC_PHYS_PAGES);
|
||||
if (ram > SIZE_MAX / sysconf(_SC_PAGESIZE) / 4)
|
||||
ram = SIZE_MAX / 4;
|
||||
else
|
||||
ram *= sysconf(_SC_PAGESIZE);
|
||||
|
||||
if (argc == 1)
|
||||
len = ram;
|
||||
else if (!strcmp(argv[1], "-h"))
|
||||
errx(1, "usage: %s [size in MiB]", argv[0]);
|
||||
else
|
||||
len = atoll(argv[1]) << 20;
|
||||
|
||||
warnx("allocate %zd transhuge pages, using %zd MiB virtual memory"
|
||||
" and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20,
|
||||
len >> (20 + HPAGE_SHIFT - PAGE_SHIFT - 1));
|
||||
|
||||
pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
|
||||
if (pagemap_fd < 0)
|
||||
err(2, "open pagemap");
|
||||
|
||||
len -= len % HPAGE_SIZE;
|
||||
ptr = mmap(NULL, len + HPAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
err(2, "initial mmap");
|
||||
ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE;
|
||||
|
||||
if (madvise(ptr, len, MADV_HUGEPAGE))
|
||||
err(2, "MADV_HUGEPAGE");
|
||||
|
||||
map_len = ram >> (HPAGE_SHIFT - 1);
|
||||
map = malloc(map_len);
|
||||
if (!map)
|
||||
errx(2, "map malloc");
|
||||
|
||||
while (1) {
|
||||
int nr_succeed = 0, nr_failed = 0, nr_pages = 0;
|
||||
|
||||
memset(map, 0, map_len);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &a);
|
||||
for (p = ptr; p < ptr + len; p += HPAGE_SIZE) {
|
||||
int64_t pfn;
|
||||
|
||||
pfn = allocate_transhuge(p);
|
||||
|
||||
if (pfn < 0) {
|
||||
nr_failed++;
|
||||
} else {
|
||||
size_t idx = pfn >> (HPAGE_SHIFT - PAGE_SHIFT);
|
||||
|
||||
nr_succeed++;
|
||||
if (idx >= map_len) {
|
||||
map = realloc(map, idx + 1);
|
||||
if (!map)
|
||||
errx(2, "map realloc");
|
||||
memset(map + map_len, 0, idx + 1 - map_len);
|
||||
map_len = idx + 1;
|
||||
}
|
||||
if (!map[idx])
|
||||
nr_pages++;
|
||||
map[idx] = 1;
|
||||
}
|
||||
|
||||
/* split transhuge page, keep last page */
|
||||
if (madvise(p, HPAGE_SIZE - PAGE_SIZE, MADV_DONTNEED))
|
||||
err(2, "MADV_DONTNEED");
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &b);
|
||||
s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.;
|
||||
|
||||
warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t"
|
||||
"%4d succeed, %4d failed, %4d different pages",
|
||||
s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20),
|
||||
nr_succeed, nr_failed, nr_pages);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue