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