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(
enum sha256_algos algo enum sha256_algos algo
) )
{ {
#if defined(__linux) // Here, the gig is to safely run a piece of code that potentially
// Make a shared+anonymous mmap // crashes. Unfortunately, the Right Way (tm) to do this is rather
const size_t map_size = 4096; // heavily platform dependent :(
void *map = mmap(
(void*)NULL, double rate = -1.23457;
map_size,
PROT_READ | #if defined(unix)
PROT_WRITE,
MAP_SHARED | // Make a pipe: [readFD, writeFD]
MAP_ANONYMOUS, int pfd[2];
-1, int r = pipe(pfd);
0 if (r<0) {
); perror("pipe - failed to create pipe for --algo auto");
if ((void*)-1 == map) {
perror("bench algo, mmap failed");
exit(1); exit(1);
} }
// Load a canary rate in the map // Make pipe non blocking
double rate = -1.23457; set_non_blocking(pfd[0], 1);
memcpy(map, &rate, sizeof(rate)); 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 // Fork a child to do the actual benchmarking
pid_t child_pid = fork(); 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) { 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); double r = bench_algo_stage3(algo);
// Load result in shared map and bail // We survived, send result to parent and bail
memcpy(map, &r, sizeof(r)); 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); exit(0);
} }
// Parent waits for a result from child // Parent waits for a result from child
int nb_loops = 0; int loop_count = 0;
while (1) { while (1) {
// Wait for child to die // Wait for child to die
int status; int status;
int r = waitpid(child_pid, &status, WNOHANG); int r = waitpid(child_pid, &status, WNOHANG);
if (child_pid==r) { if ((child_pid==r) || (r<0 && ECHILD==errno)) {
// Child died somehow. Copy result and bail
memcpy(&rate, map, sizeof(rate)); // 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; break;
} else if (r<0) { } else if (r<0) {
perror("bench_algo: waitpid failed. giving up."); perror("bench_algo: waitpid failed. giving up.");
exit(1); exit(1);
} }
// Give up on child after a ~60s // Give up on child after a ~60s
if (60<nb_loops) { if (60<loop_count) {
kill(child_pid, SIGKILL); kill(child_pid, SIGKILL);
waitpid(child_pid, &status, 0); waitpid(child_pid, &status, 0);
break; break;
} }
// Wait a bit longer // Wait a bit longer
++nb_loops; ++loop_count;
sleep(1); sleep(1);
} }
// Clean up shared map // Close pipe
int r = munmap(map, map_size); r = close(pfd[0]);
if (r<0) { if (r<0) {
perror("bench algo, munmap failed"); perror("close - failed to close read end of pipe for --algo auto");
exit(1); exit(1);
} }
#else #else
// Not on linux, just run the risk of an illegal instruction // Not on linux, just run the risk of an illegal instruction
rate = bench_algo_stage3(algo); rate = bench_algo_stage3(algo);
#endif
#endif // defined(unix)
// Done // Done
return rate; return rate;

Loading…
Cancel
Save