aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fl.fischer@fau.de>2019-02-08 13:31:11 +0100
committerFlorian Fischer <florian.fl.fischer@fau.de>2019-02-08 13:31:11 +0100
commitf2327ada5590f40137416f301762cd3c11ab36b6 (patch)
tree7e49bfbb189ce34c84384a444aed13125bc6c8ff
parent9240e149758e6e3923151687a7830e8940567ddc (diff)
downloadallocbench-f2327ada5590f40137416f301762cd3c11ab36b6.tar.gz
allocbench-f2327ada5590f40137416f301762cd3c11ab36b6.zip
s/target/allocator/ and remove analyse feature
Use systemwide installed allocators by default
-rw-r--r--.gitignore2
-rwxr-xr-xbench.py37
-rw-r--r--src/Makefile6
-rw-r--r--src/allocators.py22
-rw-r--r--src/benchmark.py114
-rw-r--r--src/chattymalloc.c161
-rw-r--r--src/chattyparser.py165
-rw-r--r--src/dj_trace.py56
-rw-r--r--src/falsesharing.py12
-rw-r--r--src/mysql.py95
-rw-r--r--src/targets.py19
-rw-r--r--targets/Makefile22
12 files changed, 131 insertions, 580 deletions
diff --git a/.gitignore b/.gitignore
index 5e44def..7070a8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
build/*
results/*
-targets/*.so
+allocators/*.so
dj_workloads/*
*.png
*__pycache__*
diff --git a/bench.py b/bench.py
index a4283d9..c4adb2a 100755
--- a/bench.py
+++ b/bench.py
@@ -7,23 +7,22 @@ import os
import subprocess
import src.facter
-import src.targets
+import src.allocators
benchmarks = ["loop", "mysql", "falsesharing", "dj_trace", "larson"]
parser = argparse.ArgumentParser(description="benchmark memory allocators")
parser.add_argument("-s", "--save", help="save benchmark results to disk", action='store_true')
parser.add_argument("-l", "--load", help="load benchmark results from directory", type=str)
-parser.add_argument("-t", "--targets", help="load target definitions from file", type=str)
+parser.add_argument("-a", "--allocators", help="load allocator definitions from file", type=str)
parser.add_argument("-r", "--runs", help="how often the benchmarks run", default=3, type=int)
parser.add_argument("-v", "--verbose", help="more output", action='store_true')
parser.add_argument("-b", "--benchmarks", help="benchmarks to run", nargs='+')
parser.add_argument("-ns", "--nosum", help="don't produce plots", action='store_true')
parser.add_argument("-sd", "--resultdir", help="directory where all results go", type=str)
-parser.add_argument("-a", "--analyse", help="collect allocation sizes", action='store_true')
-parser.add_argument("--nolibmemusage", help="don't use libmemusage to analyse", action='store_true')
parser.add_argument("--license", help="print license info and exit", action='store_true')
+
def main():
args = parser.parse_args()
if args.license:
@@ -31,6 +30,9 @@ def main():
print("License GPLv3: GNU GPL version 3 <http://gnu.org/licenses/gpl.html>")
return
+ if args.verbose:
+ print(args)
+
# Prepare allocbench
print("Building allocbench")
make_cmd = ["make"]
@@ -39,16 +41,18 @@ def main():
subprocess.run(make_cmd)
- if args.verbose:
- print(args)
+ allocators_file = os.path.join("build", "allocators", "allocators.py")
+
+ if args.allocators or os.path.isfile(allocators_file):
+ allocators_files = args.allocators or allocators_file
- if args.targets:
- with open(args.targets, "r") as f:
- g = {}
+ with open(allocators_files, "r") as f:
+ g = {"verbose": args.verbose}
exec(f.read(), g)
- src.targets.targets = g["targets"]
- if args.verbose:
- print("Targets:", src.targets.targets.keys())
+ src.allocators.allocators = g["allocators"]
+
+ if args.verbose:
+ print("Allocators:", *src.allocators.allocators.keys())
if args.save or not args.nosum and not (args.runs < 1 and not args.load):
if args.resultdir:
@@ -68,17 +72,12 @@ def main():
if args.load:
bench.load(path=args.load)
- if args.runs > 0 or args.analyse:
+ if args.runs > 0:
print("Preparing", bench.name, "...")
if not bench.prepare():
print("Preparing", bench.name, "failed!")
return
- if args.analyse and hasattr(bench, "analyse") and callable(bench.analyse):
- print("Analysing", bench.name, "...")
- analyse_args = {"nolibmemusage": args.nolibmemusage, "verbose": args.verbose}
- bench.analyse(**analyse_args)
-
if not bench.run(runs=args.runs, verbose=args.verbose):
continue
@@ -100,7 +99,7 @@ def main():
os.chdir(old_cwd)
- if (args.runs > 0 or args.analyse) and hasattr(bench, "cleanup"):
+ if args.runs > 0 and hasattr(bench, "cleanup"):
print("Cleaning up", bench.name, "...")
bench.cleanup()
diff --git a/src/Makefile b/src/Makefile
index 7173c99..e29af5d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -12,16 +12,12 @@ LDFLAGS ?= -pthread -static-libgcc
.PHONY: all clean
-all: $(OBJDIR)/print_status_on_exit.so $(OBJDIR)/chattymalloc.so
+all: $(OBJDIR)/print_status_on_exit.so
$(OBJDIR)/print_status_on_exit.so: print_status_on_exit.c | $(OBJDIR)
@echo "Compiling $@...";
$(CC) $(LDFLAGS) -shared $(CFLAGS) -o $@ $<
-$(OBJDIR)/chattymalloc.so: chattymalloc.c | $(OBJDIR)
- @echo "Compiling $@...";
- $(CC) $(LDFLAGS) -shared $(CFLAGS) -o $@ $<
-
$(OBJDIR):
mkdir $@
diff --git a/src/allocators.py b/src/allocators.py
new file mode 100644
index 0000000..dbf26d1
--- /dev/null
+++ b/src/allocators.py
@@ -0,0 +1,22 @@
+"""Default allocators using system libraries"""
+
+import os
+import subprocess
+
+maybe_allocators = ["tcmalloc", "jemalloc", "hoard"]
+
+allocators = {"libc": {"cmd_prefix" : "",
+ "binary_suffix" : "",
+ "LD_PRELOAD" : "",
+ "color" : "C1"}}
+
+for i, t in enumerate(maybe_allocators):
+ try:
+ path = subprocess.check_output('whereis lib{} | cut -d":" -f2'.format(t),
+ shell=True, text=True).strip()
+
+ if path != "":
+ allocators[t] = {"cmd_prefix": "", "binary_suffix": "",
+ "LD_PRELOAD": path, "color": "C"+str(i+2)}
+ except:
+ pass
diff --git a/src/benchmark.py b/src/benchmark.py
index e29df66..1aa5cf9 100644
--- a/src/benchmark.py
+++ b/src/benchmark.py
@@ -8,7 +8,7 @@ import pickle
import shutil
import subprocess
-from src.targets import targets
+from src.allocators import allocators
class Benchmark (object):
@@ -19,9 +19,8 @@ class Benchmark (object):
"your own useful one."),
"measure_cmd": "perf stat -x, -d",
- "analyse_cmd": "memusage -p {} -t",
"cmd": "true",
- "targets": targets,
+ "allocators": allocators,
}
def __init__(self):
@@ -39,8 +38,8 @@ class Benchmark (object):
if not hasattr(self, "results"):
self.results = {}
self.results["args"] = self.args
- self.results["targets"] = self.targets
- self.results.update({t: {} for t in self.targets})
+ self.results["allocators"] = self.allocators
+ self.results.update({t: {} for t in self.allocators})
if not hasattr(self, "requirements"):
self.requirements = []
@@ -53,11 +52,11 @@ class Benchmark (object):
# into lists of dicts.
save_data = {}
save_data.update(self.results)
- for target in self.results["targets"]:
+ for allocator in self.results["allocators"]:
tmp_list = []
- for ntuple, measures in self.results[target].items():
+ for ntuple, measures in self.results[allocator].items():
tmp_list.append((ntuple._asdict(), measures))
- save_data[target] = tmp_list
+ save_data[allocator] = tmp_list
with open(f, "wb") as f:
pickle.dump(save_data, f)
@@ -75,11 +74,11 @@ class Benchmark (object):
with open(f, "rb") as f:
self.results = pickle.load(f)
# Build new named tuples
- for target in self.results["targets"]:
+ for allocator in self.results["allocators"]:
d = {}
- for dic, measures in self.results[target]:
+ for dic, measures in self.results[allocator]:
d[self.Perm(**dic)] = measures
- self.results[target] = d
+ self.results[allocator] = d
def prepare(self, verbose=False):
def is_exe(fpath):
@@ -128,76 +127,23 @@ class Benchmark (object):
if is_fixed:
yield p
- def analyse(self, verbose=False, nolibmemusage=True):
- if not nolibmemusage and not shutil.which("memusage"):
- print("memusage not found. Using chattymalloc.")
- nolibmemusage = True
-
- if nolibmemusage:
- import chattyparser
- actual_cmd = ""
- old_preload = os.environ.get("LD_PRELOAD", None)
- os.environ["LD_PRELOAD"] = "build/chattymalloc.so"
-
- n = len(list(self.iterate_args()))
- for i, perm in enumerate(self.iterate_args()):
- print(i + 1, "of", n, "\r", end='')
- perm = perm._asdict()
- file_name = self.name + "."
- file_name += ".".join([str(x) for x in perm.values()])
- file_name += ".memusage"
-
- if not nolibmemusage:
- actual_cmd = self.analyse_cmd.format(file_name + ".png") + " "
-
- if "binary_suffix" in self.cmd:
- perm["binary_suffix"] = ""
- actual_cmd += self.cmd.format(**perm)
-
- res = subprocess.run(actual_cmd.split(),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True)
-
- if res.returncode != 0:
- print(actual_cmd, "failed.")
- print("Stdout:", res.stdout)
- print("Stderr:", res.stderr)
- print("Aborting analysing.")
- return
-
- if nolibmemusage:
- try:
- chattyparser.plot()
- except MemoryError:
- print("Can't Analyse", actual_cmd, "with chattymalloc",
- "because to much memory would be needed.")
- continue
- else:
- with open(file_name + ".hist", "w") as f:
- f.write(res.stderr)
-
- if nolibmemusage:
- os.environ["LD_PRELOAD"] = old_preload or ""
- print()
-
def run(self, verbose=False, runs=5):
if runs > 0:
print("Running", self.name, "...")
- n = len(list(self.iterate_args())) * len(self.targets)
+ n = len(list(self.iterate_args())) * len(self.allocators)
for run in range(1, runs + 1):
print(str(run) + ". run")
i = 0
- for tname, t in self.targets.items():
+ for tname, t in self.allocators.items():
if tname not in self.results:
self.results[tname] = {}
os.environ["LD_PRELOAD"] = "build/print_status_on_exit.so "
os.environ["LD_PRELOAD"] += t["LD_PRELOAD"]
- if hasattr(self, "pretarget_hook"):
- if self.pretarget_hook((tname, t), run, verbose):
+ if hasattr(self, "preallocator_hook"):
+ if self.preallocator_hook((tname, t), run, verbose):
return False
for perm in self.iterate_args():
@@ -261,8 +207,8 @@ class Benchmark (object):
self.results[tname][perm] = []
self.results[tname][perm].append(result)
- if hasattr(self, "posttarget_hook"):
- if self.posttarget_hook((tname, t), run, verbose):
+ if hasattr(self, "postallocator_hook"):
+ if self.postallocator_hook((tname, t), run, verbose):
return False
print()
os.environ["PATH"] = os.environ["PATH"].replace(":build/" + self.name, "")
@@ -273,15 +219,15 @@ class Benchmark (object):
sumdir="", arg=""):
args = self.results["args"]
- targets = self.results["targets"]
+ allocators = self.results["allocators"]
arg = arg or list(args.keys())[0]
- for target in targets:
+ for allocator in allocators:
y_vals = []
for perm in self.iterate_args(args=args):
d = []
- for m in self.results[target][perm]:
+ for m in self.results[allocator][perm]:
d.append(eval(yval.format(**m)))
y_vals.append(np.mean(d))
if not autoticks:
@@ -289,7 +235,7 @@ class Benchmark (object):
else:
x_vals = args[arg]
plt.plot(x_vals, y_vals, marker='.', linestyle='-',
- label=target, color=targets[target]["color"])
+ label=allocator, color=allocators[allocator]["color"])
plt.legend()
if not autoticks:
@@ -305,16 +251,16 @@ class Benchmark (object):
sumdir="", fixed=[]):
args = self.results["args"]
- targets = self.results["targets"]
+ allocators = self.results["allocators"]
for arg in fixed or args:
loose_arg = [a for a in args if a != arg][0]
for arg_value in args[arg]:
- for target in targets:
+ for allocator in allocators:
y_vals = []
for perm in self.iterate_args_fixed({arg: arg_value}, args=args):
d = []
- for m in self.results[target][perm]:
+ for m in self.results[allocator][perm]:
d.append(eval(yval.format(**m)))
y_vals.append(np.mean(d))
if not autoticks:
@@ -322,7 +268,7 @@ class Benchmark (object):
else:
x_vals = args[loose_arg]
plt.plot(x_vals, y_vals, marker='.', linestyle='-',
- label=target, color=targets[target]["color"])
+ label=allocator, color=allocators[allocator]["color"])
plt.legend()
if not autoticks:
@@ -338,7 +284,7 @@ class Benchmark (object):
filepostfix="", sumdir="", std=False):
args = self.results["args"]
keys = list(args.keys())
- targets = self.results["targets"]
+ allocators = self.results["allocators"]
header_arg = keys[0] if len(args[keys[0]]) < len(args[keys[1]]) else keys[1]
row_arg = [arg for arg in args if arg != header_arg][0]
@@ -352,20 +298,20 @@ class Benchmark (object):
for perm in self.iterate_args_fixed({row_arg: av}, args=args):
best = []
best_val = None
- for target in targets:
+ for allocator in allocators:
d = []
- for m in self.results[target][perm]:
+ for m in self.results[allocator][perm]:
d.append(eval(evaluation.format(**m)))
mean = np.mean(d)
if not best_val:
- best = [target]
+ best = [allocator]
best_val = mean
elif ((sort == ">" and mean > best_val)
or (sort == "<" and mean < best_val)):
- best = [target]
+ best = [allocator]
best_val = mean
elif mean == best_val:
- best.append(target)
+ best.append(allocator)
row.append("{}: {:.3f}".format(best[0], best_val))
cell_text.append(row)
diff --git a/src/chattymalloc.c b/src/chattymalloc.c
deleted file mode 100644
index 54708d6..0000000
--- a/src/chattymalloc.c
+++ /dev/null
@@ -1,161 +0,0 @@
-#define _GNU_SOURCE
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static char tmpbuff[1024];
-static unsigned long tmppos = 0;
-static unsigned long tmpallocs = 0;
-
-static int out = -1;
-static int prevent_recursion = 0;
-
-/*=========================================================
- * * interception points
- * */
-
-static void * (*myfn_malloc)(size_t size);
-static void (*myfn_free)(void* ptr);
-static void * (*myfn_calloc)(size_t nmemb, size_t size);
-static void * (*myfn_realloc)(void* ptr, size_t size);
-static void * (*myfn_memalign)(size_t alignment, size_t size);
-
-static void write_output(const char* fmt, ...)
-{
- if (!prevent_recursion)
- {
- prevent_recursion = 1;
-
- /* lockf(out, F_LOCK, 0); */
-
- va_list args;
- va_start(args, fmt);
- vdprintf(out, fmt, args);
- va_end(args);
-
- /* lockf(out, F_ULOCK, 0); */
- prevent_recursion = 0;
- }
-}
-
-static void init()
-{
- out = open("chattymalloc.data", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (out == -1)
- {
- fprintf(stderr, "failed to open output file with %d\n", errno);
- exit(1);
- }
-
- myfn_malloc = dlsym(RTLD_NEXT, "malloc");
- myfn_free = dlsym(RTLD_NEXT, "free");
- myfn_calloc = dlsym(RTLD_NEXT, "calloc");
- myfn_realloc = dlsym(RTLD_NEXT, "realloc");
- myfn_memalign = dlsym(RTLD_NEXT, "memalign");
-
- if (!myfn_malloc || !myfn_free || !myfn_calloc || !myfn_realloc || !myfn_memalign)
- {
- fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
- exit(1);
- }
-}
-
-void *malloc(size_t size)
-{
- static int initializing = 0;
-
- if (myfn_malloc == NULL)
- {
- if (!initializing)
- {
- initializing = 1;
- init();
- initializing = 0;
-
- }
- else
- {
- if (tmppos + size < sizeof(tmpbuff))
- {
- void *retptr = tmpbuff + tmppos;
- tmppos += size;
- ++tmpallocs;
- return retptr;
- }
- else
- {
- fprintf(stderr, "%d in %d allocs\n", tmppos, tmpallocs);
- fprintf(stderr, "jcheck: too much memory requested during initialisation - increase tmpbuff size\n");
- exit(1);
- }
- }
- }
-
- void *ptr = myfn_malloc(size);
- write_output("m %zu %p\n", size, ptr);
- return ptr;
-}
-
-void free(void *ptr)
-{
- // something wrong if we call free before one of the allocators!
- if (myfn_malloc == NULL)
- init();
- if (!(ptr >= (void*) tmpbuff && ptr <= (void*)(tmpbuff + tmppos)))
- {
- write_output("f %p\n", ptr);
- myfn_free(ptr);
- }
-}
-
-void* realloc(void *ptr, size_t size)
-{
- if (myfn_realloc == NULL)
- {
- void *nptr = malloc(size);
- if (nptr && ptr)
- {
- memmove(nptr, ptr, size);
- free(ptr);
- }
- return nptr;
- }
-
- void* nptr = myfn_realloc(ptr, size);
- write_output("r %p %zu %p\n", ptr, size, nptr);
- return nptr;
-}
-
-void* calloc(size_t nmemb, size_t size)
-{
- if (myfn_calloc == NULL)
- {
- void *ptr = malloc(nmemb*size);
- if (ptr)
- memset(ptr, 0, nmemb*size);
- return ptr;
- }
-
- void* ptr = myfn_calloc(nmemb, size);
- write_output("c %zu %zu %p\n", nmemb, size, ptr);
- return ptr;
-}
-
-void* memalign(size_t alignment, size_t size)
-{
- if (myfn_memalign == NULL)
- {
- fprintf(stderr, "called memalign before or during init");
- exit(1);
- }
-
- void* ptr = myfn_memalign(alignment, size);
- write_output("mm %zu %zu %p\n", alignment, size, ptr);
- return ptr;
-}
diff --git a/src/chattyparser.py b/src/chattyparser.py
deleted file mode 100644
index b1b6cd0..0000000
--- a/src/chattyparser.py
+++ /dev/null
@@ -1,165 +0,0 @@
-import re
-import matplotlib.pyplot as plt
-
-ptr = "(?:0x)?(?P<ptr>(?:\w+)|(?:\(nil\)))"
-size = "(?P<size>\d+)"
-
-malloc_re = re.compile("^m {} {}$".format(size, ptr))
-free_re = re.compile("^f {}$".format(ptr))
-calloc_re = re.compile("^c (?P<nmemb>\d+) {} {}$".format(size, ptr))
-realloc_re = re.compile("^r {} {} {}$".format(ptr, size, ptr.replace("ptr", "nptr")))
-memalign_re = re.compile("^mm (?P<alignment>\d+) {} {}$".format(size, ptr))
-
-
-def record_allocation(hist, total_size, allocations, ptr, size, coll_size,
- req_size, nohist, optr=None, add=True):
- size = int(size)
- if add:
- if optr and optr in allocations:
- size -= allocations[optr]
- del(allocations[optr])
-
- allocations[ptr] = size
- if not nohist:
- hist[size] = hist.get(size, 0) + 1
-
- if type(total_size[-1]) != int or type(size) != int:
- print("invalid type", type(total_size[-1]), type(size))
- return
-
- if coll_size:
- if not req_size or size == req_size:
- total_size.append(total_size[-1] + size)
- elif req_size:
- total_size.append(total_size[-1])
-
- elif ptr != "(nil)" and ptr in allocations:
- size = allocations[ptr]
- if coll_size:
- if not req_size or size == req_size:
- total_size.append(total_size[-1] - size)
- elif req_size:
- total_size.append(total_size[-1])
-
- del(allocations[ptr])
- elif coll_size:
- total_size.append(total_size[-1])
-
-
-def parse(path="chattymalloc.data", coll_size=True, req_size=None, nohist=False):
- tmalloc, tcalloc, trealloc, tfree, tmemalign = 0, 0, 0, 0, 0
- allocations = {}
- requested_size = [0]
- hist = {}
- ln = 0
-
- with open(path, "r") as f:
- for i, l in enumerate(f.readlines()):
- ln += 1
- res = malloc_re.match(l)
- if res is not None:
- res = res.groupdict()
- record_allocation(hist, requested_size, allocations, res["ptr"],
- res["size"], coll_size, req_size, nohist)
- tmalloc += 1
- continue
-
- res = free_re.match(l)
- if res is not None:
- res = res.groupdict()
- record_allocation(hist, requested_size, allocations, res["ptr"],
- 0, coll_size, req_size, nohist, add=False)
- tfree += 1
- continue
-
- res = calloc_re.match(l)
- if res is not None:
- res = res.groupdict()
- size = int(res["nmemb"]) * int(res["size"])
- record_allocation(hist, requested_size, allocations, res["ptr"],
- size, coll_size, req_size, nohist)
- tcalloc += 1
- continue
-
- res = realloc_re.match(l)
- if res is not None:
- res = res.groupdict()
- record_allocation(hist, requested_size, allocations, res["nptr"],
- res["size"], coll_size, req_size, nohist,
- optr=res["ptr"])
- trealloc += 1
- continue
-
- res = memalign_re.match(l)
- if res is not None:
- res = res.groupdict()
- record_allocation(hist, requested_size, allocations, res["ptr"],
- res["size"], coll_size, req_size, nohist)
- tmemalign += 1
- continue
-
- print("\ninvalid line at", ln, ":", l)
- calls = {"malloc": tmalloc, "free": tfree, "calloc": tcalloc,
- "realloc": trealloc, "memalign": tmemalign}
- return hist, calls, requested_size
-
-
-def plot(path):
- hist, calls, _ = parse(req_size=None)
- plot_hist_ascii(path+".hist", hist, calls)
- top5 = [t[1] for t in sorted([(n, s) for s, n in hist.items()])[-5:]]
-
- del(hist)
- del(calls)
- plot_profile(path+".profile.png", top5)
-
-
-def plot_profile(path, top5):
- _, calls, total_size = parse(nohist=True)
- x_vals = range(0, sum(calls.values()) + 1)
-
- plt.plot(x_vals, total_size, marker='',
- linestyle='-', label="Total requested")
-
- for s in top5:
- _, calls, total_size = parse(nohist=True, req_size=s)
- plt.plot(x_vals, total_size, label=s)
-
- plt.legend()
- plt.xlabel("Allocations")
- plt.ylabel("mem in kb")
- plt.title("Memusage profile")
- plt.savefig(path)
- plt.clf()
-
-
-def plot_hist_ascii(path, hist, calls):
- bins = {}
- for size in sorted(hist):
- bin = int(size / 16)
- bins[bin] = bins.get(bin, 0) + hist[size]
-
- total = sum(calls.values()) - calls["free"]
- with open(path, "w") as f:
- print("Total function calls:", total, file=f)
- print("malloc:", calls["malloc"], file=f)
- print("calloc:", calls["calloc"], file=f)
- print("realloc:", calls["realloc"], file=f)
- print("free:", calls["free"], file=f)
- print("memalign:", calls["memalign"], file=f)
- print(file=f)
-
- print("< 1024", sum([n for s, n in hist.items() if s < 1024]), file=f)
- print("< 4096", sum([n for s, n in hist.items() if s < 4096]), file=f)
- print(file=f)
-
- print("Histogram of sizes:", file=f)
- sbins = sorted(bins)
- binmaxlength = str(len(str(sbins[-1])) + 1)
- amountmaxlength = str(len(str(sorted(bins.values())[-1])))
- for b in sbins:
- perc = bins[b]/total*100
- binsize = "{:<" + binmaxlength + "} - {:>" + binmaxlength + "}"
- print(binsize.format((b)*16, (b+1)*16-1), end=" ", file=f)
- amount = "{:<" + amountmaxlength + "} {:.2f}% {}"
- print(amount.format(bins[b], perc, '*'*int(perc/2)), file=f)
diff --git a/src/dj_trace.py b/src/dj_trace.py
index 784b16f..d61e64d 100644
--- a/src/dj_trace.py
+++ b/src/dj_trace.py
@@ -109,7 +109,7 @@ class Benchmark_DJ_Trace(Benchmark):
sys.stderr.write("\n")
return True
- def process_output(self, result, stdout, stderr, target, perm, verbose):
+ def process_output(self, result, stdout, stderr, allocator, perm, verbose):
def to_int(s):
return int(s.replace(',', ""))
@@ -129,14 +129,14 @@ class Benchmark_DJ_Trace(Benchmark):
def summary(self):
args = self.results["args"]
- targets = self.results["targets"]
+ allocators = self.results["allocators"]
# Total times
for perm in self.iterate_args(args=args):
- for i, target in enumerate(targets):
- d = [float(x["cputime"]) for x in self.results[target][perm]]
+ for i, allocator in enumerate(allocators):
+ d = [float(x["cputime"]) for x in self.results[allocator][perm]]
y_val = np.mean(d)/1000
- plt.bar([i], y_val, label=target, color=targets[target]["color"])
+ plt.bar([i], y_val, label=allocator, color=allocators[allocator]["color"])
# ticks_y = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/1000))
# plt.gca().yaxis.set_major_formatter(ticks_y)
@@ -150,18 +150,18 @@ class Benchmark_DJ_Trace(Benchmark):
# Function Times
xa = np.arange(0, 6, 1.5)
for perm in self.iterate_args(args=args):
- for i, target in enumerate(targets):
- x_vals = [x+i/len(targets) for x in xa]
+ for i, allocator in enumerate(allocators):
+ x_vals = [x+i/len(allocators) for x in xa]
y_vals = [0] * 4
- y_vals[0] = np.mean([x["avg_malloc"] for x in self.results[target][perm]])
- y_vals[1] = np.mean([x["avg_calloc"] for x in self.results[target][perm]])
- y_vals[2] = np.mean([x["avg_realloc"] for x in self.results[target][perm]])
- y_vals[3] = np.mean([x["avg_free"] for x in self.results[target][perm]])
+ y_vals[0] = np.mean([x["avg_malloc"] for x in self.results[allocator][perm]])
+ y_vals[1] = np.mean([x["avg_calloc"] for x in self.results[allocator][perm]])
+ y_vals[2] = np.mean([x["avg_realloc"] for x in self.results[allocator][perm]])
+ y_vals[3] = np.mean([x["avg_free"] for x in self.results[allocator][perm]])
plt.bar(x_vals, y_vals, width=0.25, align="center",
- label=target, color=targets[target]["color"])
+ label=allocator, color=allocators[allocator]["color"])
plt.legend(loc="best")
- plt.xticks(xa + 1/len(targets)*2,
+ plt.xticks(xa + 1/len(allocators)*2,
["malloc\n" + str(self.results[perm.workload]["malloc"]) + "\ncalls",
"calloc\n" + str(self.results[perm.workload]["calloc"]) + "\ncalls",
"realloc\n" + str(self.results[perm.workload]["realloc"]) + "\ncalls",
@@ -173,14 +173,14 @@ class Benchmark_DJ_Trace(Benchmark):
# Memusage
for perm in self.iterate_args(args=args):
- for i, target in enumerate(targets):
- d = [x["Max_RSS"] for x in self.results[target][perm]]
+ for i, allocator in enumerate(allocators):
+ d = [x["Max_RSS"] for x in self.results[allocator][perm]]
y_val = np.mean(d)/1000
- plt.bar([i], y_val, label=target, color=targets[target]["color"])
+ plt.bar([i], y_val, label=allocator, color=allocators[allocator]["color"])
# add ideal rss
- y_val = self.results[list(targets.keys())[0]][perm][0]["Ideal_RSS"]/1000
- plt.bar([len(targets)], y_val, label="Ideal RSS")
+ y_val = self.results[list(allocators.keys())[0]][perm][0]["Ideal_RSS"]/1000
+ plt.bar([len(allocators)], y_val, label="Ideal RSS")
# ticks_y = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/1000))
# plt.gca().yaxis.set_major_formatter(ticks_y)
@@ -194,16 +194,16 @@ class Benchmark_DJ_Trace(Benchmark):
# Tables
for perm in self.iterate_args(args=args):
# collect data
- d = {target: {} for target in targets}
- for i, target in enumerate(targets):
- d[target]["time"] = [float(x["cputime"]) for x in self.results[target][perm]]
- d[target]["rss"] = [x["Max_RSS"] for x in self.results[target][perm]]
+ d = {allocator: {} for allocator in allocators}
+ for i, allocator in enumerate(allocators):
+ d[allocator]["time"] = [float(x["cputime"]) for x in self.results[allocator][perm]]
+ d[allocator]["rss"] = [x["Max_RSS"] for x in self.results[allocator][perm]]
- times = [np.mean(d[target]["time"]) for target in targets]
+ times = [np.mean(d[allocator]["time"]) for allocator in allocators]
tmin = min(times)
tmax = max(times)
- rss = [np.mean(d[target]["rss"]) for target in targets]
+ rss = [np.mean(d[allocator]["rss"]) for allocator in allocators]
rssmin = min(rss)
rssmax = max(rss)
@@ -213,10 +213,10 @@ class Benchmark_DJ_Trace(Benchmark):
print("& Zeit (ms) / $\\sigma$ (\\%) & VmHWM (KB) / $\\sigma$ (\\%) \\\\", file=f)
print("\\hline", file=f)
- for target in targets:
- print(target, end=" & ", file=f)
+ for allocator in allocators:
+ print(allocator, end=" & ", file=f)
- t = d[target]["time"]
+ t = d[allocator]["time"]
m = np.mean(t)
s = "\\textcolor{{{}}}{{{:.3f}}} / {:.3f}"
if m == tmin:
@@ -227,7 +227,7 @@ class Benchmark_DJ_Trace(Benchmark):
color = "black"
print(s.format(color, m, np.std(t)/m), end=" & ", file=f)
- t = d[target]["rss"]
+ t = d[allocator]["rss"]
m = np.mean(t)
if m == rssmin:
color = "green"
diff --git a/src/falsesharing.py b/src/falsesharing.py
index 79de436..859db03 100644
--- a/src/falsesharing.py
+++ b/src/falsesharing.py
@@ -26,31 +26,31 @@ class Benchmark_Falsesharing(Benchmark):
self.requirements = ["cache-thrash", "cache-scratch"]
super().__init__()
- def process_output(self, result, stdout, stderr, target, perm, verbose):
+ def process_output(self, result, stdout, stderr, allocator, perm, verbose):
result["time"] = time_re.match(stdout).group("time")
def summary(self):
# Speedup thrash
args = self.results["args"]
nthreads = args["threads"]
- targets = self.results["targets"]
+ allocators = self.results["allocators"]
for bench in self.results["args"]["bench"]:
- for target in targets:
+ for allocator in allocators:
y_vals = []
single_threaded_perm = self.Perm(bench=bench, threads=1)
single_threaded = np.mean([float(m["time"])
- for m in self.results[target][single_threaded_perm]])
+ for m in self.results[allocator][single_threaded_perm]])
for perm in self.iterate_args_fixed({"bench": bench}, args=args):
- d = [float(m["time"]) for m in self.results[target][perm]]
+ d = [float(m["time"]) for m in self.results[allocator][perm]]
y_vals.append(single_threaded / np.mean(d))
plt.plot(nthreads, y_vals, marker='.', linestyle='-',
- label=target, color=targets[target]["color"])
+ label=allocator, color=allocators[allocator]["color"])
plt.legend()
plt.xlabel("threads")
diff --git a/src/mysql.py b/src/mysql.py
index ac2ee34..f93a24d 100644
--- a/src/mysql.py
+++ b/src/mysql.py
@@ -10,7 +10,7 @@ from subprocess import PIPE
from time import sleep
from src.benchmark import Benchmark
-from src.targets import targets
+from src.allocators import allocators
cwd = os.getcwd()
@@ -32,9 +32,9 @@ class Benchmark_MYSQL(Benchmark):
self.descrition = """See sysbench documentation."""
# mysqld fails with hoard somehow
- self.targets = copy.copy(targets)
- if "hoard" in self.targets:
- del(self.targets["hoard"])
+ self.allocators = copy.copy(allocators)
+ if "hoard" in self.allocators:
+ del(self.allocators["hoard"])
self.args = {"nthreads": range(1, multiprocessing.cpu_count() + 1)}
self.cmd = cmd
@@ -88,7 +88,7 @@ class Benchmark_MYSQL(Benchmark):
return False
# Create sbtest TABLE
- p = subprocess.run("mysql -u root -S "+cwd+"/mysql_test/socket".split(" "),
+ p = subprocess.run(("mysql -u root -S "+cwd+"/mysql_test/socket").split(" "),
input=b"CREATE DATABASE sbtest;\n",
stdout=PIPE, stderr=PIPE)
@@ -118,20 +118,20 @@ class Benchmark_MYSQL(Benchmark):
print("Delete mysqld directory")
shutil.rmtree("mysql_test")
- def pretarget_hook(self, target, run, verbose):
+ def preallocator_hook(self, allocator, run, verbose):
if not self.start_and_wait_for_server(verbose,
- cmd_prefix=target[1]["cmd_prefix"]):
- print("Can't start server for", target[0] + ".")
+ cmd_prefix=allocator[1]["cmd_prefix"]):
+ print("Can't start server for", allocator[0] + ".")
print("Aborting Benchmark.")
- print(target[1]["cmd_prefix"])
+ print(allocator[1]["cmd_prefix"])
print(self.server.stderr.read())
return False
- def posttarget_hook(self, target, run, verbose):
+ def postallocator_hook(self, allocator, run, verbose):
self.server.kill()
self.server.wait()
- def process_output(self, result, stdout, stderr, target, perm, verbose):
+ def process_output(self, result, stdout, stderr, allocator, perm, verbose):
result["transactions"] = re.search("transactions:\s*(\d*)", stdout).group(1)
result["queries"] = re.search("queries:\s*(\d*)", stdout).group(1)
# Latency
@@ -145,53 +145,8 @@ class Benchmark_MYSQL(Benchmark):
result["rssmax"] = int(l.replace("VmHWM:", "").strip().split()[0])
break
- def analyse(self, verbose=False, nolibmemusage=""):
- import chattyparser
-
- nthreads = [0] + list(self.args["nthreads"])
- failed = False
-
- runs = len(nthreads)
- for i, t in enumerate(nthreads):
- print("analysing", i + 1, "of", runs, "\r", end='')
-
- os.environ["LD_PRELOAD"] = "build/chattymalloc.so"
- if not self.start_and_wait_for_server(verbose):
- print("Can't start server.")
- print("Aborting analysing.")
- failed = True
- os.environ["LD_PRELOAD"] = ""
-
- if not failed and t != 0:
- target_cmd = self.cmd.format(nthreads=t).split(" ")
- p = subprocess.run(target_cmd,
- stderr=PIPE,
- stdout=PIPE,
- universal_newlines=True)
-
- if p.returncode != 0:
- print("\n" + " ".join(target_cmd), "exited with",
- p.returncode, ".\n Aborting analysing.")
- print(p.stderr)
- print(p.stdout)
- failed = True
-
- self.server.kill()
- self.server.wait()
-
- hist, calls, reqsize, top5reqsize = chattyparser.parse()
- chattyparser.plot_hist_ascii(hist, calls,
- ".".join([self.name, str(t),
- "memusage", "hist"]))
-
- if failed:
- print(self.server.stdout.read())
- print(self.server.stderr.read())
- return False
- print()
-
def summary(self):
- targets = self.results["targets"]
+ allocators = self.results["allocators"]
args = self.results["args"]
# linear plot
@@ -202,14 +157,14 @@ class Benchmark_MYSQL(Benchmark):
filepostfix="l.ro")
# bar plot
- for i, target in enumerate(targets):
+ for i, allocator in enumerate(allocators):
y_vals = []
for perm in self.iterate_args(args=self.results["args"]):
- d = [int(m["transactions"]) for m in self.results[target][perm]]
+ d = [int(m["transactions"]) for m in self.results[allocator][perm]]
y_vals.append(np.mean(d))
x_vals = [x-i/8 for x in range(1, len(y_vals) + 1)]
- plt.bar(x_vals, y_vals, width=0.2, label=target, align="center",
- color=targets[target]["color"])
+ plt.bar(x_vals, y_vals, width=0.2, label=allocator, align="center",
+ color=allocators[allocator]["color"])
plt.legend()
plt.xlabel("threads")
@@ -227,21 +182,21 @@ class Benchmark_MYSQL(Benchmark):
filepostfix="ro.mem")
# Colored latex table showing transactions count
- d = {target: {} for target in targets}
+ d = {allocator: {} for allocator in allocators}
for perm in self.iterate_args(args=args):
- for i, target in enumerate(targets):
- t = [float(x["transactions"]) for x in self.results[target][perm]]
+ for i, allocator in enumerate(allocators):
+ t = [float(x["transactions"]) for x in self.results[allocator][perm]]
m = np.mean(t)
s = np.std(t)/m
- d[target][perm] = {"mean": m, "std": s}
+ d[allocator][perm] = {"mean": m, "std": s}
mins = {}
maxs = {}
for perm in self.iterate_args(args=args):
cmax = None
cmin = None
- for i, target in enumerate(targets):
- m = d[target][perm]["mean"]
+ for i, allocator in enumerate(allocators):
+ m = d[allocator][perm]["mean"]
if not cmax or m > cmax:
cmax = m
if not cmin or m < cmin:
@@ -258,10 +213,10 @@ class Benchmark_MYSQL(Benchmark):
print("& {}".format(head), end=" ", file=f)
print("\\\\\n\\hline", file=f)
- for target in targets:
- print(target, end=" ", file=f)
+ for allocator in allocators:
+ print(allocator, end=" ", file=f)
for perm in self.iterate_args(args=args):
- m = d[target][perm]["mean"]
+ m = d[allocator][perm]["mean"]
s = "& \\textcolor{{{}}}{{{:.3f}}}"
if m == maxs[perm]:
color = "green"
diff --git a/src/targets.py b/src/targets.py
deleted file mode 100644
index 50fcab0..0000000
--- a/src/targets.py
+++ /dev/null
@@ -1,19 +0,0 @@
-targets = {"glibc" : {
- "cmd_prefix" : "",
- "binary_suffix" : "",
- "LD_PRELOAD" : "",
- "color" : "C1"
- },
- "tcmalloc" : {
- "cmd_prefix" : "",
- "binary_suffix" : "",
- "LD_PRELOAD" : "targets/libtcmalloc.so",
- "color" : "C2"
- },
- "jemalloc" : {
- "cmd_prefix" : "",
- "binary_suffix" : "",
- "LD_PRELOAD" : "targets/libjemalloc.so",
- "color" : "C3"
- },
- }
diff --git a/targets/Makefile b/targets/Makefile
deleted file mode 100644
index 5df4999..0000000
--- a/targets/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-OBJDIR ?= obj
-
-CC ?= gcc
-
-WARNFLAGS ?= -Wall -Wextra
-COMMONFLAGS ?= -fno-builtin -fPIC -DPIC -pthread
-OPTFLAGS ?= -O3 -DNDEBUG
-
-CFLAGS ?= $(OPTFLAGS) $(WARNFLAGS) $(COMMONFLAGS)
-
-LDFLAGS ?= -pthread -static-libgcc
-
-.PHONY: all clean
-
-all: $(OBJDIR)
- @echo building targets
-
-$(OBJDIR):
- mkdir $@
-
-clean:
- rm -rf $(OBJDIR)