memtest.cpp revision b4950a59dcd4fa7fa4adaec6c8429388c2640291
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);
98
99#if 0
100#pragma mark -
101#pragma mark main
102#endif
103
104int 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
132int validate_memcpy(char* s, char* d, size_t size);
133int validate_memset(char* s, char c, size_t size);
134
135int 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
236int 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,%lu) 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,%lu) 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,%lu) 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
264int 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
343int 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,%lu) clobbered past end of destination!\n",d,(int)c,size);
352        nberr++;
353    }
354    if (d[-1]!=0x55) {
355        printf("*** memset(%p,%02x,%lu) 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,%lu) failed at offset %lu\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
373static 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;
385}
386
387int 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    //printf("%d, %d\n", a, b);
393    if (a != b) {
394        printf("*** memcmp(%p,%p,%lu) failed %d should be %d\n",s,d,size,b,a);
395        return 1;
396    }
397    return 0;
398}
399
400int memcmp_test(int argc, char** argv)
401{
402    int option = 0;
403    if (argc >= 2) {
404        if (!strcmp(argv[1], "perf"))       option = 0;
405        else if (!strcmp(argv[1], "test"))  option = 1;
406        else                                return -1;
407    }
408
409    const int MAX_SIZE = 1024*1024; // 1MB
410    const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 150 MB/s
411    const int UNCACHED_SPEED_EST = (CPU_FREQ_EST/4)*1024*1024; // 60 MB/s
412    char* src = (char*)malloc(MAX_SIZE+4+8+32);
413    char* dst = (char*)malloc(MAX_SIZE+4+8+32);
414
415    if (option == 0) {
416        printf("memcmp() performance test is running, please wait...\n");
417        fflush(stdout);
418        usleep(10000);
419        setpriority(PRIO_PROCESS, 0, -20);
420
421        static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
422
423        struct result_t { int size; float res; };
424        result_t* results = (result_t*)src;
425        int nbr = 0;
426        int size = 0;
427        for (int i=0 ; ; i++) {
428            if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
429                break;
430            size = FAST_SIZES[i];
431            if (size > MAX_SIZE) {
432                break;
433            }
434
435            const int REPEAT = (((size < DCACHE_SIZE) ?
436                        (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size) / 2;
437                                // ~0.5 second per test
438
439            const nsecs_t overhead = loop_overhead(REPEAT);
440
441            // tweak to make it a bad case
442            char* ddd = (char*)((long(dst+31)&~31) + 4);
443            char* sss = (char*)((long(src+31)&~31) + 28);
444
445            for (int offset=0 ; offset<=2 ; offset +=2 ) {
446                memcpy(ddd, sss+offset, size); // just make sure to load the caches I/D
447                nsecs_t t = -system_time();
448                register int count = REPEAT;
449                char c;
450                c = memcmp(ddd, sss+offset, size);
451                //printf("size %d, memcmp -> %d\n", size, (int)c);
452                do {
453                    c = memcmp(ddd, sss+offset, size);
454                    asm volatile (""::"r"(c):"memory");
455                } while (--count);
456                t += system_time() - overhead;
457                const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
458                results[nbr].size = size;
459                results[nbr].res = throughput;
460                nbr++;
461            }
462        }
463
464        printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (nc)");
465        for (int i=0 ; i<nbr ; i+=2) {
466            printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
467        }
468    } else {
469        printf("memcmp() validation test is running, please wait...\n");
470        fflush(stdout);
471
472        const char* const s = (const char*)src + 1024;
473        const char* const d = (const char*)dst + 1024;
474        int nb = 0;
475        for (int j=0 ; j<32 ; j++) {
476
477            char *curr0 = (char*)src;
478            char *curr1 = (char*)dst;
479            for (int i=0 ; i<MAX_SIZE ; i++) {
480                char c = rand();
481                *curr0++ = c;
482                *curr1++ = c;
483            }
484            if (j) {
485                src[1024 + j] ^= 0xFF;
486            }
487
488
489            for (int size=0 ; size<32 && !nb ; size++) {
490                for (int o=0 ; o<4 ; o++) {
491                    nb += validate_memcmp(s+o, d+o, size);
492                }
493               // memmove((char*)d+1, d, size);
494                for (int o=0 ; o<4 ; o++) {
495                    nb += validate_memcmp(s, d+o, size);
496                }
497            }
498        }
499        if (nb) printf("%d error(s) found\n", nb);
500        else    printf("success!\n");
501    }
502    fflush(stdout);
503    free(dst);
504    free(src);
505    return 0;
506}
507
508#if 0
509#pragma mark -
510#pragma mark strlen
511#endif
512
513int strlen_test(int argc, char** argv)
514{
515    int option = 0;
516    if (argc >= 2) {
517        if (!strcmp(argv[1], "perf"))       option = 0;
518        else if (!strcmp(argv[1], "test"))  option = 1;
519        else                                return -1;
520    }
521
522    const int MAX_SIZE = 1024*1024; // 1MB
523    const int CACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
524    const int UNCACHED_SPEED_EST = CPU_FREQ_EST*1024*1024; // 195 MB/s
525    char* str = (char*)calloc(MAX_SIZE+4+8, 1);
526
527    if (option == 0) {
528        printf("strlen() performance test is running, please wait...\n");
529        fflush(stdout);
530        usleep(10000);
531        setpriority(PRIO_PROCESS, 0, -20);
532
533        static int FAST_SIZES[] = { 1024, DCACHE_SIZE/2, DCACHE_SIZE, DCACHE_SIZE*2, MAX_SIZE };
534        const size_t FAST_SIZES_COUNT = sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]);
535        struct result_t { int size; float res; };
536        result_t results[FAST_SIZES_COUNT*2];
537        int nbr = 0;
538        int size = 0;
539        for (int i=0 ; ; i++) {
540            if (size_t(i) >= sizeof(FAST_SIZES)/sizeof(FAST_SIZES[0]))
541                break;
542            size = FAST_SIZES[i];
543            if (size > MAX_SIZE) {
544                break;
545            }
546            const int REPEAT = (((size < DCACHE_SIZE) ?
547                        (CACHED_SPEED_EST) : (UNCACHED_SPEED_EST)) / size);
548                                // ~0.5 second per test
549
550            const nsecs_t overhead = loop_overhead(REPEAT);
551
552            for (int j=0 ; j<2 ; j++) {
553                memset(str, 'A', size-1);
554                if (j==0)   preload(str, DCACHE_SIZE*4);   // flush D
555                else        preload(str, size);            // load D
556
557                nsecs_t t = -system_time();
558                size_t count = REPEAT;
559                int c=0;
560                do {
561                    c = strlen(str);
562                    asm volatile (""::"r"(c):"memory");
563                } while (--count);
564                t += system_time() - overhead;
565
566                const float throughput = (size*1000000000.0f*REPEAT) / (1024*1024*t);
567                results[nbr].size = size;
568                results[nbr].res = throughput;
569                nbr++;
570            }
571        }
572
573        printf("%9s %9s %9s\n", "size", "MB/s", "MB/s (cached)");
574        for (int i=0 ; i<nbr ; i+=2) {
575            printf("%9d %9ld %9ld\n", results[i].size, (long)results[i].res, (long)results[i+1].res);
576        }
577    }
578
579    fflush(stdout);
580    free(str);
581    return 0;
582}
583
584
585#if 0
586#pragma mark -
587#pragma mark malloc
588#endif
589
590int malloc_test(int argc, char** argv)
591{
592    bool fill = (argc>=2 && !strcmp(argv[1], "fill"));
593    size_t total = 0;
594    size_t size = 0x40000000;
595    while (size) {
596        void* addr = malloc(size);
597        if (addr == 0) {
598            printf("size = %9lu failed\n", size);
599            size >>= 1;
600        } else {
601            total += size;
602            printf("size = %9lu, addr = %p (total = %9lu (%lu MB))\n",
603                    size, addr, total, total / (1024*1024));
604            if (fill) {
605                printf("filling...\n");
606                fflush(stdout);
607                memset(addr, 0, size);
608            }
609            size = size + size>>1;
610        }
611    }
612    printf("done. allocated %lu MB\n", total / (1024*1024));
613    return 0;
614}
615
616#if 0
617#pragma mark -
618#pragma mark madvise
619#endif
620
621int madvise_test(int argc, char** argv)
622{
623    for (int i=0 ; i<2 ; i++) {
624        size_t size = i==0 ? 4096 : 48*1024*1024; // 48 MB
625        printf("Allocating %lu MB... ", size/(1024*1024)); fflush(stdout);
626        void* addr1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
627        printf("%p (%s)\n", addr1, addr1==(void*)-1 ? "failed" : "OK"); fflush(stdout);
628
629        printf("touching %p...\n", addr1); fflush(stdout);
630        memset(addr1, 0x55, size);
631
632        printf("advising DONTNEED...\n"); fflush(stdout);
633        madvise(addr1, size, MADV_DONTNEED);
634
635        printf("reading back %p...\n", addr1); fflush(stdout);
636        if (*(long*)addr1 == 0) {
637            printf("madvise freed some pages\n");
638        } else if (*(long*)addr1 == 0x55555555) {
639            printf("pages are still there\n");
640        } else {
641            printf("getting garbage back\n");
642        }
643
644        printf("Allocating %lu MB... ", size/(1024*1024)); fflush(stdout);
645        void* addr2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
646        printf("%p (%s)\n", addr2, addr2==(void*)-1 ? "failed" : "OK"); fflush(stdout);
647
648        printf("touching %p...\n", addr2); fflush(stdout);
649        memset(addr2, 0xAA, size);
650
651        printf("unmap %p ...\n", addr2); fflush(stdout);
652        munmap(addr2, size);
653
654        printf("touching %p...\n", addr1); fflush(stdout);
655        memset(addr1, 0x55, size);
656
657        printf("unmap %p ...\n", addr1); fflush(stdout);
658        munmap(addr1, size);
659    }
660
661    printf("Done\n"); fflush(stdout);
662    return 0;
663}
664
665#if 0
666#pragma mark -
667#pragma mark cpufreq
668#endif
669
670int cpufreq_test(int argc, char** argv)
671{
672    struct timespec res;
673    clock_getres(CLOCK_REALTIME, &res);
674    printf("CLOCK_REALTIME  resolution: %lu ns\n", res.tv_nsec);
675    clock_getres(CLOCK_MONOTONIC, &res);
676    printf("CLOCK_MONOTONIC resolution: %lu ns\n", res.tv_nsec);
677    clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res);
678    printf("CLOCK_PROCESS_CPUTIME_ID resolution: %lu ns\n", res.tv_nsec);
679    clock_getres(CLOCK_THREAD_CPUTIME_ID, &res);
680    printf("CLOCK_THREAD_CPUTIME_ID  resolution: %lu ns\n", res.tv_nsec);
681
682    if (clock_getres(CLOCK_REALTIME_HR, &res) != 0)
683        printf("CLOCK_REALTIME_HR   resolution: %lu ns\n", res.tv_nsec);
684    else
685        printf("CLOCK_REALTIME_HR   not supported\n");
686
687    if (clock_getres(CLOCK_MONOTONIC_HR, &res) != 0)
688        printf("CLOCK_MONOTONIC_HR  resolution: %lu ns\n", res.tv_nsec);
689    else
690        printf("CLOCK_MONOTONIC_HR  not supported\n");
691
692    printf("\nEstimating the CPU frequency, please wait...\n");
693    fflush(stdout);
694    usleep(10000);
695    setpriority(PRIO_PROCESS, 0, -20);
696
697    const int LOOP_CYCLES = 1+BRANCH_CYCLE; // 1 cycle + 3 cycles for the branch
698    const size_t REPEAT = CPU_FREQ_EST*1000000;   // ~4 seconds (4cycles/loop)
699    register size_t count = REPEAT;
700    nsecs_t t = system_time();
701    do { // this loop generates 1+3 cycles
702        asm volatile ("":::"memory");
703    } while (--count);
704    t = system_time() - t;
705    const float freq = t ? (1000.0f*float(REPEAT)*LOOP_CYCLES) / t : 0;
706    printf("this CPU frequency: %ld MHz\n", long(freq+0.5f));
707    return 0;
708}
709
710#if 0
711#pragma mark -
712#pragma mark crash_test
713#endif
714
715int crash_test(int argc, char** argv)
716{
717    printf("about to crash...\n");
718    asm volatile(
719        "mov r0,  #0 \n"
720        "mov r1,  #1 \n"
721        "mov r2,  #2 \n"
722        "mov r3,  #3 \n"
723        "ldr r12, [r0] \n"
724    );
725
726    return 0;
727}
728
729int stack_smasher_test(int argc, char** argv)
730{
731    int dummy = 0;
732    printf("corrupting our stack...\n");
733    *(volatile long long*)&dummy = 0;
734    return 0;
735}
736
737// --------------------------------------------------------------------
738
739extern "C" void thumb_function_1(int*p);
740extern "C" void thumb_function_2(int*p);
741extern "C" void arm_function_3(int*p);
742extern "C" void arm_function_2(int*p);
743extern "C" void arm_function_1(int*p);
744
745void arm_function_3(int*p) {
746    int a = 0;
747    thumb_function_2(&a);
748}
749
750void arm_function_2(int*p) {
751    int a = 0;
752    thumb_function_1(&a);
753}
754
755void arm_function_1(int*p) {
756    int a = 0;
757    arm_function_2(&a);
758}
759
760int crawl_test(int argc, char** argv)
761{
762    int a = 0;
763    arm_function_1(&a);
764    return 0;
765}
766
767