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
;
74 struct pollfd servpoll
[nserv
];
75 struct sockaddr_un servaddr
;
84 unsigned int row
= cnt
/ size_x
;
85 unsigned int col
= cnt
% size_x
;
91 * (creal (bottom_right
) - creal (top_left
))) / size_x
)
92 + (_Complex_I
* (row
* (cimag (bottom_right
) - cimag (top_left
)))
101 for (cnt
= 0; cnt
< nserv
; ++cnt
)
103 servpoll
[cnt
].fd
= socket (AF_UNIX
, SOCK_STREAM
, 0);
104 if (servpoll
[cnt
].fd
< 0)
106 puts ("cannot create socket in client");
110 memset (&servaddr
, '\0', sizeof (servaddr
));
111 servaddr
.sun_family
= AF_UNIX
;
112 strncpy (servaddr
.sun_path
, PATH
, sizeof (servaddr
.sun_path
));
113 servlen
= offsetof (struct sockaddr_un
, sun_path
) + strlen (PATH
) + 1;
119 err
= TEMP_FAILURE_RETRY (connect (servpoll
[cnt
].fd
, &servaddr
,
121 if (err
!= -1 || errno
!= ECONNREFUSED
)
129 printf ("cannot connect: %m (%d)\n", errno
);
133 servpoll
[cnt
].events
= POLLOUT
;
134 servpoll
[cnt
].revents
= 0;
145 int n
= poll (servpoll
, nserv
, -1);
148 puts ("poll returned error");
153 for (i
= 0; i
< nserv
&& n
> 0; ++i
)
154 if (servpoll
[i
].revents
!= 0)
156 if (servpoll
[i
].revents
== POLLIN
)
158 unsigned int vals
[3];
159 if (TEMP_FAILURE_RETRY (read (servpoll
[i
].fd
, &vals
,
163 puts ("read error in client");
167 pthread_mutex_lock (&image_lock
);
169 gdImageSetPixel (image
, vals
[0], vals
[1], vals
[2]);
172 pthread_mutex_unlock (&image_lock
);
174 servpoll
[i
].events
= POLLOUT
;
178 if (servpoll
[i
].revents
!= POLLOUT
)
179 printf ("revents: %hd != POLLOUT ???\n",
180 servpoll
[i
].revents
);
184 if (TEMP_FAILURE_RETRY (write (servpoll
[i
].fd
, &c
,
185 sizeof (c
))) != sizeof (c
))
187 puts ("write error in client");
191 servpoll
[i
].events
= POLLIN
;
193 z_valid
= new_coord ();
195 /* No more to do. Clear the event fields. */
196 for (i
= 0; i
< nserv
; ++i
)
197 if (servpoll
[i
].events
== POLLOUT
)
198 servpoll
[i
].events
= servpoll
[i
].revents
= 0;
201 servpoll
[i
].events
= servpoll
[i
].revents
= 0;
206 else if (servpoll
[i
].events
!= 0)
209 if (! cont
&& ! z_valid
)
215 for (cnt
= 0; cnt
< nserv
; ++cnt
)
217 TEMP_FAILURE_RETRY (write (servpoll
[cnt
].fd
, &c
, sizeof (c
)));
218 close (servpoll
[cnt
].fd
);
228 struct sockaddr_un cliaddr
;
230 int clisock
= TEMP_FAILURE_RETRY (accept (sock
, &cliaddr
, &clilen
));
234 puts ("accept failed");
242 if (TEMP_FAILURE_RETRY (read (clisock
, &c
, sizeof (c
))) != sizeof (c
))
244 printf ("server read failed: %m (%d)\n", errno
);
248 if (c
.x
== 0xffffffff && c
.y
== 0xffffffff)
251 unsigned int rnds
= 0;
252 complex double z
= c
.z
;
253 while (cabs (z
) < 4.0)
260 unsigned int vals
[3] = { c
.x
, c
.y
, rnds
};
261 if (TEMP_FAILURE_RETRY (write (clisock
, vals
, sizeof (vals
)))
264 puts ("server write error");
275 static const char *outfilename
= "test.png";
278 static const struct argp_option options
[] =
280 { "clients", 'c', "NUMBER", 0, "Number of client threads" },
281 { "servers", 's', "NUMBER", 0, "Number of server threads per client" },
282 { "timing", 'T', NULL
, 0,
283 "Measure time from startup to the last thread finishing" },
284 { NULL
, 0, NULL
, 0, NULL
}
287 /* Prototype for option handler. */
288 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
290 /* Data structure to communicate with argp functions. */
291 static struct argp argp
=
298 main (int argc
, char *argv
[])
302 struct sockaddr_un servaddr
;
306 /* Parse and process arguments. */
307 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
310 pthread_t servth
[nservers
* nclients
];
311 pthread_t clntth
[nclients
];
312 struct thread_param clntparam
[nclients
];
315 image
= gdImageCreate (size_x
, size_y
);
318 puts ("gdImageCreate failed");
322 for (cnt
= 0; cnt
< 255; ++cnt
)
323 colors
[cnt
] = gdImageColorAllocate (image
, 256 - cnt
, 256 - cnt
,
326 colors
[cnt
] = gdImageColorAllocate (image
, 0, 0, 0);
329 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
331 error (EXIT_FAILURE
, errno
, "cannot create socket");
333 memset (&servaddr
, '\0', sizeof (servaddr
));
334 servaddr
.sun_family
= AF_UNIX
;
335 strncpy (servaddr
.sun_path
, PATH
, sizeof (servaddr
.sun_path
));
336 servlen
= offsetof (struct sockaddr_un
, sun_path
) + strlen (PATH
) + 1;
338 if (bind (sock
, &servaddr
, servlen
) == -1)
339 error (EXIT_FAILURE
, errno
, "bind failed");
341 listen (sock
, SOMAXCONN
);
343 pthread_mutex_init (&image_lock
, NULL
);
347 sa
.sa_handler
= SIG_IGN
;
348 sigemptyset (&sa
.sa_mask
);
352 struct timespec start_time
;
355 if (clock_getcpuclockid (0, &cl
) != 0
356 || clock_gettime (cl
, &start_time
) != 0)
360 /* Start the servers. */
361 for (cnt
= 0; cnt
< nservers
* nclients
; ++cnt
)
363 if (pthread_create (&servth
[cnt
], NULL
, server
, NULL
) != 0)
365 puts ("pthread_create for server failed");
370 for (cnt
= 0; cnt
< nclients
; ++cnt
)
372 clntparam
[cnt
].from
= cnt
* (size_x
* size_y
) / nclients
;
373 clntparam
[cnt
].to
= MIN ((cnt
+ 1) * (size_x
* size_y
) / nclients
,
375 clntparam
[cnt
].nserv
= nservers
;
377 if (pthread_create (&clntth
[cnt
], NULL
, client
, &clntparam
[cnt
]) != 0)
379 puts ("pthread_create for client failed");
385 /* Wait for the clients. */
386 for (cnt
= 0; cnt
< nclients
; ++cnt
)
387 if (pthread_join (clntth
[cnt
], NULL
) != 0)
389 puts ("client pthread_join failed");
393 /* Wait for the servers. */
394 for (cnt
= 0; cnt
< nclients
* nservers
; ++cnt
)
395 if (pthread_join (servth
[cnt
], NULL
) != 0)
397 puts ("server pthread_join failed");
404 struct timespec end_time
;
406 if (clock_gettime (cl
, &end_time
) == 0)
408 end_time
.tv_sec
-= start_time
.tv_sec
;
409 end_time
.tv_nsec
-= start_time
.tv_nsec
;
410 if (end_time
.tv_nsec
< 0)
412 end_time
.tv_nsec
+= 1000000000;
416 printf ("\nRuntime: %lu.%09lu seconds\n%d points computed\n",
417 (unsigned long int) end_time
.tv_sec
,
418 (unsigned long int) end_time
.tv_nsec
,
424 outfile
= fopen (outfilename
, "w");
426 error (EXIT_FAILURE
, errno
, "cannot open output file '%s'", outfilename
);
428 gdImagePng (image
, outfile
);
438 /* Handle program arguments. */
440 parse_opt (int key
, char *arg
, struct argp_state
*state
)
445 nclients
= strtoul (arg
, NULL
, 0);
449 nservers
= strtoul (arg
, NULL
, 0);
457 return ARGP_ERR_UNKNOWN
;
467 /* We read the information from the /proc filesystem. It contains at
472 We search for this line and convert the number in an integer. */
473 static hp_timing_t result
;
476 /* If this function was called before, we know the result. */
480 fd
= open ("/proc/cpuinfo", O_RDONLY
);
481 if (__glibc_likely (fd
!= -1))
483 /* XXX AFAIK the /proc filesystem can generate "files" only up
484 to a size of 4096 bytes. */
488 n
= read (fd
, buf
, sizeof buf
);
489 if (__builtin_expect (n
, 1) > 0)
491 char *mhz
= memmem (buf
, n
, "cpu MHz", 7);
493 if (__glibc_likely (mhz
!= NULL
))
495 char *endp
= buf
+ n
;
496 int seen_decpoint
= 0;
499 /* Search for the beginning of the string. */
500 while (mhz
< endp
&& (*mhz
< '0' || *mhz
> '9') && *mhz
!= '\n')
503 while (mhz
< endp
&& *mhz
!= '\n')
505 if (*mhz
>= '0' && *mhz
<= '9')
508 result
+= *mhz
- '0';
512 else if (*mhz
== '.')
518 /* Compensate for missing digits at the end. */
519 while (ndigits
++ < 6)
532 clock_getcpuclockid (pid_t pid
, clockid_t
*clock_id
)
534 /* We don't allow any process ID but our own. */
535 if (pid
!= 0 && pid
!= getpid ())
538 #ifdef CLOCK_PROCESS_CPUTIME_ID
539 /* Store the number. */
540 *clock_id
= CLOCK_PROCESS_CPUTIME_ID
;
544 /* We don't have a timer for that. */
550 #define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var))
552 /* Get current value of CLOCK and store it in TP. */
554 clock_gettime (clockid_t clock_id
, struct timespec
*tp
)
560 case CLOCK_PROCESS_CPUTIME_ID
:
563 static hp_timing_t freq
;
566 /* Get the current counter. */
571 freq
= get_clockfreq ();
576 /* Compute the seconds. */
577 tp
->tv_sec
= tsc
/ freq
;
579 /* And the nanoseconds. This computation should be stable until
580 we get machines with about 16GHz frequency. */
581 tp
->tv_nsec
= ((tsc
% freq
) * UINT64_C (1000000000)) / freq
;