Home | History | Annotate | Download | only in tests
      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 
     13 static int n_children = 3;
     14 static int n_active_children;
     15 static int n_iters = 10000;
     16 static GMainLoop *loop;
     17 
     18 static void
     19 io_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 
     33 static gboolean
     34 read_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 
     57 static gboolean
     58 write_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 
     76 static void
     77 run_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 
    100 static gboolean
    101 input_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 
    136 static void
    137 create_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 
    172 static double
    173 difftimeval (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 
    179 int
    180 main (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