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
30const int DCACHE_SIZE = 8*1024;
31const int CPU_FREQ_EST = 195;
32const int BRANCH_CYCLE = 3;
33#else
34const int DCACHE_SIZE  = 32*1024;
35const int CPU_FREQ_EST = 384;
36const int BRANCH_CYCLE = 2;
37#endif
38
39//extern "C" void* xmemcpy(void*, void*, size_t);
40#define MEMCPY  memcpy
41
42typedef long long nsecs_t;
43
44static 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
52nsecs_t loop_overhead(size_t count) __attribute__((noinline));
53nsecs_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
63static 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
71static 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
88int cpufreq_test(int argc, char** argv);
89int memcpy_test(int argc, char** argv);
90int memset_test(int argc, char** argv);
91int memcmp_test(int argc, char** argv);
92int strlen_test(int argc, char** argv);
93int malloc_test(int argc, char** argv);
94int madvise_test(int argc, char** argv);
95int crash_test(int argc, char** argv);
96int stack_smasher_test(int argc, char** argv);
97int crawl_test(int argc, char** argv);
98int fp_test(int argc, char** argv);
99
100#if 0
101#pragma mark -
102#pragma mark main
103#endif
104
105int 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
134int validate_memcpy(char* s, char* d, size_t size);
135int validate_memset(char* s, char c, size_t size);
136
137int 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
238int 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
266int 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
345int 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
375static 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
389int 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
403int 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
516int 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
593int 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
624int 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
673int 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
718int 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
732int 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
742extern "C" void thumb_function_1(int*p);
743extern "C" void thumb_function_2(int*p);
744extern "C" void arm_function_3(int*p);
745extern "C" void arm_function_2(int*p);
746extern "C" void arm_function_1(int*p);
747
748void arm_function_3(int*p) {
749    int a = 0;
750    thumb_function_2(&a);
751}
752
753void arm_function_2(int*p) {
754    int a = 0;
755    thumb_function_1(&a);
756}
757
758void arm_function_1(int*p) {
759    int a = 0;
760    arm_function_2(&a);
761}
762
763int crawl_test(int argc, char** argv)
764{
765    int a = 0;
766    arm_function_1(&a);
767    return 0;
768}
769
770