18 #include <sys/param.h>
20 #include <sys/socket.h>
28 #define PATH "/tmp/s.sockperf"
46 /* We use 64bit values for the times. */
47 typedef unsigned long long int hp_timing_t
;
50 static unsigned int nclients
= 2;
51 static unsigned int nservers
= 2;
57 static complex double top_left
= -0.7 + 0.2i
;
58 static complex double bottom_right
= -0.5 - 0.0i
;
61 static int colors
[256];
62 static gdImagePtr image
;
63 static pthread_mutex_t image_lock
;
71 struct thread_param
*param
= arg
;
73 unsigned int nserv
= param
->nserv
;
75 struct pollfd servpoll
[nserv
];
76 struct sockaddr_un servaddr
;
85 unsigned int row
= cnt
/ size_x
;
86 unsigned int col
= cnt
% size_x
;
92 * (creal (bottom_right
) - creal (top_left
))) / size_x
)
93 + (_Complex_I
* (row
* (cimag (bottom_right
) - cimag (top_left
)))
102 for (cnt
= 0; cnt
< nserv
; ++cnt
)
104 servpoll
[cnt
].fd
= socket (AF_UNIX
, SOCK_STREAM
, 0);
107 puts ("cannot create socket in client");
111 memset (&servaddr
, '\0', sizeof (servaddr
));
112 servaddr
.sun_family
= AF_UNIX
;
113 strncpy (servaddr
.sun_path
, PATH
, sizeof (servaddr
.sun_path
));
114 servlen
= offsetof (struct sockaddr_un
, sun_path
) + strlen (PATH
) + 1;
120 err
= TEMP_FAILURE_RETRY (connect (servpoll
[cnt
].fd
, &servaddr
,
122 if (err
!= -1 || errno
!= ECONNREFUSED
)
130 printf ("cannot connect: %m (%d)\n", errno
);
134 servpoll
[cnt
].events
= POLLOUT
;
135 servpoll
[cnt
].revents
= 0;
146 int n
= poll (servpoll
, nserv
, -1);
149 puts ("poll returned error");
154 for (i
= 0; i
< nserv
&& n
> 0; ++i
)
155 if (servpoll
[i
].revents
!= 0)
157 if (servpoll
[i
].revents
== POLLIN
)
159 unsigned int vals
[3];
160 if (TEMP_FAILURE_RETRY (read (servpoll
[i
].fd
, &vals
,
164 puts ("read error in client");
168 pthread_mutex_lock (&image_lock
);
170 gdImageSetPixel (image
, vals
[0], vals
[1], vals
[2]);
173 pthread_mutex_unlock (&image_lock
);
175 servpoll
[i
].events
= POLLOUT
;
179 if (servpoll
[i
].revents
!= POLLOUT
)
180 printf ("revents: %hd != POLLOUT ???\n",
181 servpoll
[i
].revents
);
185 if (TEMP_FAILURE_RETRY (write (servpoll
[i
].fd
, &c
,
186 sizeof (c
))) != sizeof (c
))
188 puts ("write error in client");
192 servpoll
[i
].events
= POLLIN
;
194 z_valid
= new_coord ();
196 /* No more to do. Clear the event fields. */
197 for (i
= 0; i
< nserv
; ++i
)
198 if (servpoll
[i
].events
== POLLOUT
)
199 servpoll
[i
].events
= servpoll
[i
].revents
= 0;
202 servpoll
[i
].events
= servpoll
[i
].revents
= 0;
207 else if (servpoll
[i
].events
!= 0)
210 if (! cont
&& ! z_valid
)
216 for (cnt
= 0; cnt
< nserv
; ++cnt
)
218 TEMP_FAILURE_RETRY (write (servpoll
[cnt
].fd
, &c
, sizeof (c
)));
219 close (servpoll
[cnt
].fd
);
229 struct sockaddr_un cliaddr
;
231 int clisock
= TEMP_FAILURE_RETRY (accept (sock
, &cliaddr
, &clilen
));
235 puts ("accept failed");
243 if (TEMP_FAILURE_RETRY (read (clisock
, &c
, sizeof (c
))) != sizeof (c
))
245 printf ("server read failed: %m (%d)\n", errno
);
249 if (c
.x
== 0xffffffff && c
.y
== 0xffffffff)
252 unsigned int rnds
= 0;
253 complex double z
= c
.z
;
254 while (cabs (z
) < 4.0)
261 unsigned int vals
[3] = { c
.x
, c
.y
, rnds
};
262 if (TEMP_FAILURE_RETRY (write (clisock
, vals
, sizeof (vals
)))
265 puts ("server write error");
276 static const char *outfilename
= "test.png";
279 static const struct argp_option options
[] =
281 { "clients", 'c', "NUMBER", 0, "Number of client threads" },
282 { "servers", 's', "NUMBER", 0, "Number of server threads per client" },
283 { "timing", 'T', NULL
, 0,
284 "Measure time from startup to the last thread finishing" },
285 { NULL
, 0, NULL
, 0, NULL
}
288 /* Prototype for option handler. */
289 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
291 /* Data structure to communicate with argp functions. */
292 static struct argp argp
=
299 main (int argc
, char *argv
[])
303 struct sockaddr_un servaddr
;
307 /* Parse and process arguments. */
308 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
311 pthread_t servth
[nservers
* nclients
];
312 pthread_t clntth
[nclients
];
313 struct thread_param clntparam
[nclients
];
316 image
= gdImageCreate (size_x
, size_y
);
319 puts ("gdImageCreate failed");
323 for (cnt
= 0; cnt
< 255; ++cnt
)
324 colors
[cnt
] = gdImageColorAllocate (image
, 256 - cnt
, 256 - cnt
,
327 colors
[cnt
] = gdImageColorAllocate (image
, 0, 0, 0);
330 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
332 error (EXIT_FAILURE
, errno
, "cannot create socket");
334 memset (&servaddr
, '\0', sizeof (servaddr
));
335 servaddr
.sun_family
= AF_UNIX
;
336 strncpy (servaddr
.sun_path
, PATH
, sizeof (servaddr
.sun_path
));
337 servlen
= offsetof (struct sockaddr_un
, sun_path
) + strlen (PATH
) + 1;
339 if (bind (sock
, &servaddr
, servlen
) == -1)
340 error (EXIT_FAILURE
, errno
, "bind failed");
342 listen (sock
, SOMAXCONN
);
344 pthread_mutex_init (&image_lock
, NULL
);
348 sa
.sa_handler
= SIG_IGN
;
349 sigemptyset (&sa
.sa_mask
);
353 struct timespec start_time
;
356 if (clock_getcpuclockid (0, &cl
) != 0
357 || clock_gettime (cl
, &start_time
) != 0)
361 /* Start the servers. */
362 for (cnt
= 0; cnt
< nservers
* nclients
; ++cnt
)
364 if (pthread_create (&servth
[cnt
], NULL
, server
, NULL
) != 0)
366 puts ("pthread_create for server failed");
371 for (cnt
= 0; cnt
< nclients
; ++cnt
)
373 clntparam
[cnt
].from
= cnt
* (size_x
* size_y
) / nclients
;
374 clntparam
[cnt
].to
= MIN ((cnt
+ 1) * (size_x
* size_y
) / nclients
,
376 clntparam
[cnt
].nserv
= nservers
;
378 if (pthread_create (&clntth
[cnt
], NULL
, client
, &clntparam
[cnt
]) != 0)
380 puts ("pthread_create for client failed");
386 /* Wait for the clients. */
387 for (cnt
= 0; cnt
< nclients
; ++cnt
)
388 if (pthread_join (clntth
[cnt
], NULL
) != 0)
390 puts ("client pthread_join failed");
394 /* Wait for the servers. */
395 for (cnt
= 0; cnt
< nclients
* nservers
; ++cnt
)
396 if (pthread_join (servth
[cnt
], NULL
) != 0)
398 puts ("server pthread_join failed");
405 struct timespec end_time
;
407 if (clock_gettime (cl
, &end_time
) == 0)
409 end_time
.tv_sec
-= start_time
.tv_sec
;
410 end_time
.tv_nsec
-= start_time
.tv_nsec
;
411 if (end_time
.tv_nsec
< 0)
413 end_time
.tv_nsec
+= 1000000000;
417 printf ("\nRuntime: %lu.%09lu seconds\n%d points computed\n",
418 (unsigned long int) end_time
.tv_sec
,
419 (unsigned long int) end_time
.tv_nsec
,
425 outfile
= fopen (outfilename
, "w");
427 error (EXIT_FAILURE
, errno
, "cannot open output file '%s'", outfilename
);
429 gdImagePng (image
, outfile
);
439 /* Handle program arguments. */
441 parse_opt (int key
, char *arg
, struct argp_state
*state
)
446 nclients
= strtoul (arg
, NULL
, 0);
450 nservers
= strtoul (arg
, NULL
, 0);
458 return ARGP_ERR_UNKNOWN
;
468 /* We read the information from the /proc filesystem. It contains at
473 We search for this line and convert the number in an integer. */
474 static hp_timing_t result
;
477 /* If this function was called before, we know the result. */
481 fd
= open ("/proc/cpuinfo", O_RDONLY
);
482 if (__builtin_expect (fd
!= -1, 1))
484 /* XXX AFAIK the /proc filesystem can generate "files" only up
485 to a size of 4096 bytes. */
489 n
= read (fd
, buf
, sizeof buf
);
490 if (__builtin_expect (n
, 1) > 0)
492 char *mhz
= memmem (buf
, n
, "cpu MHz", 7);
494 if (__builtin_expect (mhz
!= NULL
, 1))
496 char *endp
= buf
+ n
;
497 int seen_decpoint
= 0;
500 /* Search for the beginning of the string. */
501 while (mhz
< endp
&& (*mhz
< '0' || *mhz
> '9') && *mhz
!= '\n')
504 while (mhz
< endp
&& *mhz
!= '\n')
506 if (*mhz
>= '0' && *mhz
<= '9')
509 result
+= *mhz
- '0';
513 else if (*mhz
== '.')
519 /* Compensate for missing digits at the end. */
520 while (ndigits
++ < 6)
533 clock_getcpuclockid (pid_t pid
, clockid_t
*clock_id
)
535 /* We don't allow any process ID but our own. */
536 if (pid
!= 0 && pid
!= getpid ())
539 #ifdef CLOCK_PROCESS_CPUTIME_ID
540 /* Store the number. */
541 *clock_id
= CLOCK_PROCESS_CPUTIME_ID
;
545 /* We don't have a timer for that. */
551 #define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var))
553 /* Get current value of CLOCK and store it in TP. */
555 clock_gettime (clockid_t clock_id
, struct timespec
*tp
)
561 case CLOCK_PROCESS_CPUTIME_ID
:
564 static hp_timing_t freq
;
567 /* Get the current counter. */
572 freq
= get_clockfreq ();
577 /* Compute the seconds. */
578 tp
->tv_sec
= tsc
/ freq
;
580 /* And the nanoseconds. This computation should be stable until
581 we get machines with about 16GHz frequency. */
582 tp
->tv_nsec
= ((tsc
% freq
) * UINT64_C (1000000000)) / freq
;