• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
system_time()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));
loop_overhead(size_t count)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 
preload(volatile char * addr,size_t s)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 
usage(char * p)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 
main(int argc,char ** argv)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 
memcpy_test(int argc,char ** argv)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 
validate_memcpy(char * s,char * d,size_t size)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 
memset_test(int argc,char ** argv)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 
validate_memset(char * d,char c,size_t size)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 
ref_memcmp(const void * s1,const void * s2,size_t n)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 
validate_memcmp(const char * s,const char * d,size_t size)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 
memcmp_test(int argc,char ** argv)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 
strlen_test(int argc,char ** argv)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 
malloc_test(int argc,char ** argv)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 
madvise_test(int argc,char ** argv)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 
cpufreq_test(int argc,char ** argv)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 
crash_test(int argc,char ** argv)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 
stack_smasher_test(int argc,char ** argv)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 
arm_function_3(int * p)748 void arm_function_3(int*p) {
749     int a = 0;
750     thumb_function_2(&a);
751 }
752 
arm_function_2(int * p)753 void arm_function_2(int*p) {
754     int a = 0;
755     thumb_function_1(&a);
756 }
757 
arm_function_1(int * p)758 void arm_function_1(int*p) {
759     int a = 0;
760     arm_function_2(&a);
761 }
762 
crawl_test(int argc,char ** argv)763 int crawl_test(int argc, char** argv)
764 {
765     int a = 0;
766     arm_function_1(&a);
767     return 0;
768 }
769 
770