Commit 92df484d authored by ale's avatar ale

improve splay implementation

The random splay time is now constant across invocations on the same
host, making its behavior more predictable.
parent a495487a
......@@ -12,7 +12,9 @@ AC_PROG_MAKE_SET
AC_HEADER_STDC
AC_HEADER_TIME
AC_CHECK_LIBM
CFLAGS="$CFLAGS -Wall -Werror"
LIBS="$LIBS $LIBM"
AC_OUTPUT(Makefile)
......@@ -27,6 +27,7 @@
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <math.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/wait.h>
......@@ -98,9 +99,52 @@ int to_int(char *s) {
return n;
}
void splay() {
srand((unsigned int)time(NULL));
sleep(rand() % splay_time);
/* hashpjw implementation, based on glibc/intl/hash-string.c */
void hash_add(unsigned long *hvalp, const char *s) {
unsigned long hval = *hvalp, g;
unsigned const char *sptr = (unsigned const char *)s;
for (; *sptr; sptr++) {
hval <<= 4;
hval += *sptr;
g = hval & ((unsigned long)0xf << (32 - 4));
if (g != 0) {
hval ^= g >> (32 - 8);
hval ^= g;
}
}
*hvalp = hval;
}
/* Convert a floating-point time (seconds) to a struct timespec. */
void time_to_spec(float t, struct timespec *out) {
int secs = (int)floor(t);
out->tv_sec = (time_t)secs;
out->tv_nsec = (long)floor((t - (float)secs) * 1e9);
}
/* Return a time in the range [0, mod), based on the given hash value. */
float hash_time(unsigned long hval, float mod) {
/* Use the lower 16 bits to obtain a value in the [0,1) range. */
static const unsigned long maxhashbits = (1 << 16) - 1;
float f = (float)(hval & maxhashbits) / (float)maxhashbits;
return mod * f;
}
void splay(char **argv) {
/* The splay time should be different for every host / job
* combination, but it should also be only a function of those
* parameters. To achieve this and also guarantee a reasonable
* spread over the time space, we use a very simple hash of hostid +
* command line.
*/
unsigned long hval = gethostid();
struct timespec sleep_time;
for (; *argv; argv++) {
hash_add(&hval, *argv);
}
time_to_spec(hash_time(hval, splay_time), &sleep_time);
nanosleep(&sleep_time, NULL);
}
void lock_wait_expired(int signum) {
......@@ -376,7 +420,7 @@ int main(int argc, char **argv) {
}
if (splay_time > 0) {
splay();
splay(argv + optind);
}
if (syslog) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment