Merge remote-tracking branch 'gvdb/master'
[platform/upstream/glib.git] / tests / timeloop-basic.c
1 #undef G_DISABLE_ASSERT
2 #undef G_LOG_DOMAIN
3
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/resource.h>
10 #include <sys/time.h>
11 #include <sys/poll.h>
12
13 #define TRUE 1
14 #define FALSE 0
15
16 static int n_children = 3;
17 static int n_active_children;
18 static int n_iters = 10000;
19
20 static int write_fds[1024];
21 static struct pollfd poll_fds[1024];
22
23 void
24 my_pipe (int *fds)
25 {
26   if (pipe(fds) < 0)
27     {
28       fprintf (stderr, "Cannot create pipe %s\n", strerror (errno));
29       exit (1);
30     }
31 }
32
33 int
34 read_all (int fd, char *buf, int len)
35 {
36   size_t bytes_read = 0;
37   ssize_t count;
38
39   while (bytes_read < len)
40     {
41       count = read (fd, buf + bytes_read, len - bytes_read);
42       if (count < 0)
43         {
44           if (errno != EAGAIN)
45             return FALSE;
46         }
47       else if (count == 0)
48         return FALSE;
49
50       bytes_read += count;
51     }
52
53   return TRUE;
54 }
55
56 int
57 write_all (int fd, char *buf, int len)
58 {
59   size_t bytes_written = 0;
60   ssize_t count;
61
62   while (bytes_written < len)
63     {
64       count = write (fd, buf + bytes_written, len - bytes_written);
65       if (count < 0)
66         {
67           if (errno != EAGAIN)
68             return FALSE;
69         }
70
71       bytes_written += count;
72     }
73
74   return TRUE;
75 }
76
77 void
78 run_child (int in_fd, int out_fd)
79 {
80   int i;
81   int val = 1;
82
83   for (i = 0; i < n_iters; i++)
84     {
85       write_all (out_fd, (char *)&val, sizeof (val));
86       read_all (in_fd, (char *)&val, sizeof (val));
87     }
88
89   val = 0;
90   write_all (out_fd, (char *)&val, sizeof (val));
91
92   exit (0);
93 }
94
95 int
96 input_callback (int source, int dest)
97 {
98   int val;
99   
100   if (!read_all (source, (char *)&val, sizeof(val)))
101     {
102       fprintf (stderr,"Unexpected EOF\n");
103       exit (1);
104     }
105
106   if (val)
107     {
108       write_all (dest, (char *)&val, sizeof(val));
109       return TRUE;
110     }
111   else
112     {
113       close (source);
114       close (dest);
115       
116       n_active_children--;
117       return FALSE;
118     }
119 }
120
121 void
122 create_child (int pos)
123 {
124   int pid;
125   int in_fds[2];
126   int out_fds[2];
127   
128   my_pipe (in_fds);
129   my_pipe (out_fds);
130
131   pid = fork ();
132
133   if (pid > 0)                  /* Parent */
134     {
135       close (in_fds[0]);
136       close (out_fds[1]);
137
138       write_fds[pos] = in_fds[1];
139       poll_fds[pos].fd = out_fds[0];
140       poll_fds[pos].events = POLLIN;
141     }
142   else if (pid == 0)            /* Child */
143     {
144       close (in_fds[1]);
145       close (out_fds[0]);
146
147       setsid ();
148
149       run_child (in_fds[0], out_fds[1]);
150     }
151   else                          /* Error */
152     {
153       fprintf (stderr,"Cannot fork: %s\n", strerror (errno));
154       exit (1);
155     }
156 }
157
158 static double 
159 difftimeval (struct timeval *old, struct timeval *new)
160 {
161   return
162     (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000;
163 }
164
165 int 
166 main (int argc, char **argv)
167 {
168   int i, j;
169   struct rusage old_usage;
170   struct rusage new_usage;
171   
172   if (argc > 1)
173     n_children = atoi(argv[1]);
174
175   if (argc > 2)
176     n_iters = atoi(argv[2]);
177
178   printf ("Children: %d     Iters: %d\n", n_children, n_iters);
179
180   n_active_children = n_children;
181   for (i = 0; i < n_children; i++)
182     create_child (i);
183
184   getrusage (RUSAGE_SELF, &old_usage);
185
186   while (n_active_children > 0)
187     {
188       int old_n_active_children = n_active_children;
189
190       poll (poll_fds, n_active_children, -1);
191
192       for (i=0; i<n_active_children; i++)
193         {
194           if (poll_fds[i].events & (POLLIN | POLLHUP))
195             {
196               if (!input_callback (poll_fds[i].fd, write_fds[i]))
197                 write_fds[i] = -1;
198             }
199         }
200
201       if (old_n_active_children > n_active_children)
202         {
203           j = 0;
204           for (i=0; i<old_n_active_children; i++)
205             {
206               if (write_fds[i] != -1)
207                 {
208                   if (j < i)
209                     {
210                       poll_fds[j] = poll_fds[i];
211                       write_fds[j] = write_fds[i];
212                     }
213                   j++;
214                 }
215             }
216         }
217     }
218
219   getrusage (RUSAGE_SELF, &new_usage);
220
221   printf ("Elapsed user: %g\n",
222            difftimeval (&old_usage.ru_utime, &new_usage.ru_utime));
223   printf ("Elapsed system: %g\n",
224            difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
225   printf ("Elapsed total: %g\n",
226           difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +         
227            difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
228   printf ("total / iteration: %g\n",
229            (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +       
230             difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) /
231            (n_iters * n_children));
232
233   return 0;
234 }
235