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