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