added latency tool
[tridge/junkcode.git] / aio_open.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sched.h>
4 #include <unistd.h>
5 #include <time.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <sys/wait.h>
11 #include <sys/socket.h>
12 #include <sys/time.h>
13
14 static struct timeval tp1,tp2;
15
16 static void start_timer()
17 {
18         gettimeofday(&tp1,NULL);
19 }
20
21 static double end_timer()
22 {
23         gettimeofday(&tp2,NULL);
24         return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
25                 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
26 }
27
28 struct aio_open_args {
29         const char *fname;
30         int flags;
31         mode_t mode;
32         int error;
33         int ret;
34 };
35
36 static int aio_pipe[2];
37
38 static int aio_open_child(void *ptr)
39 {
40         struct aio_open_args *args = ptr;
41         args->ret = open(args->fname, args->flags, args->mode);
42         args->error = errno;
43         write(aio_pipe[1], &ptr, sizeof(ptr));
44         return 0;
45 }
46
47 static int aio_open(const char *fname, int flags, mode_t mode)
48 {
49         char stack[512];
50         struct aio_open_args *args, *a2;
51         pid_t pid;
52         int ret, status;
53
54         args = malloc(sizeof(*args));
55         args->fname = fname;
56         args->flags = flags;
57         args->mode  = mode;
58
59         pid = clone(aio_open_child, stack+sizeof(stack)-32, 
60                     CLONE_FS|CLONE_FILES|CLONE_VM, 
61                     args);
62         
63         if (read(aio_pipe[0], &a2, sizeof(a2)) != sizeof(a2)) {
64                 errno = EIO;
65                 return -1;
66         }
67
68         waitpid(pid, &status, __WCLONE);
69
70         ret = args->ret;
71         if (ret == -1) {
72                 errno = args->error;
73         }
74         free(args);
75
76         return ret;
77 }
78
79 enum aio_clone_op {AIO_CLONE_NOOP, AIO_CLONE_OPEN};
80
81 struct aio_clone_common {
82         char stack[2048];
83         enum aio_clone_op op;
84         int fd1[2];
85         int fd2[2];
86         int error;
87         int ret;
88         pid_t pid;
89 };
90
91 union aio_clone {
92         struct {
93                 struct aio_clone_common common;
94         } _noop;
95         struct {
96                 struct aio_clone_common common;
97                 const char *fname;
98                 int flags;
99                 mode_t mode;
100         } _open;
101 };
102
103 static int aio_clone_wake(union aio_clone *args)
104 {
105         if (write(args->_open.common.fd1[1], &args, sizeof(args)) != sizeof(args)) {
106                 return -1;
107         }
108         return 0;
109 }
110
111 static int aio_clone_finished(union aio_clone *args)
112 {
113         if (write(args->_open.common.fd2[1], &args, sizeof(args)) != sizeof(args)) {
114                 return -1;
115         }
116         return 0;
117 }
118
119 static int aio_clone_wait_child(union aio_clone *args)
120 {
121         if (read(args->_open.common.fd1[0], &args, sizeof(args)) != sizeof(args)) {
122                 return -1;
123         }
124         return 0;
125 }
126
127 static int aio_clone_wait_parent(union aio_clone *args)
128 {
129         if (read(args->_open.common.fd2[0], &args, sizeof(args)) != sizeof(args)) {
130                 return -1;
131         }
132         return 0;
133 }
134
135 static int aio_clone_child(void *ptr)
136 {
137         union aio_clone *args = ptr;
138         while (aio_clone_wait_child(args) == 0) {
139                 struct aio_clone_common *common = &args->_noop.common;
140                 switch (common->op) {
141                 case AIO_CLONE_NOOP:
142                         common->ret = 0;
143                         break;
144                 case AIO_CLONE_OPEN:
145                         common->ret = open(args->_open.fname, 
146                                            args->_open.flags, 
147                                            args->_open.mode);
148                         break;
149                 }
150                 if (common->ret == -1) {
151                         common->error = errno;
152                 }
153                 if (aio_clone_finished(args) != 0) break;
154         }
155         return -1;
156 }
157
158 static union aio_clone *aio_clone_start(void)
159 {
160         union aio_clone *args = calloc(1, sizeof(*args));
161         pipe(args->_noop.common.fd1);
162         pipe(args->_noop.common.fd2);
163         args->_noop.common.pid = 
164                 clone(aio_clone_child, args->_noop.common.stack+
165                       sizeof(args->_noop.common.stack)-32, 
166                       CLONE_FS|CLONE_FILES|CLONE_VM, 
167                       (void*)args);
168         sleep(1);
169         return args;
170 }
171
172
173 static int aio_open2(const char *fname, int flags, mode_t mode)
174 {
175         static union aio_clone *args;
176         int ret;
177
178         if (args == NULL) {
179                 args = aio_clone_start();
180         }
181
182         args->_open.common.op    = AIO_CLONE_OPEN;
183         args->_open.fname = fname;
184         args->_open.flags = flags;
185         args->_open.mode  = mode;
186
187         if (aio_clone_wake(args) != 0) {
188                 errno = EIO;
189                 return -1;
190         }
191
192         if (aio_clone_wait_parent(args) != 0) {
193                 errno = EIO;
194                 return -1;
195         }
196
197         ret = args->_open.common.ret;
198         if (ret == -1) {
199                 errno = args->_open.common.error;
200         }
201
202         return ret;
203 }
204
205
206 static int aio_noop(const char *fname, int flags, mode_t mode)
207 {
208         static union aio_clone *args;
209         int ret;
210
211         if (args == NULL) {
212                 args = aio_clone_start();
213         }
214
215         args->_noop.common.op = AIO_CLONE_NOOP;
216
217         if (aio_clone_wake(args) != 0) {
218                 errno = EIO;
219                 return -1;
220         }
221         
222         if (aio_clone_wait_parent(args) != 0) {
223                 errno = EIO;
224                 return -1;
225         }
226
227         ret = args->_open.common.ret;
228         if (ret == -1) {
229                 errno = args->_open.common.error;
230         }
231
232         return ret;
233 }
234
235
236 static void run_test(const char *name, int (*fn)(const char *, int, mode_t))
237 {
238         const char *fname = "test.dat";
239         const int timeout=3;
240         int count=0;
241
242         pipe(aio_pipe);
243
244         start_timer();
245         while (end_timer() < timeout) {
246                 int fd = fn(fname, O_CREAT|O_TRUNC|O_RDWR, 0600);
247                 if (fd == -1) {
248                         perror(fname);
249                         exit(1);
250                 }
251                 if (fd != 0) close(fd);
252 //              unlink(fname);
253                 count++;
254         }
255         printf("%.1f usec/op (%s)\n", 1.0e6*end_timer()/count, name);
256
257         close(aio_pipe[0]);
258         close(aio_pipe[1]);
259 }
260
261 int main(void)
262 {
263         run_test("aio_open2", aio_open2);
264
265         run_test("noop", aio_noop);
266
267         run_test("aio_open", aio_open);
268         run_test("open", open);
269         run_test("aio_open2", aio_open2);
270
271         run_test("aio_open", aio_open);
272         run_test("open", open);
273         run_test("aio_open2", aio_open2);
274
275         return 0;
276 }