summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2015-12-29 19:59:51 -0800
committerAndy Lutomirski <luto@kernel.org>2015-12-29 19:59:51 -0800
commit3042f3f08ad781437cdb97b91435aabbf0ab3a68 (patch)
treedaea06910fb1a7506ca61ff4e6ba0ed91c612dfb
parent1cc2ec6849376c3d47378f43b5be0427e6aedcfc (diff)
downloadmisc-tests-3042f3f08ad781437cdb97b91435aabbf0ab3a68.tar.gz
Improve dump-vvar
-rw-r--r--dump-vvar.c48
-rw-r--r--tight_loop/perf_self_monitor.c96
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);
}