This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[Patch] Dryrun framework.
- From: OndÅej BÃlka <neleai at seznam dot cz>
- To: libc-alpha at sourceware dot org
- Date: Tue, 9 Apr 2013 21:22:49 +0200
- Subject: [Patch] Dryrun framework.
Hi,
Dryrun is framework to supply real world data for microbenchmarks
and analyze workloads.
To keep first commit simple I only added code to handle exp.
Others will follow.
One question is where to save data? For memset I produced 20MB file
so adding to git is out of question.
Is possible http/ftp at sourceware where we could upload these files.
Another issue leaking information. So far I for memset/memcpy/strlen
need only to know positions and I doubt that somebody can reconstruct
from it password.
Compiling directory with given function creates three files:
record.so: To record function calls write 'LD_PRELOAD=dir/record.so command'
or add record.so to /ld.so.preload for global recording.
replay: Calls function as recorded.
show: displays recorded data.
OK to commit?
Ondra
* dryrun/common/common.h: New file.
* dryrun/common/record_common.h: New file.
* dryrun/common/replay_common.h: New file.
* dryrun/exp/Makefile: New file.
* dryrun/exp/layout.h: New file.
* dryrun/exp/record.c: New file.
* dryrun/exp/replay.c: New file.
* dryrun/exp/show.c: New file.
* dryrun/sysdeps/generic.h: New file.
>From 563629a9f59f1d2926e5b234ed4bd84d20930ce4 Mon Sep 17 00:00:00 2001
From: Ondrej Bilka <neleai@seznam.cz>
Date: Tue, 9 Apr 2013 20:34:53 +0200
Subject: [PATCH] dryrun framework
---
dryrun/common/common.h | 24 +++++++++++++++++++++
dryrun/common/record_common.h | 39 ++++++++++++++++++++++++++++++++++
dryrun/common/replay_common.h | 24 +++++++++++++++++++++
dryrun/exp/Makefile | 4 +++
dryrun/exp/layout.h | 5 ++++
dryrun/exp/record.c | 18 +++++++++++++++
dryrun/exp/replay.c | 10 ++++++++
dryrun/exp/show.c | 9 +++++++
dryrun/sysdeps/generic.h | 47 +++++++++++++++++++++++++++++++++++++++++
9 files changed, 180 insertions(+), 0 deletions(-)
create mode 100644 dryrun/common/common.h
create mode 100644 dryrun/common/record_common.h
create mode 100644 dryrun/common/replay_common.h
create mode 100644 dryrun/exp/Makefile
create mode 100644 dryrun/exp/layout.h
create mode 100644 dryrun/exp/record.c
create mode 100644 dryrun/exp/replay.c
create mode 100644 dryrun/exp/show.c
create mode 100644 dryrun/sysdeps/generic.h
diff --git a/dryrun/common/common.h b/dryrun/common/common.h
new file mode 100644
index 0000000..c7a0148
--- /dev/null
+++ b/dryrun/common/common.h
@@ -0,0 +1,24 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../sysdeps/generic.h"
+
+typedef struct
+{
+ uint64_t time_start;
+ uint64_t time_end;
+ uint64_t backtrace;
+} common_s;
+
+#include "layout.h"
+
+typedef struct
+{
+ char binary_name[48];
+ uint64_t size,capacity;
+ rec items[];
+} header;
+
+static void init_fn();
+static header *h;
diff --git a/dryrun/common/record_common.h b/dryrun/common/record_common.h
new file mode 100644
index 0000000..bbd13eb
--- /dev/null
+++ b/dryrun/common/record_common.h
@@ -0,0 +1,39 @@
+#include "common.h"
+
+__attribute__ ((constructor)) static void __start_profile ()
+{
+ h = malloc (sizeof (header) + 1000 * sizeof (rec));
+ h->size = 0;
+ h->capacity = 1000;
+ init_fn ();
+}
+
+
+__attribute__ ((destructor)) static void __end_profile ()
+{
+ int i, j;
+ binary_name (h->binary_name);
+ FILE* fi = fopen (FNAME, "a");
+ if (fi)
+ {
+ //lock_file (fi);
+ fwrite (h, sizeof (header) + h->size * sizeof (rec), 1, fi);
+ fclose (fi);
+ }
+}
+
+rec* add_record ()
+{
+ h->size++;
+ if (h->size == h->capacity)
+ {
+ h->capacity *= 2;
+ h = realloc (h, sizeof (header) + h->capacity * sizeof (rec));
+ }
+
+ rec* r = h->items + (h->size - 1);
+ r->common.time_start = get_ticks ();
+ r->common.backtrace = backtrace2 ();
+
+ return r;
+}
diff --git a/dryrun/common/replay_common.h b/dryrun/common/replay_common.h
new file mode 100644
index 0000000..04c322b
--- /dev/null
+++ b/dryrun/common/replay_common.h
@@ -0,0 +1,24 @@
+#include "common.h"
+
+void replay (rec* r, int size);
+
+int main (int argc, char** argv)
+{
+ long i;
+ rec* buf;
+ char* fname = argv[1];
+ if (argc == 1)
+ fname = FNAME;
+ FILE* fi = fopen (fname, "r");
+ h = malloc (sizeof (header));
+ while (!feof (fi))
+ {
+ fread (h, sizeof (header), 1, fi);
+ buf = malloc (h->size * sizeof (rec));
+ fread (buf, h->size * sizeof (rec), 1, fi);
+ printf ("replaying %s\n", h->binary_name);
+
+ replay (buf, h->size);
+ free (buf);
+ }
+}
diff --git a/dryrun/exp/Makefile b/dryrun/exp/Makefile
new file mode 100644
index 0000000..1e4cae6
--- /dev/null
+++ b/dryrun/exp/Makefile
@@ -0,0 +1,4 @@
+all:
+ gcc -I. -I../common -g -DFNAME='"${PWD}/record.rec"' record.c -lm -lrt -ldl -shared -fPIC -o record.so
+ gcc -I. -I../common -g -DFNAME='"${PWD}/record.rec"' replay.c -lm -lrt -o replay
+ gcc -I. -I../common -g -DFNAME='"${PWD}/record.rec"' show.c -lm -lrt -o show
diff --git a/dryrun/exp/layout.h b/dryrun/exp/layout.h
new file mode 100644
index 0000000..660f481
--- /dev/null
+++ b/dryrun/exp/layout.h
@@ -0,0 +1,5 @@
+typedef struct
+{
+ common_s common;
+ double x;
+} rec;
diff --git a/dryrun/exp/record.c b/dryrun/exp/record.c
new file mode 100644
index 0000000..8208a99
--- /dev/null
+++ b/dryrun/exp/record.c
@@ -0,0 +1,18 @@
+#include <dlfcn.h>
+#include "record_common.h"
+
+static void *libm_handle;
+static double (*fn) (double);
+
+static void init_fn ()
+{
+ libm_handle = dlopen ("libm.so", RTLD_NOW);
+ fn = dlsym (libm_handle, "exp");
+}
+
+double exp (double x)
+{
+ rec *r = add_record ();
+ r->x = x;
+ return fn (x);
+}
diff --git a/dryrun/exp/replay.c b/dryrun/exp/replay.c
new file mode 100644
index 0000000..a07fdea
--- /dev/null
+++ b/dryrun/exp/replay.c
@@ -0,0 +1,10 @@
+#include "replay_common.h"
+
+void replay (rec *r, int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ exp (r[i].x);
+ }
+}
diff --git a/dryrun/exp/show.c b/dryrun/exp/show.c
new file mode 100644
index 0000000..89e88bd
--- /dev/null
+++ b/dryrun/exp/show.c
@@ -0,0 +1,9 @@
+#include "replay_common.h"
+void replay (rec *r,int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ printf ("%lf\n", r[i].x);
+ }
+}
diff --git a/dryrun/sysdeps/generic.h b/dryrun/sysdeps/generic.h
new file mode 100644
index 0000000..8e5e5c4
--- /dev/null
+++ b/dryrun/sysdeps/generic.h
@@ -0,0 +1,47 @@
+#include <stdint.h>
+#include <time.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+
+/* TODO Placeholder function. */
+/* We can use backtrace as it depends on libgcc which causes dlopen->backtrace->dlopen infinite loop. */
+static uint64_t __attribute__ ((noinline)) backtrace2 ()
+{
+ return 0;
+}
+
+/* TODO now only linux specific. */
+static void binary_name (char *x)
+{
+ int i;
+ sprintf (x, "/proc/%i/cmdline", getpid ());
+ FILE *f=fopen (x, "r");
+ for (i = 0 ; i < 48 ; i++)
+ x[i] = 0;
+ fgets (x, 48, f);
+ x[47] = 0;
+}
+
+/* TODO add platform specific clocks that measure cycles. */
+static uint64_t __attribute__ ((noinline)) get_ticks ()
+{
+ struct timespec ts;
+ clock_gettime (CLOCK_REALTIME, &ts);
+ return 1000000000 * ts.tv_sec + ts.tv_nsec;
+}
+
+static void lock_file (FILE *fi)
+{
+ lock_file (fi);
+ struct flock fl;
+ int fd = fileno (fi);
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_pid = getpid ();
+ fcntl (fd, F_SETLKW, &fl);
+}
--
1.7.4.4