diff options
author | Andy Lutomirski <luto@kernel.org> | 2015-12-29 19:59:51 -0800 |
---|---|---|
committer | Andy Lutomirski <luto@kernel.org> | 2015-12-29 19:59:51 -0800 |
commit | 3042f3f08ad781437cdb97b91435aabbf0ab3a68 (patch) | |
tree | daea06910fb1a7506ca61ff4e6ba0ed91c612dfb | |
parent | 1cc2ec6849376c3d47378f43b5be0427e6aedcfc (diff) | |
download | misc-tests-3042f3f08ad781437cdb97b91435aabbf0ab3a68.tar.gz |
Improve dump-vvar
-rw-r--r-- | dump-vvar.c | 48 | ||||
-rw-r--r-- | tight_loop/perf_self_monitor.c | 96 |
2 files changed, 130 insertions, 14 deletions
diff --git a/dump-vvar.c b/dump-vvar.c index 0128542..afb3244 100644 --- a/dump-vvar.c +++ b/dump-vvar.c @@ -3,12 +3,52 @@ #include <string.h> #include <sys/mman.h> #include <unistd.h> +#include <setjmp.h> +#include <signal.h> +#include <err.h> + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), + int flags) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); +} + +static jmp_buf fail_jmp; + +static void handler(int sig, siginfo_t *si, void *ctx_void) +{ + write(2, "whoops!\n", 8); + siglongjmp(fail_jmp, 1); +} + +static void dump_page(int n, const void *base) +{ + unsigned char data[4096]; + + sethandler(SIGBUS, handler, 0); + + if (sigsetjmp(fail_jmp, 0)) { + fprintf(stderr, "Cannot read vvar page %d\n", n); + memset(data, 0xff, sizeof(data)); + } else { + memcpy(data, base, sizeof(data)); + } + + write(1, data, 4096); +} int main() { FILE *maps; void *vvar_begin, *vvar_end; int found_vvar = 0; + int npages; maps = fopen("/proc/self/maps", "r"); char buf[1024]; @@ -26,11 +66,13 @@ int main() } sscanf(buf, "%p-%p", &vvar_begin, &vvar_end); + npages = ((char *)vvar_end - (char *)vvar_begin) / 4096;; - fprintf(stderr, "vvar mapping is at 0x%lx to 0x%lx\n", - (unsigned long)vvar_begin, (unsigned long)vvar_end); + fprintf(stderr, "vvar mapping is %d pages (0x%lx - 0x%lx)\n", + npages, (unsigned long)vvar_begin, (unsigned long)vvar_end); - write(1, vvar_begin, vvar_end - vvar_begin); + for (int i = 0; i < npages; i++) + dump_page(i, (char *)vvar_begin + i * 4096); mprotect(vvar_begin, vvar_end - vvar_begin, PROT_READ | PROT_WRITE); diff --git a/tight_loop/perf_self_monitor.c b/tight_loop/perf_self_monitor.c index 323e91f..c5a8a44 100644 --- a/tight_loop/perf_self_monitor.c +++ b/tight_loop/perf_self_monitor.c @@ -17,7 +17,7 @@ struct psm_counter { struct psm_counter *psm_counter_create(void) { - struct psm_counter *counter = malloc(sizeof(struct psm_counter));; + struct psm_counter *counter = malloc(sizeof(struct psm_counter)); struct perf_event_attr attr; memset(&attr, 0, sizeof(attr)); @@ -226,8 +226,8 @@ uint64_t psm_integer_quantile(const struct psm_counter *ctr, psm_sample_fn fn, return ret; } -void psm_settle(const struct psm_counter *ctr, psm_sample_fn fn, - int reps, void *opaque) +uint64_t psm_settle(const struct psm_counter *ctr, psm_sample_fn fn, + int reps, void *opaque) { uint64_t val = UINT64_MAX; int good_iters = 0; @@ -248,25 +248,90 @@ void psm_settle(const struct psm_counter *ctr, psm_sample_fn fn, } else { good_iters++; if (good_iters == 10) - return; + return val; } } + + return ~0ULL; } int reparray[] = {1, 200}; +struct psm_costestimate +{ + double baseline; + double per_rep; +}; + +struct pair +{ + int x; + double y; +}; + +bool psm_estimate_cost(struct psm_costestimate *est, + const struct psm_counter *ctr, + psm_sample_fn fn, void *opaque) +{ + int rounds = 50; + int scale = 1; + int steps = 100; + int n = rounds * steps; + int i = 0; + uint64_t sample; + + struct pair *array = calloc(sizeof(struct pair), n); + for (int r = 0; r < rounds; r++) { + for (int s = 0; s < steps; s++) { + array[i].x = s * scale; + i++; + } + } + + /* Now randomly permute it. */ + for (i = n - 1; i >= 1; i--) { + int j = rand() % i; + int tmp = array[i].x; + array[i].x = array[j].x; + array[j].x = tmp; + } + + /* Burn a big sample. */ + fn(&sample, ctr, scale * steps * (rounds / 2), opaque); + + /* Now get all the samples and accumulate. */ + double sum_xy = 0.0, sum_x = 0.0, sum_xx = 0.0, sum_y = 0.0; + for (i = 0; i < n; i++) { + while (!fn(&sample, ctr, array[i].x, opaque)) + ; + array[i].y = sample; + + sum_x += array[i].x; + sum_xy += array[i].x * array[i].y; + sum_xx += (double)array[i].x * (double)array[i].x; + sum_y += array[i].y; + } + + /* Calculate a simple linear regression. */ + est->per_rep = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x); + est->baseline = (sum_y - est->per_rep * sum_x) / n; + + free(array); + return true; +}; + int main() { struct psm_counter *ctr = psm_counter_create(); - psm_settle(ctr, psm_atomic_sample_empty, 1, NULL); - - uint64_t baseline = - psm_integer_quantile(ctr, psm_atomic_sample_empty, - 1, NULL, 250, 500); - printf("An empty sample takes %llu cycles\n", - (unsigned long long)baseline); + uint64_t baseline = psm_settle(ctr, psm_atomic_sample_empty, 1, NULL); + if (baseline == (uint64_t)~0ULL) + printf("Self-monitoring warm-up didn't settle down\n"); + else + printf("Self-monitoring warmed up: overhead is %llu cycles\n", + (unsigned long long)baseline); + /* for (int repidx = 0; repidx < 2; repidx++) { int reps = reparray[repidx]; for (int i = 0; i < 10; i++) { @@ -282,6 +347,15 @@ int main() printf("%dx bad prctl: %llu\n", reps, (unsigned long long)cost/reps); } } + */ + + struct psm_costestimate est; + + psm_estimate_cost(&est, ctr, psm_atomic_sample_enosys, NULL); + printf("ENOSYS:\t\t%.2f cycles (plus %.2f cycles self-monitoring overhead)\n", est.per_rep, est.baseline); + + psm_estimate_cost(&est, ctr, psm_atomic_sample_bad_prctl, NULL); + printf("bad prctl:\t%.2f cycles (plus %.2f cycles self-monitoring overhead)\n", est.per_rep, est.baseline); psm_counter_destroy(ctr); } |