• 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 
99 #if 0
100 #pragma mark -
101 #pragma mark main
102 #endif
103 
main(int argc,char ** argv)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 
memcpy_test(int argc,char ** argv)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 
validate_memcpy(char * s,char * d,size_t size)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 
memset_test(int argc,char ** argv)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 
validate_memset(char * d,char c,size_t size)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 
ref_memcmp(const void * s1,const void * s2,size_t n)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 
validate_memcmp(const char * s,const char * d,size_t size)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 
memcmp_test(int argc,char ** argv)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 
strlen_test(int argc,char ** argv)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 
malloc_test(int argc,char ** argv)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 
madvise_test(int argc,char ** argv)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 
cpufreq_test(int argc,char ** argv)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 
crash_test(int argc,char ** argv)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 
stack_smasher_test(int argc,char ** argv)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 
arm_function_3(int * p)746 void arm_function_3(int*p) {
747     int a = 0;
748     thumb_function_2(&a);
749 }
750 
arm_function_2(int * p)751 void arm_function_2(int*p) {
752     int a = 0;
753     thumb_function_1(&a);
754 }
755 
arm_function_1(int * p)756 void arm_function_1(int*p) {
757     int a = 0;
758     arm_function_2(&a);
759 }
760 
crawl_test(int argc,char ** argv)761 int crawl_test(int argc, char** argv)
762 {
763     int a = 0;
764     arm_function_1(&a);
765     return 0;
766 }
767 
768