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