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