Browse Source

On unix, make algo benchmark more generic

nfactor-troky
Znort 987 13 years ago
parent
commit
6fd06387b3
  1. 102
      main.c

102
main.c

@ -480,78 +480,118 @@ static double bench_algo_stage2( @@ -480,78 +480,118 @@ static double bench_algo_stage2(
enum sha256_algos algo
)
{
#if defined(__linux)
// Make a shared+anonymous mmap
const size_t map_size = 4096;
void *map = mmap(
(void*)NULL,
map_size,
PROT_READ |
PROT_WRITE,
MAP_SHARED |
MAP_ANONYMOUS,
-1,
0
);
if ((void*)-1 == map) {
perror("bench algo, mmap failed");
// Here, the gig is to safely run a piece of code that potentially
// crashes. Unfortunately, the Right Way (tm) to do this is rather
// heavily platform dependent :(
double rate = -1.23457;
#if defined(unix)
// Make a pipe: [readFD, writeFD]
int pfd[2];
int r = pipe(pfd);
if (r<0) {
perror("pipe - failed to create pipe for --algo auto");
exit(1);
}
// Load a canary rate in the map
double rate = -1.23457;
memcpy(map, &rate, sizeof(rate));
// Make pipe non blocking
set_non_blocking(pfd[0], 1);
set_non_blocking(pfd[1], 1);
// Don't allow a crashing child to kill the main process
sighandler_t sr0 = signal(SIGPIPE, SIG_IGN);
sighandler_t sr1 = signal(SIGPIPE, SIG_IGN);
if (SIG_ERR==sr0 || SIG_ERR==sr1) {
perror("signal - failed to edit signal mask for --algo auto");
exit(1);
}
// Fork a child to do the actual benchmarking
pid_t child_pid = fork();
if (child_pid<0) {
perror("fork - failed to create a child process for --algo auto");
exit(1);
}
// Do the dangerous work in the child, knowing we might crash
if (0==child_pid) {
// Do the dangerous work in the child
// TODO: some umask trickery to prevent coredumps
// Benchmark this algorithm
double r = bench_algo_stage3(algo);
// Load result in shared map and bail
memcpy(map, &r, sizeof(r));
// We survived, send result to parent and bail
int loop_count = 0;
while (1) {
ssize_t bytes_written = write(pfd[1], &r, sizeof(r));
int try_again = (0==bytes_written || (bytes_written<0 && EAGAIN==errno));
int success = (sizeof(r)==(size_t)bytes_written);
if (success)
break;
if (!try_again) {
perror("write - child failed to write benchmark result to pipe");
exit(1);
}
if (5<loop_count) {
applog(LOG_ERR, "child tried %d times to communicate with parent, giving up", loop_count);
exit(1);
}
++loop_count;
sleep(1);
}
exit(0);
}
// Parent waits for a result from child
int nb_loops = 0;
int loop_count = 0;
while (1) {
// Wait for child to die
int status;
int r = waitpid(child_pid, &status, WNOHANG);
if (child_pid==r) {
// Child died somehow. Copy result and bail
memcpy(&rate, map, sizeof(rate));
if ((child_pid==r) || (r<0 && ECHILD==errno)) {
// Child died somehow. Grab result and bail
double tmp;
ssize_t bytes_read = read(pfd[0], &tmp, sizeof(tmp));
if (sizeof(tmp)==(size_t)bytes_read)
rate = tmp;
break;
} else if (r<0) {
perror("bench_algo: waitpid failed. giving up.");
exit(1);
}
// Give up on child after a ~60s
if (60<nb_loops) {
if (60<loop_count) {
kill(child_pid, SIGKILL);
waitpid(child_pid, &status, 0);
break;
}
// Wait a bit longer
++nb_loops;
++loop_count;
sleep(1);
}
// Clean up shared map
int r = munmap(map, map_size);
// Close pipe
r = close(pfd[0]);
if (r<0) {
perror("bench algo, munmap failed");
perror("close - failed to close read end of pipe for --algo auto");
exit(1);
}
#else
// Not on linux, just run the risk of an illegal instruction
rate = bench_algo_stage3(algo);
#endif
#endif // defined(unix)
// Done
return rate;

Loading…
Cancel
Save