Home | History | Annotate | Download | only in memtest
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <sys/time.h>
     21 #include <time.h>
     22 #include <unistd.h>
     23 #include <sched.h>
     24 #include <sys/resource.h>
     25 #include <sys/syscall.h>
     26 #include <sys/types.h>
     27 #include <sys/mman.h>
     28 
     29 #if 0
     30 const int DCACHE_SIZE = 8*1024;
     31 const int CPU_FREQ_EST = 195;
     32 const int BRANCH_CYCLE = 3;
     33 #else
     34 const int DCACHE_SIZE  = 32*1024;
     35 const int CPU_FREQ_EST = 384;
     36 const int BRANCH_CYCLE = 2;
     37 #endif
     38 
     39 //extern "C" void* xmemcpy(void*, void*, size_t);
     40 #define MEMCPY  memcpy
     41 
     42 typedef long long nsecs_t;
     43 
     44 static nsecs_t system_time()
     45 {
     46     struct timespec t;
     47     t.tv_sec = t.tv_nsec = 0;
     48     clock_gettime(CLOCK_MONOTONIC, &t);
     49     return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
     50 }
     51 
     52 nsecs_t loop_overhead(size_t count) __attribute__((noinline));
     53 nsecs_t loop_overhead(size_t count)
     54 {
     55     nsecs_t overhead = -system_time();
     56     do {
     57         asm volatile ("":::"memory");
     58     } while (--count);
     59     overhead += system_time();
     60     return overhead;
     61 }
     62 
     63 static void preload(volatile char* addr, size_t s)
     64 {
     65     for (size_t i=0 ; i<s ; i+=32) {
     66         char c = addr[i];
     67         (void)c;
     68     }
     69 }
     70 
     71 static void usage(char* p) {
     72     printf( "Usage: %s <test> <options>\n"
     73             "<test> is one of the following:\n"
     74             "       cpufreq\n"
     75             "       memcpy [perf [fast] | test]\n"
     76             "       memset [perf | test]\n"
     77             "       memcmp [perf | test]\n"
     78             "       strlen [perf | test]\n"
     79             "       malloc [fill]\n"
     80             "       madvise\n"
     81             "       resampler\n"
     82             "       crash\n"
     83             "       stack (stack smasher)\n"
     84             "       crawl\n"
     85             , p);
     86 }
     87 
     88 int cpufreq_test(int argc, char** argv);
     89 int memcpy_test(int argc, char** argv);
     90 int memset_test(int argc, char** argv);
     91 int memcmp_test(int argc, char** argv);
     92 int strlen_test(int argc, char** argv);
     93 int malloc_test(int argc, char** argv);
     94 int madvise_test(int argc, char** argv);
     95 int crash_test(int argc, char** argv);
     96 int stack_smasher_test(int argc, char** argv);
     97 int crawl_test(int argc, char** argv);
     98 int fp_test(int argc, char** argv);
     99 
    100 #if 0
    101 #pragma mark -
    102 #pragma mark main
    103 #endif
    104 
    105 int main(int argc, char** argv)
    106 {
    107     if (argc == 1) {
    108         usage(argv[0]);
    109         return 0;
    110     }
    111     int err = -1;
    112     if      (!strcmp(argv[1], "cpufreq"))   err = cpufreq_test(argc-1, argv+1);
    113     else if (!strcmp(argv[1], "memcpy"))    err = memcpy_test(argc-1, argv+1);
    114     else if (!strcmp(argv[1], "memset"))    err = memset_test(argc-1, argv+1);
    115     else if (!strcmp(argv[1], "memcmp"))    err = memcmp_test(argc-1, argv+1);
    116     else if (!strcmp(argv[1], "strlen"))    err = strlen_test(argc-1, argv+1);
    117     else if (!strcmp(argv[1], "malloc"))    err = malloc_test(argc-1, argv+1);
    118     else if (!strcmp(argv[1], "madvise"))   err = madvise_test(argc-1, argv+1);
    119     else if (!strcmp(argv[1], "crash"))     err = crash_test(argc-1, argv+1);
    120     else if (!strcmp(argv[1], "stack"))     err = stack_smasher_test(argc-1, argv+1);
    121     else if (!strcmp(argv[1], "crawl"))     err = crawl_test(argc-1, argv+1);
    122     else if (!strcmp(argv[1], "fp"))     err = fp_test(argc-1, argv+1);
    123     if (err) {
    124         usage(argv[0]);
    125     }
    126     return 0;
    127 }
    128 
    129 #if 0
    130 #pragma mark -
    131 #pragma mark memcpy
    132 #endif
    133 
    134 int validate_memcpy(char* s, char* d, size_t size);
    135 int validate_memset(char* s, char c, size_t size);
    136 
    137 int memcpy_test(int argc, char** argv)
    138 {
    139     int option = 0;
    140     if (argc >= 2) {
    141         if (!strcmp(argv[1], "perf"))       option = 0;
    142         else if (!strcmp(argv[1], "test"))  option = 1;
    143         else                                return -1;
    144     }
    145 
    146     const int MAX_SIZE = 1024*1024; // 1MB
    147     const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
    148     const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
    149     char* src = (char*)malloc(MAX_SIZE+4+8+32);
    150     char* dst = (char*)malloc(MAX_SIZE+4+8+32);
    151     memset(src, 0, MAX_SIZE+4+8+32);
    152     memset(dst, 0, MAX_SIZE+4+8+32);
    153 
    154     if (option == 0) {
    155         bool fast = (argc>=3 && !strcmp(argv[2], "fast"));
    156         printf("memcpy() performance test is running, please wait...\n");
    157         fflush(stdout);
    158         usleep(10000);
    159         setpriority(PRIO_PROCESS, 0, -20);
    160         static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
    161 
    162         struct result_t { int size; float res; };
    163         result_t* results = (result_t*)src;
    164         int nbr = 0;
    165         int size = 0;
    166         for (int i=0 ; ; i++) {
    167             if (!fast) {
    168                 if (size<128)          size += 8;
    169                 else if (size<1024)    size += 128;
    170                 else if (size<16384)   size += 1024;
    171                 else                   size <<= 1;
    172             } else {
    173                 if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
    174                     break;
    175                 size = FAST_SIZES[i];
    176             }
    177             if (size > MAX_SIZE) {
    178                 break;
    179             }
    180 
    181             const int REPEAT = (((size < DCACHE_SIZE) ?
    182                         (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
    183                                 // ~0.5 second per test
    184 
    185             const nsecs_t overhead = loop_overhead(REPEAT);
    186 
    187             // tweak to make it a bad case
    188             char* ddd = (char*)((long(dst+31)&~31) + 4);
    189             char* sss = (char*)((long(src+31)&~31) + 28);
    190 
    191             for (int offset=0 ; offset<=2 ; offset +=2 ) {
    192                 memcpy(dst, src, size); // just make sure to load the caches I/D
    193                 nsecs_t t = -system_time();
    194                 register int count = REPEAT;
    195                 do {
    196                     MEMCPY(ddd, sss+offset, size);
    197                 } while (--count);
    198                 t += system_time() - overhead;
    199                 const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
    200                 results[nbr].size = size;
    201                 results[nbr].res = throughput;
    202                 nbr++;
    203             }
    204         }
    205 
    206         printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
    207         for (int i=0 ; i<nbr ; i+=2) {
    208             printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
    209         }
    210     } else if (option == 1) {
    211         printf("memcpy() validation test is running, please wait...\n");
    212         fflush(stdout);
    213         char* curr = (char*)src;
    214         for (int i=0 ; i<MAX_SIZE ; i++) {
    215             char c = rand();
    216             *curr++ = c != 0x55 ? c : 0xAA;
    217         }
    218         char* s = src + 1024;
    219         char* d = dst + 1024;
    220         int nb = 0;
    221         for (int size=0 ; size<4096 && !nb ; size++) {
    222             nb += validate_memcpy(s, d, size);
    223             for (int o=1 ; o<32 && !nb ; o++) {
    224                 nb += validate_memcpy(s+o, d, size);
    225                 nb += validate_memcpy(s, d+o, size);
    226                 nb += validate_memcpy(s+o, d+o, size);
    227             }
    228         }
    229         if (nb) printf("%d error(s) found\n", nb);
    230         else    printf("success!\n");
    231     }
    232     fflush(stdout);
    233     free(dst);
    234     free(src);
    235     return 0;
    236 }
    237 
    238 int validate_memcpy(char* s, char* d, size_t size)
    239 {
    240     int nberr = 0;
    241     memset(d-4, 0x55, size+8);
    242     MEMCPY(s, d, size);
    243     if (memcmp(s,d,size)) {
    244         printf("*** memcpy(%p,%p,%zd) destination != source\n",s,d,size);
    245         nberr++;
    246     }
    247     bool r = (d[size]==0x55)&&(d[size+1]==0x55)&&(d[size+2]==0x55)&&(d[size+3]==0x55);
    248     if (!r) {
    249         printf("*** memcpy(%p,%p,%zd) clobbered past end of destination!\n",s,d,size);
    250         nberr++;
    251     }
    252     r = (d[-1]==0x55)&&(d[-2]==0x55)&&(d[-3]==0x55)&&(d[-4]==0x55);
    253     if (!r) {
    254         printf("*** memcpy(%p,%p,%zd) clobbered before start of destination!\n",s,d,size);
    255         nberr++;
    256     }
    257     return nberr;
    258 }
    259 
    260 
    261 #if 0
    262 #pragma mark -
    263 #pragma mark memset
    264 #endif
    265 
    266 int memset_test(int argc, char** argv)
    267 {
    268     int option = 0;
    269     if (argc >= 2) {
    270         if (!strcmp(argv[1], "perf"))       option = 0;
    271         else if (!strcmp(argv[1], "test"))  option = 1;
    272         else                                return -1;
    273     }
    274 
    275     const int MAX_SIZE = 1024*1024; // 1MB
    276     const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
    277     const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
    278     char* dst = (char*)malloc(MAX_SIZE+4+8);
    279 
    280     if (option == 0) {
    281         printf("memset() performance test is running, please wait...\n");
    282         fflush(stdout);
    283         usleep(10000);
    284         setpriority(PRIO_PROCESS, 0, -20);
    285 
    286         static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
    287         const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
    288         struct result_t { int size; float res; };
    289         result_t results[FAST_SIZES_COUNT*2];
    290         int nbr = 0;
    291         int size = 0;
    292         for (int i=0 ; ; i++) {
    293             if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
    294                 break;
    295             size = FAST_SIZES[i];
    296             if (size > MAX_SIZE) {
    297                 break;
    298             }
    299             const int REPEAT = (((size < DCACHE_SIZE) ?
    300                         (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
    301                                 // ~0.5 second per test
    302 
    303             const nsecs_t overhead = loop_overhead(REPEAT);
    304 
    305             for (int j=0 ; j<2 ; j++) {
    306                 if (j==0)   preload(dst, DCACHE_SIZE*4);   // flush D
    307                 else        preload(dst, size);            // load D
    308                 nsecs_t t = -system_time();
    309                 size_t count = REPEAT;
    310                 do {
    311                     memset(dst, 0, size);
    312                 } while (--count);
    313                 t += system_time() - overhead;
    314 
    315                 const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
    316                 results[nbr].size = size;
    317                 results[nbr].res = throughput;
    318                 nbr++;
    319             }
    320         }
    321 
    322         printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
    323         for (int i=0 ; i<nbr ; i+=2) {
    324             printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
    325         }
    326     } else if (option == 1) {
    327         printf("memset() validation test is running, please wait...\n");
    328         fflush(stdout);
    329         char* d = dst + 1024;
    330         int nb = 0;
    331         for (int o=1 ; o<32 ; o++) {
    332             for (int size=0 ; size<4096 && !nb ; size++) {
    333                 nb += validate_memset(d, char(o), size);
    334                 nb += validate_memset(d+o, char(o), size);
    335             }
    336         }
    337         if (nb) printf("%d error(s) found\n", nb);
    338         else    printf("success!\n");
    339     }
    340     fflush(stdout);
    341     free(dst);
    342     return 0;
    343 }
    344 
    345 int validate_memset(char* d, char c, size_t size)
    346 {
    347     int nberr = 0;
    348     for (size_t i=0; i<size ; d[i++]=0xaa) ;
    349     d[-1] = 0x55;
    350     d[size+1] = 0x55;
    351     memset(d, c, size);
    352     if (d[size+1]!=0x55) {
    353         printf("*** memset(%p,%02x,%zd) clobbered past end of destination!\n",d,(int)c,size);
    354         nberr++;
    355     }
    356     if (d[-1]!=0x55) {
    357         printf("*** memset(%p,%02x,%zd) clobbered before start of destination!\n",d,(int)c,size);
    358         nberr++;
    359     }
    360     for (size_t i=0 ; i<size ; i++) {
    361         if (d[i] != c) {
    362             printf("*** memset(%p,%02x,%zd) failed at offset %zd\n",d,(int)c,size, i);
    363             nberr++;
    364             break;
    365         }
    366     }
    367     return nberr;
    368 }
    369 
    370 #if 0
    371 #pragma mark -
    372 #pragma mark memcmp
    373 #endif
    374 
    375 static int ref_memcmp(const void *s1, const void *s2, size_t n)
    376 {
    377   const unsigned char *c1 = (const unsigned char *)s1, *c2 = (const unsigned char *)s2;
    378   int d = 0;
    379 
    380   while ( n-- ) {
    381     d = (int)*c1++ - (int)*c2++;
    382     if ( d )
    383       break;
    384   }
    385 
    386   return (d < 0 ? -1 : (d > 0 ? 1 : 0));
    387 }
    388 
    389 int validate_memcmp(const char* s, const char* d, size_t size)
    390 {
    391 
    392     int a = ref_memcmp(s, d, size);
    393     int b = memcmp(s, d, size);
    394     b = (b < 0 ? -1 : (b > 0 ? 1 : 0));
    395     //printf("%d, %d\n", a, b);
    396     if (a != b) {
    397         printf("*** memcmp(%p,%p,%zd) failed %d should be %d\n",s,d,size,b,a);
    398         return 1;
    399     }
    400     return 0;
    401 }
    402 
    403 int memcmp_test(int argc, char** argv)
    404 {
    405     int option = 0;
    406     if (argc >= 2) {
    407         if (!strcmp(argv[1], "perf"))       option = 0;
    408         else if (!strcmp(argv[1], "test"))  option = 1;
    409         else                                return -1;
    410     }
    411 
    412     const int MAX_SIZE = 1024*1024; // 1MB
    413     const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
    414     const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
    415     char* src = (char*)malloc(MAX_SIZE+4+8+32);
    416     char* dst = (char*)malloc(MAX_SIZE+4+8+32);
    417 
    418     if (option == 0) {
    419         printf("memcmp() performance test is running, please wait...\n");
    420         fflush(stdout);
    421         usleep(10000);
    422         setpriority(PRIO_PROCESS, 0, -20);
    423 
    424         static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
    425 
    426         struct result_t { int size; float res; };
    427         result_t* results = (result_t*)src;
    428         int nbr = 0;
    429         int size = 0;
    430         for (int i=0 ; ; i++) {
    431             if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
    432                 break;
    433             size = FAST_SIZES[i];
    434             if (size > MAX_SIZE) {
    435                 break;
    436             }
    437 
    438             const int REPEAT = (((size < DCACHE_SIZE) ?
    439                         (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
    440                                 // ~0.5 second per test
    441 
    442             const nsecs_t overhead = loop_overhead(REPEAT);
    443 
    444             // tweak to make it a bad case
    445             char* ddd = (char*)((long(dst+31)&~31) + 4);
    446             char* sss = (char*)((long(src+31)&~31) + 28);
    447 
    448             for (int offset=0 ; offset<=2 ; offset +=2 ) {
    449                 memcpy(ddd, sss+offset, size); // just make sure to load the caches I/D
    450                 nsecs_t t = -system_time();
    451                 register int count = REPEAT;
    452                 char c;
    453                 c = memcmp(ddd, sss+offset, size);
    454                 //printf("size %d, memcmp -> %d\n", size, (int)c);
    455                 do {
    456                     c = memcmp(ddd, sss+offset, size);
    457                     asm volatile (""::"r"(c):"memory");
    458                 } while (--count);
    459                 t += system_time() - overhead;
    460                 const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
    461                 results[nbr].size = size;
    462                 results[nbr].res = throughput;
    463                 nbr++;
    464             }
    465         }
    466 
    467         printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
    468         for (int i=0 ; i<nbr ; i+=2) {
    469             printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
    470         }
    471     } else {
    472         printf("memcmp() validation test is running, please wait...\n");
    473         fflush(stdout);
    474 
    475         const char* const s = (const char*)src + 1024;
    476         const char* const d = (const char*)dst + 1024;
    477         int nb = 0;
    478         for (int j=0 ; j<32 ; j++) {
    479 
    480             char *curr0 = (char*)src;
    481             char *curr1 = (char*)dst;
    482             for (int i=0 ; i<MAX_SIZE ; i++) {
    483                 char c = rand();
    484                 *curr0++ = c;
    485                 *curr1++ = c;
    486             }
    487             if (j) {
    488                 src[1024 + j] ^= 0xFF;
    489             }
    490 
    491 
    492             for (int size=0 ; size<32 && !nb ; size++) {
    493                 for (int o=0 ; o<4 ; o++) {
    494                     nb += validate_memcmp(s+o, d+o, size);
    495                 }
    496                // memmove((char*)d+1, d, size);
    497                 for (int o=0 ; o<4 ; o++) {
    498                     nb += validate_memcmp(s, d+o, size);
    499                 }
    500             }
    501         }
    502         if (nb) printf("%d error(s) found\n", nb);
    503         else    printf("success!\n");
    504     }
    505     fflush(stdout);
    506     free(dst);
    507     free(src);
    508     return 0;
    509 }
    510 
    511 #if 0
    512 #pragma mark -
    513 #pragma mark strlen
    514 #endif
    515 
    516 int strlen_test(int argc, char** argv)
    517 {
    518     int option = 0;
    519     if (argc >= 2) {
    520         if (!strcmp(argv[1], "perf"))       option = 0;
    521         else if (!strcmp(argv[1], "test"))  option = 1;
    522         else                                return -1;
    523     }
    524 
    525     const int MAX_SIZE = 1024*1024; // 1MB
    526     const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
    527     const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
    528     char* str = (char*)calloc(MAX_SIZE+4+8, 1);
    529 
    530     if (option == 0) {
    531         printf("strlen() performance test is running, please wait...\n");
    532         fflush(stdout);
    533         usleep(10000);
    534         setpriority(PRIO_PROCESS, 0, -20);
    535 
    536         static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
    537         const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
    538         struct result_t { int size; float res; };
    539         result_t results[FAST_SIZES_COUNT*2];
    540         int nbr = 0;
    541         int size = 0;
    542         for (int i=0 ; ; i++) {
    543             if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
    544                 break;
    545             size = FAST_SIZES[i];
    546             if (size > MAX_SIZE) {
    547                 break;
    548             }
    549             const int REPEAT = (((size < DCACHE_SIZE) ?
    550                         (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
    551                                 // ~0.5 second per test
    552 
    553             const nsecs_t overhead = loop_overhead(REPEAT);
    554 
    555             for (int j=0 ; j<2 ; j++) {
    556                 memset(str, 'A', size-1);
    557                 if (j==0)   preload(str, DCACHE_SIZE*4);   // flush D
    558                 else        preload(str, size);            // load D
    559 
    560                 nsecs_t t = -system_time();
    561                 size_t count = REPEAT;
    562                 int c=0;
    563                 do {
    564                     c = strlen(str);
    565                     asm volatile (""::"r"(c):"memory");
    566                 } while (--count);
    567                 t += system_time() - overhead;
    568 
    569                 const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
    570                 results[nbr].size = size;
    571                 results[nbr].res = throughput;
    572                 nbr++;
    573             }
    574         }
    575 
    576         printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
    577         for (int i=0 ; i<nbr ; i+=2) {
    578             printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
    579         }
    580     }
    581 
    582     fflush(stdout);
    583     free(str);
    584     return 0;
    585 }
    586 
    587 
    588 #if 0
    589 #pragma mark -
    590 #pragma mark malloc
    591 #endif
    592 
    593 int malloc_test(int argc, char** argv)
    594 {
    595     bool fill = (argc>=2 && !strcmp(argv[1], "fill"));
    596     size_t total = 0;
    597     size_t size = 0x40000000;
    598     while (size) {
    599         void* addr = malloc(size);
    600         if (addr == 0) {
    601             printf("size = %9zd failed\n", size);
    602             size >>= 1;
    603         } else {
    604             total += size;
    605             printf("size = %9zd, addr = %p (total = %9zd (%zd MB))\n",
    606                     size, addr, total, total / (1024*1024));
    607             if (fill) {
    608                 printf("filling...\n");
    609                 fflush(stdout);
    610                 memset(addr, 0, size);
    611             }
    612             size = size + (size>>1);
    613         }
    614     }
    615     printf("done. allocated %zd MB\n", total / (1024*1024));
    616     return 0;
    617 }
    618 
    619 #if 0
    620 #pragma mark -
    621 #pragma mark madvise
    622 #endif
    623 
    624 int madvise_test(int argc, char** argv)
    625 {
    626     for (int i=0 ; i<2 ; i++) {
    627         size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB
    628         printf("Allocating %zd MB... ", size/(1024*1024)); fflush(stdout);
    629         void* addr1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    630         printf("%p (%s)\n", addr1, addr1==(void*)-1 ? "failed" : "OK"); fflush(stdout);
    631 
    632         printf("touching %p...\n", addr1); fflush(stdout);
    633         memset(addr1, 0x55, size);
    634 
    635         printf("advising DONTNEED...\n"); fflush(stdout);
    636         madvise(addr1, size, MADV_DONTNEED);
    637 
    638         printf("reading back %p...\n", addr1); fflush(stdout);
    639         if (*(long*)addr1 == 0) {
    640             printf("madvise freed some pages\n");
    641         } else if (*(long*)addr1 == 0x55555555) {
    642             printf("pages are still there\n");
    643         } else {
    644             printf("getting garbage back\n");
    645         }
    646 
    647         printf("Allocating %zd MB... ", size/(1024*1024)); fflush(stdout);
    648         void* addr2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    649         printf("%p (%s)\n", addr2, addr2==(void*)-1 ? "failed" : "OK"); fflush(stdout);
    650 
    651         printf("touching %p...\n", addr2); fflush(stdout);
    652         memset(addr2, 0xAA, size);
    653 
    654         printf("unmap %p ...\n", addr2); fflush(stdout);
    655         munmap(addr2, size);
    656 
    657         printf("touching %p...\n", addr1); fflush(stdout);
    658         memset(addr1, 0x55, size);
    659 
    660         printf("unmap %p ...\n", addr1); fflush(stdout);
    661         munmap(addr1, size);
    662     }
    663 
    664     printf("Done\n"); fflush(stdout);
    665     return 0;
    666 }
    667 
    668 #if 0
    669 #pragma mark -
    670 #pragma mark cpufreq
    671 #endif
    672 
    673 int cpufreq_test(int argc, char** argv)
    674 {
    675     struct timespec res;
    676     clock_getres(CLOCK_REALTIME, &res);
    677     printf("CLOCK_REALTIME  resolution: %lu ns\n", res.tv_nsec);
    678     clock_getres(CLOCK_MONOTONIC, &res);
    679     printf("CLOCK_MONOTONIC resolution: %lu ns\n", res.tv_nsec);
    680     clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res);
    681     printf("CLOCK_PROCESS_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec);
    682     clock_getres(CLOCK_THREAD_CPUTIME_ID, &res);
    683     printf("CLOCK_THREAD_CPUTIME_ID  resolution: %lu ns\n", res.tv_nsec);
    684 
    685     if (clock_getres(CLOCK_REALTIME_HR, &res) != 0)
    686         printf("CLOCK_REALTIME_HR   resolution: %lu ns\n", res.tv_nsec);
    687     else
    688         printf("CLOCK_REALTIME_HR   not supported\n");
    689 
    690     if (clock_getres(CLOCK_MONOTONIC_HR, &res) != 0)
    691         printf("CLOCK_MONOTONIC_HR  resolution: %lu ns\n", res.tv_nsec);
    692     else
    693         printf("CLOCK_MONOTONIC_HR  not supported\n");
    694 
    695     printf("\nEstimating the CPU frequency, please wait...\n");
    696     fflush(stdout);
    697     usleep(10000);
    698     setpriority(PRIO_PROCESS, 0, -20);
    699 
    700     const int LOOP_CYCLES = 1+BRANCH_CYCLE; // 1 cycle + 3 cycles for the branch
    701     const size_t REPEAT = CPU_FREQ_EST*1000000;   // ~4 seconds (4cycles/loop)
    702     register size_t count = REPEAT;
    703     nsecs_t t = system_time();
    704     do { // this loop generates 1+3 cycles
    705         asm volatile ("":::"memory");
    706     } while (--count);
    707     t = system_time() - t;
    708     const float freq = t ? (1000.0f*float(REPEAT)*LOOP_CYCLES) / t : 0;
    709     printf("this CPU frequency: %ld MHz\n", long(freq+0.5f));
    710     return 0;
    711 }
    712 
    713 #if 0
    714 #pragma mark -
    715 #pragma mark crash_test
    716 #endif
    717 
    718 int crash_test(int argc, char** argv)
    719 {
    720     printf("about to crash...\n");
    721     asm volatile(
    722         "mov r0,  #0 \n"
    723         "mov r1,  #1 \n"
    724         "mov r2,  #2 \n"
    725         "mov r3,  #3 \n"
    726         "ldr r12, [r0] \n"
    727     );
    728 
    729     return 0;
    730 }
    731 
    732 int stack_smasher_test(int argc, char** argv)
    733 {
    734     int dummy = 0;
    735     printf("corrupting our stack...\n");
    736     *(volatile long long*)&dummy = 0;
    737     return 0;
    738 }
    739 
    740 // --------------------------------------------------------------------
    741 
    742 extern "C" void thumb_function_1(int*p);
    743 extern "C" void thumb_function_2(int*p);
    744 extern "C" void arm_function_3(int*p);
    745 extern "C" void arm_function_2(int*p);
    746 extern "C" void arm_function_1(int*p);
    747 
    748 void arm_function_3(int*p) {
    749     int a = 0;
    750     thumb_function_2(&a);
    751 }
    752 
    753 void arm_function_2(int*p) {
    754     int a = 0;
    755     thumb_function_1(&a);
    756 }
    757 
    758 void arm_function_1(int*p) {
    759     int a = 0;
    760     arm_function_2(&a);
    761 }
    762 
    763 int crawl_test(int argc, char** argv)
    764 {
    765     int a = 0;
    766     arm_function_1(&a);
    767     return 0;
    768 }
    769 
    770