1/*
2** Copyright 2010 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/*
18 * Some quick and dirty micro-benchmarks
19 */
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <errno.h>
24#include <sys/uio.h>
25#include <unistd.h>
26#include <sys/time.h>
27#include <stdint.h>
28#include <string.h>
29
30/* tv2 -= tv1 */
31static void tv_sub(struct timeval *tv2, struct timeval *tv1) {
32        tv2->tv_sec -= tv1->tv_sec;
33        tv2->tv_usec -= tv1->tv_usec;
34        while (tv2->tv_usec < 0) {
35            tv2->tv_usec += 1000000;
36            tv2->tv_sec -= 1;
37        }
38}
39
40static int do_sleep(int iters, int delay) {
41    struct timeval tv1;
42    struct timeval tv2;
43    int i;
44
45    for (i = 0; iters == -1 || i < iters; i++) {
46        gettimeofday(&tv1, NULL);
47        sleep(delay);
48        gettimeofday(&tv2, NULL);
49
50        tv_sub(&tv2, &tv1);
51
52        printf("sleep(%d) took %ld.%06ld seconds\n", delay, tv2.tv_sec, tv2.tv_usec);
53    }
54
55    return 0;
56}
57
58int cpu_foo;
59
60static int do_cpu(int iters, int a) {
61    struct timeval tv1;
62    struct timeval tv2;
63    int i;
64
65    for (i = 0; iters == -1 || i < iters; i++) {
66        gettimeofday(&tv1, NULL);
67        for (cpu_foo = 0; cpu_foo < 100000000; cpu_foo++);
68        gettimeofday(&tv2, NULL);
69
70        tv_sub(&tv2, &tv1);
71
72        printf("cpu took %ld.%06ld seconds\n", tv2.tv_sec, tv2.tv_usec);
73    }
74    return 0;
75}
76
77static double mb_sec(unsigned long bytes, struct timeval *delta) {
78    unsigned long us = delta->tv_sec * 1000000 + delta->tv_usec;
79    return (double)bytes * 1000000.0 / 1048576.0 / (double)us;
80}
81
82static int do_memset(int iters, int sz) {
83    struct timeval tv1;
84    struct timeval tv2;
85    int i, j;
86
87    uint8_t *b = malloc(sz);
88    if (!b) return -1;
89    int c = 1000000000/sz;
90
91    for (i = 0; iters == -1 || i < iters; i++) {
92        gettimeofday(&tv1, NULL);
93        for (j = 0; j < c; j++)
94            memset(b, 0, sz);
95
96        gettimeofday(&tv2, NULL);
97
98        tv_sub(&tv2, &tv1);
99
100        printf("memset %dx%d bytes took %ld.%06ld seconds (%f MB/s)\n",
101                c, sz, tv2.tv_sec, tv2.tv_usec, mb_sec(c*sz, &tv2));
102    }
103    return 0;
104}
105
106static int do_memcpy(int iters, int sz) {
107    struct timeval tv1;
108    struct timeval tv2;
109    int i, j;
110
111    uint8_t *a = malloc(sz);
112    if (!a) return -1;
113    uint8_t *b = malloc(sz);
114    if (!b) return -1;
115    int c = 1000000000/sz;
116
117    for (i = 0; iters == -1 || i < iters; i++) {
118        gettimeofday(&tv1, NULL);
119        for (j = 0; j < c; j++)
120            memcpy(b, a, sz);
121
122        gettimeofday(&tv2, NULL);
123
124        tv_sub(&tv2, &tv1);
125
126        printf("memcpy %dx%d bytes took %ld.%06ld seconds (%f MB/s)\n",
127                c, sz, tv2.tv_sec, tv2.tv_usec, mb_sec(c*sz, &tv2));
128    }
129    return 0;
130}
131
132int foo;
133
134static int do_memread(int iters, int sz) {
135    struct timeval tv1;
136    struct timeval tv2;
137    int i, j, k;
138
139    int *b = malloc(sz);
140    if (!b) return -1;
141    int c = 1000000000/sz;
142
143    for (i = 0; iters == -1 || i < iters; i++) {
144        gettimeofday(&tv1, NULL);
145        for (j = 0; j < c; j++)
146            for (k = 0; k < sz/4; k++)
147                foo = b[k];
148
149        gettimeofday(&tv2, NULL);
150
151        tv_sub(&tv2, &tv1);
152
153        printf("read %dx%d bytes took %ld.%06ld seconds (%f MB/s)\n",
154                c, sz, tv2.tv_sec, tv2.tv_usec, mb_sec(c*sz, &tv2));
155    }
156    return 0;
157}
158
159struct {
160    char *name;
161    int (*ptr)(int, int);
162} function_table[]  = {
163    {"sleep", do_sleep},
164    {"cpu", do_cpu},
165    {"memset", do_memset},
166    {"memcpy", do_memcpy},
167    {"memread", do_memread},
168    {NULL, NULL},
169};
170
171static void usage() {
172    int i;
173
174    printf("Usage:\n");
175    for (i = 0; function_table[i].name; i++) {
176        printf("\tmicro_bench %s ARG [ITERS]\n", function_table[i].name);
177    }
178}
179
180int main(int argc, char **argv) {
181    int i;
182    int iters;
183
184    if (argc < 3 || argc > 4) {
185        usage();
186        return -1;
187    }
188    if (argc == 3) {
189        iters = -1;
190    } else {
191        iters = atoi(argv[3]);
192    }
193    for (i = 0; function_table[i].name; i++) {
194        if (!strcmp(argv[1], function_table[i].name)) {
195            printf("%s\n", function_table[i].name);
196            return (*function_table[i].ptr)(iters, atoi(argv[2]));
197        }
198    }
199    usage();
200    return -1;
201}
202