Major change in API for creating sources to handle multiple main loops
[platform/upstream/glib.git] / timeloop.c
1 #include <errno.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <sys/resource.h>
6 #include <sys/time.h>
7
8 #include <glib.h>
9
10 static int n_children = 3;
11 static int n_active_children;
12 static int n_iters = 10000;
13 static GMainLoop *loop;
14
15 void
16 io_pipe (GIOChannel **channels)
17 {
18   int fds[2];
19
20   if (pipe(fds) < 0)
21     {
22       fprintf (stderr, "Cannot create pipe %s\n", g_strerror (errno));
23       exit (1);
24     }
25
26   channels[0] = g_io_channel_unix_new (fds[0]);
27   channels[1] = g_io_channel_unix_new (fds[1]);
28 }
29
30 gboolean
31 read_all (GIOChannel *channel, char *buf, int len)
32 {
33   int bytes_read = 0;
34   int count;
35   GIOError err;
36
37   while (bytes_read < len)
38     {
39       err = g_io_channel_read (channel, buf + bytes_read, len - bytes_read, &count);
40       if (err)
41         {
42           if (err != G_IO_ERROR_AGAIN)
43             return FALSE;
44         }
45       else if (count == 0)
46         return FALSE;
47
48       bytes_read += count;
49     }
50
51   return TRUE;
52 }
53
54 gboolean
55 write_all (GIOChannel *channel, char *buf, int len)
56 {
57   int bytes_written = 0;
58   int count;
59   GIOError err;
60
61   while (bytes_written < len)
62     {
63       err = g_io_channel_write (channel, buf + bytes_written, len - bytes_written, &count);
64       if (err && err != G_IO_ERROR_AGAIN)
65         return FALSE;
66
67       bytes_written += count;
68     }
69
70   return TRUE;
71 }
72
73 void
74 run_child (GIOChannel *in_channel, GIOChannel *out_channel)
75 {
76   int i;
77   int val = 1;
78   GTimer *timer = g_timer_new();
79
80   for (i = 0; i < n_iters; i++)
81     {
82       write_all (out_channel, (char *)&val, sizeof (val));
83       read_all (in_channel, (char *)&val, sizeof (val));
84     }
85
86   val = 0;
87   write_all (out_channel, (char *)&val, sizeof (val));
88
89   val = g_timer_elapsed (timer, NULL) * 1000;
90   
91   write_all (out_channel, (char *)&val, sizeof (val));
92   g_timer_destroy (timer);
93
94   exit (0);
95 }
96
97 gboolean
98 input_callback (GIOChannel   *source,
99                 GIOCondition  condition,
100                 gpointer      data)
101 {
102   int val;
103   GIOChannel *dest = (GIOChannel *)data;
104   
105   if (!read_all (source, (char *)&val, sizeof(val)))
106     {
107       fprintf (stderr, "Unexpected EOF\n");
108       exit (1);
109     }
110
111   if (val)
112     {
113       write_all (dest, (char *)&val, sizeof(val));
114       
115       return TRUE;
116     }
117   else
118     {
119       g_io_channel_close (source);
120       g_io_channel_close (dest);
121       
122       g_io_channel_unref (source);
123       g_io_channel_unref (dest);
124
125       n_active_children--;
126       if (n_active_children == 0)
127         g_main_quit (loop);
128       
129       return FALSE;
130     }
131 }
132
133 void
134 create_child ()
135 {
136   int pid;
137   GIOChannel *in_channels[2];
138   GIOChannel *out_channels[2];
139   
140   io_pipe (in_channels);
141   io_pipe (out_channels);
142
143   pid = fork ();
144
145   if (pid > 0)                  /* Parent */
146     {
147       g_io_channel_close (in_channels[0]);
148       g_io_channel_close (out_channels[1]);
149
150       g_io_add_watch (out_channels[0], G_IO_IN | G_IO_HUP,
151                       input_callback, in_channels[1]);
152     }
153   else if (pid == 0)            /* Child */
154     {
155       g_io_channel_close (in_channels[1]);
156       g_io_channel_close (out_channels[0]);
157
158       setsid ();
159
160       run_child (in_channels[0], out_channels[1]);
161     }
162   else                          /* Error */
163     {
164       fprintf (stderr, "Cannot fork: %s\n", g_strerror (errno));
165       exit (1);
166     }
167 }
168
169 static double 
170 difftimeval (struct timeval *old, struct timeval *new)
171 {
172   return
173     (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000;
174 }
175
176 int 
177 main (int argc, char **argv)
178 {
179   int i;
180   struct rusage old_usage;
181   struct rusage new_usage;
182   
183   if (argc > 1)
184     n_children = atoi(argv[1]);
185
186   if (argc > 2)
187     n_iters = atoi(argv[2]);
188
189   printf ("Children: %d     Iters: %d\n", n_children, n_iters);
190
191   n_active_children = n_children;
192   for (i = 0; i < n_children; i++)
193     create_child ();
194
195   getrusage (RUSAGE_SELF, &old_usage);
196   loop = g_main_new (FALSE);
197   g_main_run (loop);
198   getrusage (RUSAGE_SELF, &new_usage);
199
200   printf ("Elapsed user: %g\n",
201           difftimeval (&old_usage.ru_utime, &new_usage.ru_utime));
202   printf ("Elapsed system: %g\n",
203           difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
204   printf ("Elapsed total: %g\n",
205           difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +         
206           difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
207   printf ("total / iteration: %g\n",
208           (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +        
209            difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) /
210           (n_iters * n_children));
211
212   return 0;
213 }