]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - tools/tools/syscall_timing/syscall_timing.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / tools / tools / syscall_timing / syscall_timing.c
1 /*-
2  * Copyright (c) 2003-2004 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/time.h>
32
33 #include <assert.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #define timespecsub(vvp, uvp)                                           \
40         do {                                                            \
41                 (vvp)->tv_sec -= (uvp)->tv_sec;                         \
42                 (vvp)->tv_nsec -= (uvp)->tv_nsec;                       \
43                 if ((vvp)->tv_nsec < 0) {                               \
44                         (vvp)->tv_sec--;                                \
45                         (vvp)->tv_nsec += 1000000000;                   \
46                 }                                                       \
47         } while (0)
48
49 inline void
50 test_getuid(int num)
51 {
52         int i;
53
54         /*
55          * Thread-local data should require no locking if system
56          * call is MPSAFE.
57          */
58         for (i = 0; i < num; i++)
59                 getuid();
60 }
61
62 inline void
63 test_getppid(int num)
64 {
65         int i;
66
67         /*
68          * This is process-local, but can change, so will require a
69          * lock.
70          */
71         for (i = 0; i < num; i++)
72                 getppid();
73 }
74
75 inline void
76 test_clock_gettime(int num)
77 {
78         struct timespec ts;
79         int i;
80
81         for (i = 0; i < num; i++) {
82                 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
83                         perror("clock_gettime");
84                         exit(-1);
85                 }
86         }
87 }
88
89 inline void
90 test_pipe(int num)
91 {
92         int i;
93
94         /*
95          * pipe creation is expensive, as it will allocate a new file
96          * descriptor, allocate a new pipe, hook it all up, and return.
97          * Destroying is also expensive, as we now have to free up
98          * the file descriptors and return the pipe.
99          */
100         for (i = 0; i < num; i++) {
101                 int fd[2];
102                 if (pipe(fd) == -1) {
103                         perror("pipe");
104                         exit(-1);
105                 }
106
107                 close(fd[0]);
108                 close(fd[1]);
109         }
110 }
111
112 inline void
113 test_socket_stream(int num)
114 {
115         int i, so;
116
117         for (i = 0; i < num; i++) {
118                 so = socket(PF_LOCAL, SOCK_STREAM, 0);
119                 if (so == -1) {
120                         perror("socket_stream");
121                         exit(-1);
122                 }
123                 close(so);
124         }
125 }
126
127 inline void
128 test_socket_dgram(int num)
129 {
130         int i, so;
131
132         for (i = 0; i < num; i++) {
133                 so = socket(PF_LOCAL, SOCK_DGRAM, 0);
134                 if (so == -1) {
135                         perror("socket_dgram");
136                         exit(-1);
137                 }
138                 close(so);
139         }
140 }
141
142 inline void
143 test_socketpair_stream(int num)
144 {
145         int i, so[2];
146
147         for (i = 0; i < num; i++) {
148                 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1) {
149                         perror("socketpair_stream");
150                         exit(-1);
151                 }
152                 close(so[0]);
153                 close(so[1]);
154         }
155 }
156
157 inline void
158 test_socketpair_dgram(int num)
159 {
160         int i, so[2];
161
162         for (i = 0; i < num; i++) {
163                 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1) {
164                         perror("socketpair_dgram");
165                         exit(-1);
166                 }
167                 close(so[0]);
168                 close(so[1]);
169         }
170 }
171
172 static void
173 usage(void)
174 {
175
176         fprintf(stderr, "syscall_timing [iterations] [test]\n");
177         fprintf(stderr,
178             "supported tests: getuid getppid clock_gettime pipe\n"
179             "socket_stream socket_dgram socketpair_stream\n"
180             "socketpair_dgram\n");
181         exit(-1);
182 }
183
184 int
185 main(int argc, char *argv[])
186 {
187         struct timespec ts_start, ts_end, ts_res;
188         int count;
189
190         if (argc != 3)
191                 usage();
192         count = atoi(argv[1]);
193
194         assert(clock_getres(CLOCK_REALTIME, &ts_res) == 0);
195         printf("Clock resolution: %d.%09lu\n", ts_res.tv_sec, ts_res.tv_nsec);
196
197         if (strcmp(argv[2], "getuid") == 0) {
198                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
199                 test_getuid(count);
200                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
201         } else if (strcmp(argv[2], "getppid") == 0) {
202                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
203                 test_getppid(count);
204                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
205         } else if (strcmp(argv[2], "clock_gettime") == 0) {
206                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
207                 test_clock_gettime(count);
208                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
209         } else if (strcmp(argv[2], "pipe") == 0) {
210                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
211                 test_pipe(count);
212                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
213         } else if (strcmp(argv[2], "socket_stream") == 0) {
214                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
215                 test_socket_stream(count);
216                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
217         } else if (strcmp(argv[2], "socket_dgram") == 0) {
218                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
219                 test_socket_dgram(count);
220                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
221         } else if (strcmp(argv[2], "socketpair_stream") == 0) {
222                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
223                 test_socketpair_stream(count);
224                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
225         } else if (strcmp(argv[2], "socketpair_dgram") == 0) {
226                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
227                 test_socketpair_dgram(count);
228                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
229          } else
230                 usage();
231
232         timespecsub(&ts_end, &ts_start);
233
234         printf("test: %s\n", argv[2]);
235
236         printf("%d.%09lu for %d iterations\n", ts_end.tv_sec,
237             ts_end.tv_nsec, count);
238
239         /*
240          * Note.  This assumes that each iteration takes less than
241          * a second, and that our total nanoseconds doesn't exceed
242          * the room in our arithmetic unit.  Fine for system calls,
243          * but not for long things.
244          */
245         ts_end.tv_sec *= 1000000000 / count;
246         printf("0.%09lu per/iteration\n", 
247             ts_end.tv_sec + ts_end.tv_nsec / count);
248         return (0);
249 }