]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/tools/tools/syscall_timing/syscall_timing.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / 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(int num)
114 {
115         int i, so;
116
117         /*
118          * Sockets are also expensive, but unlike pipes, currently
119          * require Giant.
120          */
121         for (i = 0; i < num; i++) {
122                 so = socket(PF_LOCAL, SOCK_STREAM, 0);
123                 if (so == -1) {
124                         perror("socket");
125                         exit(-1);
126                 }
127                 close(so);
128         }
129 }
130
131 static void
132 usage(void)
133 {
134
135         fprintf(stderr, "syscall_timing [iterations] [test]\n");
136         fprintf(stderr, "supported tests: getuid getppid clock_gettime "
137             "pipe socket\n");
138         exit(-1);
139 }
140
141 int
142 main(int argc, char *argv[])
143 {
144         struct timespec ts_start, ts_end, ts_res;
145         int count;
146
147         if (argc != 3)
148                 usage();
149         count = atoi(argv[1]);
150
151         assert(clock_getres(CLOCK_REALTIME, &ts_res) == 0);
152         printf("Clock resolution: %d.%09lu\n", ts_res.tv_sec, ts_res.tv_nsec);
153
154         if (strcmp(argv[2], "getuid") == 0) {
155                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
156                 test_getuid(count);
157                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
158         } else if (strcmp(argv[2], "getppid") == 0) {
159                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
160                 test_getppid(count);
161                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
162         } else if (strcmp(argv[2], "clock_gettime") == 0) {
163                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
164                 test_clock_gettime(count);
165                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
166         } else if (strcmp(argv[2], "pipe") == 0) {
167                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
168                 test_pipe(count);
169                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
170         } else if (strcmp(argv[2], "socket") == 0) {
171                 assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
172                 test_socket(count);
173                 assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
174          } else
175                 usage();
176
177         timespecsub(&ts_end, &ts_start);
178
179         printf("test: %s\n", argv[2]);
180
181         printf("%d.%09lu for %d iterations\n", ts_end.tv_sec,
182             ts_end.tv_nsec, count);
183
184         /*
185          * Note.  This assumes that each iteration takes less than
186          * a second, and that our total nanoseconds doesn't exceed
187          * the room in our arithmetic unit.  Fine for system calls,
188          * but not for long things.
189          */
190         ts_end.tv_sec *= 1000000000 / count;
191         printf("0.%09lu per/iteration\n", 
192             ts_end.tv_sec + ts_end.tv_nsec / count);
193         return (0);
194 }