1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-25 00:07:09 -07:00

Adding multi-threading to djbench in order to test performance with thread contention.

Copied from Perforce
 Change: 182778
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Richard Brooksby 2013-06-16 21:20:29 +01:00
parent 8ef0a0be21
commit b0e4e8528f
2 changed files with 85 additions and 30 deletions

View file

@ -15,15 +15,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <alloca.h>
#include <pthread.h>
#include "getopt.h"
#include "testlib.h"
#include "mps.c"
#define MUST(expr) \
do { \
mps_res_t res = (expr); \
if (res != MPS_RES_OK) { \
fprintf(stderr, #expr " returned %d\n", res); \
exit(EXIT_FAILURE); \
} \
} while(0)
static mps_arena_t arena;
static mps_pool_t pool;
static mps_ap_t ap;
/* The benchmark behaviour is defined as a macro in order to give realistic
@ -31,6 +40,7 @@ static mps_ap_t ap;
MPS functions. */
static rnd_state_t seed = 0; /* random number seed */
static unsigned nthreads = 1; /* threads */
static unsigned niter = 50; /* iterations */
static unsigned npass = 100; /* passes over blocks */
static unsigned nblocks = 64; /* number of blocks */
@ -40,8 +50,8 @@ static unsigned rinter = 75; /* pass interval for recursion */
static unsigned rmax = 10; /* maximum recursion depth */
#define DJRUN(fname, alloc, free) \
static unsigned fname##_inner(unsigned depth, unsigned r) { \
struct {void *p; size_t s;} *blocks = alloca(sizeof(*blocks) * nblocks); \
static unsigned fname##_inner(mps_ap_t ap, unsigned depth, unsigned r) { \
struct {void *p; size_t s;} *blocks = alloca(sizeof(blocks[0]) * nblocks); \
unsigned j, k; \
\
for (k = 0; k < nblocks; ++k) { \
@ -65,7 +75,7 @@ static unsigned rmax = 10; /* maximum recursion depth */
} \
if (rinter > 0 && depth > 0 && ++r % rinter == 0) { \
/* putchar('>'); fflush(stdout); */ \
r = fname##_inner(depth - 1, r); \
r = fname##_inner(ap, depth - 1, r); \
/* putchar('<'); fflush(stdout); */ \
} \
} \
@ -79,10 +89,16 @@ static unsigned rmax = 10; /* maximum recursion depth */
return r; \
} \
\
static void fname(void) { \
static void *fname(void *p) { \
unsigned i; \
mps_ap_t ap = NULL; \
if (pool != NULL) \
MUST(mps_ap_create_k(&ap, pool, mps_args_none)); \
for (i = 0; i < niter; ++i) \
(void)fname##_inner(rmax, 0); \
(void)fname##_inner(ap, rmax, 0); \
if (ap != NULL) \
mps_ap_destroy(ap); \
return p; \
}
@ -115,34 +131,59 @@ DJRUN(dj_alloc, MPS_ALLOC, MPS_FREE)
DJRUN(dj_reserve, RESERVE_ALLOC, RESERVE_FREE)
typedef void *(*dj_t)(void *);
/* Wrap a call to dj benchmark that doesn't require MPS setup */
static void weave(dj_t dj)
{
pthread_t *threads = alloca(sizeof(threads[0]) * nthreads);
unsigned t;
for (t = 0; t < nthreads; ++t) {
int err = pthread_create(&threads[t], NULL, dj, NULL);
if (err != 0) {
fprintf(stderr, "Unable to create thread: %d\n", err);
exit(EXIT_FAILURE);
}
}
for (t = 0; t < nthreads; ++t) {
int err = pthread_join(threads[t], NULL);
if (err != 0) {
fprintf(stderr, "Unable to join thread: %d\n", err);
exit(EXIT_FAILURE);
}
}
}
static void wrap(void (*dj)(void), mps_class_t dummy, const char *name)
static void watch(dj_t dj, const char *name)
{
clock_t start, finish;
(void)dummy;
start = clock();
dj();
if (nthreads == 1)
dj(NULL);
else
weave(dj);
finish = clock();
printf("%s: %g\n", name, (double)(finish - start) / CLOCKS_PER_SEC);
}
/* Wrap a call to dj benchmark that doesn't require MPS setup */
static void wrap(dj_t dj, mps_class_t dummy, const char *name)
{
(void)dummy;
pool = NULL;
watch(dj, name);
}
/* Wrap a call to a dj benchmark that requires MPS setup */
#define MUST(expr) \
do { \
mps_res_t res = (expr); \
if (res != MPS_RES_OK) { \
fprintf(stderr, #expr " returned %d\n", res); \
exit(EXIT_FAILURE); \
} \
} while(0)
static void arena_wrap(void (*dj)(void), mps_class_t pool_class, const char *name)
static void arena_wrap(dj_t dj, mps_class_t pool_class, const char *name)
{
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 256ul * 1024 * 1024); /* FIXME: Why is there no default? */
@ -150,9 +191,7 @@ static void arena_wrap(void (*dj)(void), mps_class_t pool_class, const char *nam
MUST(mps_arena_create_k(&arena, mps_arena_class_vm(), args));
} MPS_ARGS_END(args);
MUST(mps_pool_create_k(&pool, arena, pool_class, mps_args_none));
MUST(mps_ap_create_k(&ap, pool, mps_args_none));
wrap(dj, NULL, name);
mps_ap_destroy(ap);
watch(dj, name);
mps_pool_destroy(pool);
mps_arena_destroy(arena);
}
@ -162,6 +201,7 @@ static void arena_wrap(void (*dj)(void), mps_class_t pool_class, const char *nam
static struct option longopts[] = {
{"help", no_argument, NULL, 'h'},
{"nthreads",required_argument, NULL, 't'},
{"niter", required_argument, NULL, 'i'},
{"npass", required_argument, NULL, 'p'},
{"nblocks", required_argument, NULL, 'b'},
@ -183,8 +223,8 @@ static mps_class_t dummy_class(void)
static struct {
const char *name;
void (*wrap)(void (*)(void), mps_class_t, const char *name);
void (*dj)(void);
void (*wrap)(dj_t, mps_class_t, const char *name);
dj_t dj;
mps_class_t (*pool_class)(void);
} pools[] = {
{"mvt", arena_wrap, dj_reserve, mps_class_mvt},
@ -203,8 +243,11 @@ int main(int argc, char *argv[]) {
seed = rnd_seed();
while ((ch = getopt_long(argc, argv, "hi:p:b:s:a:r:d:x:", longopts, NULL)) != -1)
while ((ch = getopt_long(argc, argv, "ht:i:p:b:s:a:r:d:x:", longopts, NULL)) != -1)
switch (ch) {
case 't':
nthreads = (unsigned)strtoul(optarg, NULL, 10);
break;
case 'i':
niter = (unsigned)strtoul(optarg, NULL, 10);
break;
@ -233,6 +276,8 @@ int main(int argc, char *argv[]) {
fprintf(stderr,
"Usage: %s [option...] [test...]\n"
"Options:\n"
" -t n, --nthreads=n\n"
" Launch n threads each running the test\n"
" -i n, --niter=n\n"
" Iterate each test n times (default %u).\n"
" -p n, --npass=n\n"

View file

@ -59,7 +59,7 @@
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "--seed=1857658610"
argument = "-t 5"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
@ -87,10 +87,10 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
shouldUseLaunchSchemeArgsEnv = "NO"
savedToolIdentifier = "/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/Resources/templates/Time Profiler.tracetemplate"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
buildConfiguration = "WE"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
@ -101,6 +101,16 @@
ReferencedContainer = "container:mps.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-t 10"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "mvff"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">