0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <stdlib.h>
0016 #include <stdio.h>
0017 #include <unistd.h>
0018 #include <sys/mman.h>
0019 #define __USE_GNU
0020 #include <fcntl.h>
0021
0022 #define USAGE "USAGE: %s <hugepagefile_name>\n"
0023 #define MIN_FREE_PAGES 20
0024 #define NR_HUGE_PAGES 10
0025
0026 #define validate_free_pages(exp_free) \
0027 do { \
0028 int fhp = get_free_hugepages(); \
0029 if (fhp != (exp_free)) { \
0030 printf("Unexpected number of free huge " \
0031 "pages line %d\n", __LINE__); \
0032 exit(1); \
0033 } \
0034 } while (0)
0035
0036 unsigned long huge_page_size;
0037 unsigned long base_page_size;
0038
0039
0040
0041
0042 unsigned long default_huge_page_size(void)
0043 {
0044 unsigned long hps = 0;
0045 char *line = NULL;
0046 size_t linelen = 0;
0047 FILE *f = fopen("/proc/meminfo", "r");
0048
0049 if (!f)
0050 return 0;
0051 while (getline(&line, &linelen, f) > 0) {
0052 if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
0053 hps <<= 10;
0054 break;
0055 }
0056 }
0057
0058 free(line);
0059 fclose(f);
0060 return hps;
0061 }
0062
0063 unsigned long get_free_hugepages(void)
0064 {
0065 unsigned long fhp = 0;
0066 char *line = NULL;
0067 size_t linelen = 0;
0068 FILE *f = fopen("/proc/meminfo", "r");
0069
0070 if (!f)
0071 return fhp;
0072 while (getline(&line, &linelen, f) > 0) {
0073 if (sscanf(line, "HugePages_Free: %lu", &fhp) == 1)
0074 break;
0075 }
0076
0077 free(line);
0078 fclose(f);
0079 return fhp;
0080 }
0081
0082 void write_fault_pages(void *addr, unsigned long nr_pages)
0083 {
0084 unsigned long i;
0085
0086 for (i = 0; i < nr_pages; i++)
0087 *((unsigned long *)(addr + (i * huge_page_size))) = i;
0088 }
0089
0090 void read_fault_pages(void *addr, unsigned long nr_pages)
0091 {
0092 unsigned long dummy = 0;
0093 unsigned long i;
0094
0095 for (i = 0; i < nr_pages; i++)
0096 dummy += *((unsigned long *)(addr + (i * huge_page_size)));
0097 }
0098
0099 int main(int argc, char **argv)
0100 {
0101 unsigned long free_hugepages;
0102 void *addr, *addr2;
0103 int fd;
0104 int ret;
0105
0106 if (argc != 2) {
0107 printf(USAGE, argv[0]);
0108 exit(1);
0109 }
0110
0111 huge_page_size = default_huge_page_size();
0112 if (!huge_page_size) {
0113 printf("Unable to determine huge page size, exiting!\n");
0114 exit(1);
0115 }
0116 base_page_size = sysconf(_SC_PAGE_SIZE);
0117 if (!huge_page_size) {
0118 printf("Unable to determine base page size, exiting!\n");
0119 exit(1);
0120 }
0121
0122 free_hugepages = get_free_hugepages();
0123 if (free_hugepages < MIN_FREE_PAGES) {
0124 printf("Not enough free huge pages to test, exiting!\n");
0125 exit(1);
0126 }
0127
0128 fd = open(argv[1], O_CREAT | O_RDWR, 0755);
0129 if (fd < 0) {
0130 perror("Open failed");
0131 exit(1);
0132 }
0133
0134
0135
0136
0137
0138
0139
0140 addr = mmap(NULL, (NR_HUGE_PAGES + 2) * huge_page_size,
0141 PROT_READ | PROT_WRITE,
0142 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
0143 -1, 0);
0144 if (addr == MAP_FAILED) {
0145 perror("mmap");
0146 exit(1);
0147 }
0148 if (munmap(addr, huge_page_size) ||
0149 munmap(addr + (NR_HUGE_PAGES + 1) * huge_page_size,
0150 huge_page_size)) {
0151 perror("munmap");
0152 exit(1);
0153 }
0154 addr = addr + huge_page_size;
0155
0156 write_fault_pages(addr, NR_HUGE_PAGES);
0157 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0158
0159
0160 ret = madvise(addr - base_page_size, NR_HUGE_PAGES * huge_page_size,
0161 MADV_DONTNEED);
0162 if (!ret) {
0163 printf("Unexpected success of madvise call with invalid addr line %d\n",
0164 __LINE__);
0165 exit(1);
0166 }
0167
0168
0169 ret = madvise(addr, (NR_HUGE_PAGES * huge_page_size) + base_page_size,
0170 MADV_DONTNEED);
0171 if (!ret) {
0172 printf("Unexpected success of madvise call with invalid length line %d\n",
0173 __LINE__);
0174 exit(1);
0175 }
0176
0177 (void)munmap(addr, NR_HUGE_PAGES * huge_page_size);
0178
0179
0180
0181
0182 addr = mmap(NULL, NR_HUGE_PAGES * huge_page_size,
0183 PROT_READ | PROT_WRITE,
0184 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
0185 -1, 0);
0186 if (addr == MAP_FAILED) {
0187 perror("mmap");
0188 exit(1);
0189 }
0190 write_fault_pages(addr, NR_HUGE_PAGES);
0191 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0192
0193
0194 ret = madvise(addr + base_page_size,
0195 NR_HUGE_PAGES * huge_page_size - base_page_size,
0196 MADV_DONTNEED);
0197 if (!ret) {
0198 printf("Unexpected success of madvise call with unaligned start address %d\n",
0199 __LINE__);
0200 exit(1);
0201 }
0202
0203
0204 if (madvise(addr,
0205 ((NR_HUGE_PAGES - 1) * huge_page_size) + base_page_size,
0206 MADV_DONTNEED)) {
0207 perror("madvise");
0208 exit(1);
0209 }
0210
0211
0212 validate_free_pages(free_hugepages);
0213
0214 (void)munmap(addr, NR_HUGE_PAGES * huge_page_size);
0215
0216
0217
0218
0219 addr = mmap(NULL, NR_HUGE_PAGES * huge_page_size,
0220 PROT_READ | PROT_WRITE,
0221 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
0222 -1, 0);
0223 if (addr == MAP_FAILED) {
0224 perror("mmap");
0225 exit(1);
0226 }
0227 write_fault_pages(addr, NR_HUGE_PAGES);
0228 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0229
0230 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_DONTNEED)) {
0231 perror("madvise");
0232 exit(1);
0233 }
0234
0235
0236 validate_free_pages(free_hugepages);
0237
0238 (void)munmap(addr, NR_HUGE_PAGES * huge_page_size);
0239
0240
0241
0242
0243 if (fallocate(fd, 0, 0, NR_HUGE_PAGES * huge_page_size)) {
0244 perror("fallocate");
0245 exit(1);
0246 }
0247 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0248
0249 addr = mmap(NULL, NR_HUGE_PAGES * huge_page_size,
0250 PROT_READ | PROT_WRITE,
0251 MAP_PRIVATE, fd, 0);
0252 if (addr == MAP_FAILED) {
0253 perror("mmap");
0254 exit(1);
0255 }
0256
0257
0258 read_fault_pages(addr, NR_HUGE_PAGES);
0259 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0260
0261
0262 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_DONTNEED)) {
0263 perror("madvise");
0264 exit(1);
0265 }
0266 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0267
0268
0269 write_fault_pages(addr, NR_HUGE_PAGES);
0270 validate_free_pages(free_hugepages - (2 * NR_HUGE_PAGES));
0271
0272
0273 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_DONTNEED)) {
0274 perror("madvise");
0275 exit(1);
0276 }
0277 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0278
0279
0280 write_fault_pages(addr, NR_HUGE_PAGES);
0281 validate_free_pages(free_hugepages - (2 * NR_HUGE_PAGES));
0282
0283
0284
0285
0286
0287
0288
0289
0290 if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0291 0, NR_HUGE_PAGES * huge_page_size)) {
0292 perror("fallocate");
0293 exit(1);
0294 }
0295 validate_free_pages(free_hugepages);
0296
0297 (void)munmap(addr, NR_HUGE_PAGES * huge_page_size);
0298
0299
0300
0301
0302 if (fallocate(fd, 0, 0, NR_HUGE_PAGES * huge_page_size)) {
0303 perror("fallocate");
0304 exit(1);
0305 }
0306 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0307
0308 addr = mmap(NULL, NR_HUGE_PAGES * huge_page_size,
0309 PROT_READ | PROT_WRITE,
0310 MAP_SHARED, fd, 0);
0311 if (addr == MAP_FAILED) {
0312 perror("mmap");
0313 exit(1);
0314 }
0315
0316
0317 write_fault_pages(addr, NR_HUGE_PAGES);
0318 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0319
0320
0321 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_DONTNEED)) {
0322 perror("madvise");
0323 exit(1);
0324 }
0325 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0326
0327
0328
0329
0330
0331
0332 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_REMOVE)) {
0333 perror("madvise");
0334 exit(1);
0335 }
0336 validate_free_pages(free_hugepages);
0337 (void)munmap(addr, NR_HUGE_PAGES * huge_page_size);
0338
0339
0340
0341
0342 if (fallocate(fd, 0, 0, NR_HUGE_PAGES * huge_page_size)) {
0343 perror("fallocate");
0344 exit(1);
0345 }
0346 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0347
0348 addr = mmap(NULL, NR_HUGE_PAGES * huge_page_size,
0349 PROT_READ | PROT_WRITE,
0350 MAP_SHARED, fd, 0);
0351 if (addr == MAP_FAILED) {
0352 perror("mmap");
0353 exit(1);
0354 }
0355
0356
0357 write_fault_pages(addr, NR_HUGE_PAGES);
0358 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0359
0360 addr2 = mmap(NULL, NR_HUGE_PAGES * huge_page_size,
0361 PROT_READ | PROT_WRITE,
0362 MAP_PRIVATE, fd, 0);
0363 if (addr2 == MAP_FAILED) {
0364 perror("mmap");
0365 exit(1);
0366 }
0367
0368
0369 read_fault_pages(addr2, NR_HUGE_PAGES);
0370 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0371
0372
0373 write_fault_pages(addr2, NR_HUGE_PAGES);
0374 validate_free_pages(free_hugepages - (2 * NR_HUGE_PAGES));
0375
0376
0377 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_DONTNEED)) {
0378 perror("madvise");
0379 exit(1);
0380 }
0381 validate_free_pages(free_hugepages - (2 * NR_HUGE_PAGES));
0382
0383
0384 if (madvise(addr2, NR_HUGE_PAGES * huge_page_size, MADV_DONTNEED)) {
0385 perror("madvise");
0386 exit(1);
0387 }
0388 validate_free_pages(free_hugepages - NR_HUGE_PAGES);
0389
0390
0391 write_fault_pages(addr2, NR_HUGE_PAGES);
0392 validate_free_pages(free_hugepages - (2 * NR_HUGE_PAGES));
0393
0394
0395
0396
0397
0398
0399 if (madvise(addr, NR_HUGE_PAGES * huge_page_size, MADV_REMOVE)) {
0400 perror("madvise");
0401 exit(1);
0402 }
0403 validate_free_pages(free_hugepages);
0404
0405 (void)munmap(addr, NR_HUGE_PAGES * huge_page_size);
0406 (void)munmap(addr2, NR_HUGE_PAGES * huge_page_size);
0407
0408 close(fd);
0409 unlink(argv[1]);
0410 return 0;
0411 }