You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
6.2 KiB
264 lines
6.2 KiB
#include "cache.h" |
|
#include "parse-options.h" |
|
|
|
static int single; |
|
static int multi; |
|
static int count = 1; |
|
static int dump; |
|
static int perf; |
|
static int analyze; |
|
static int analyze_step; |
|
|
|
/* |
|
* Dump the contents of the "dir" and "name" hash tables to stdout. |
|
* If you sort the result, you can compare it with the other type |
|
* mode and verify that both single and multi produce the same set. |
|
*/ |
|
static void dump_run(void) |
|
{ |
|
struct hashmap_iter iter_dir; |
|
struct hashmap_iter iter_cache; |
|
|
|
/* Stolen from name-hash.c */ |
|
struct dir_entry { |
|
struct hashmap_entry ent; |
|
struct dir_entry *parent; |
|
int nr; |
|
unsigned int namelen; |
|
char name[FLEX_ARRAY]; |
|
}; |
|
|
|
struct dir_entry *dir; |
|
struct cache_entry *ce; |
|
|
|
read_cache(); |
|
if (single) { |
|
test_lazy_init_name_hash(&the_index, 0); |
|
} else { |
|
int nr_threads_used = test_lazy_init_name_hash(&the_index, 1); |
|
if (!nr_threads_used) |
|
die("non-threaded code path used"); |
|
} |
|
|
|
dir = hashmap_iter_first(&the_index.dir_hash, &iter_dir); |
|
while (dir) { |
|
printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name); |
|
dir = hashmap_iter_next(&iter_dir); |
|
} |
|
|
|
ce = hashmap_iter_first(&the_index.name_hash, &iter_cache); |
|
while (ce) { |
|
printf("name %08x %s\n", ce->ent.hash, ce->name); |
|
ce = hashmap_iter_next(&iter_cache); |
|
} |
|
|
|
discard_cache(); |
|
} |
|
|
|
/* |
|
* Run the single or multi threaded version "count" times and |
|
* report on the time taken. |
|
*/ |
|
static uint64_t time_runs(int try_threaded) |
|
{ |
|
uint64_t t0, t1, t2; |
|
uint64_t sum = 0; |
|
uint64_t avg; |
|
int nr_threads_used; |
|
int i; |
|
|
|
for (i = 0; i < count; i++) { |
|
t0 = getnanotime(); |
|
read_cache(); |
|
t1 = getnanotime(); |
|
nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded); |
|
t2 = getnanotime(); |
|
|
|
sum += (t2 - t1); |
|
|
|
if (try_threaded && !nr_threads_used) |
|
die("non-threaded code path used"); |
|
|
|
if (nr_threads_used) |
|
printf("%f %f %d multi %d\n", |
|
((double)(t1 - t0))/1000000000, |
|
((double)(t2 - t1))/1000000000, |
|
the_index.cache_nr, |
|
nr_threads_used); |
|
else |
|
printf("%f %f %d single\n", |
|
((double)(t1 - t0))/1000000000, |
|
((double)(t2 - t1))/1000000000, |
|
the_index.cache_nr); |
|
fflush(stdout); |
|
|
|
discard_cache(); |
|
} |
|
|
|
avg = sum / count; |
|
if (count > 1) |
|
printf("avg %f %s\n", |
|
(double)avg/1000000000, |
|
(try_threaded) ? "multi" : "single"); |
|
|
|
return avg; |
|
} |
|
|
|
/* |
|
* Try a series of runs varying the "istate->cache_nr" and |
|
* try to find a good value for the multi-threaded criteria. |
|
*/ |
|
static void analyze_run(void) |
|
{ |
|
uint64_t t1s, t1m, t2s, t2m; |
|
int cache_nr_limit; |
|
int nr_threads_used; |
|
int i; |
|
int nr; |
|
|
|
read_cache(); |
|
cache_nr_limit = the_index.cache_nr; |
|
discard_cache(); |
|
|
|
nr = analyze; |
|
while (1) { |
|
uint64_t sum_single = 0; |
|
uint64_t sum_multi = 0; |
|
uint64_t avg_single; |
|
uint64_t avg_multi; |
|
|
|
if (nr > cache_nr_limit) |
|
nr = cache_nr_limit; |
|
|
|
for (i = 0; i < count; i++) { |
|
read_cache(); |
|
the_index.cache_nr = nr; /* cheap truncate of index */ |
|
t1s = getnanotime(); |
|
test_lazy_init_name_hash(&the_index, 0); |
|
t2s = getnanotime(); |
|
sum_single += (t2s - t1s); |
|
the_index.cache_nr = cache_nr_limit; |
|
discard_cache(); |
|
|
|
read_cache(); |
|
the_index.cache_nr = nr; /* cheap truncate of index */ |
|
t1m = getnanotime(); |
|
nr_threads_used = test_lazy_init_name_hash(&the_index, 1); |
|
t2m = getnanotime(); |
|
sum_multi += (t2m - t1m); |
|
the_index.cache_nr = cache_nr_limit; |
|
discard_cache(); |
|
|
|
if (!nr_threads_used) |
|
printf(" [size %8d] [single %f] non-threaded code path used\n", |
|
nr, ((double)(t2s - t1s))/1000000000); |
|
else |
|
printf(" [size %8d] [single %f] %c [multi %f %d]\n", |
|
nr, |
|
((double)(t2s - t1s))/1000000000, |
|
(((t2s - t1s) < (t2m - t1m)) ? '<' : '>'), |
|
((double)(t2m - t1m))/1000000000, |
|
nr_threads_used); |
|
fflush(stdout); |
|
} |
|
if (count > 1) { |
|
avg_single = sum_single / count; |
|
avg_multi = sum_multi / count; |
|
if (!nr_threads_used) |
|
printf("avg [size %8d] [single %f]\n", |
|
nr, |
|
(double)avg_single/1000000000); |
|
else |
|
printf("avg [size %8d] [single %f] %c [multi %f %d]\n", |
|
nr, |
|
(double)avg_single/1000000000, |
|
(avg_single < avg_multi ? '<' : '>'), |
|
(double)avg_multi/1000000000, |
|
nr_threads_used); |
|
fflush(stdout); |
|
} |
|
|
|
if (nr >= cache_nr_limit) |
|
return; |
|
nr += analyze_step; |
|
} |
|
} |
|
|
|
int cmd_main(int argc, const char **argv) |
|
{ |
|
const char *usage[] = { |
|
"test-lazy-init-name-hash -d (-s | -m)", |
|
"test-lazy-init-name-hash -p [-c c]", |
|
"test-lazy-init-name-hash -a a [--step s] [-c c]", |
|
"test-lazy-init-name-hash (-s | -m) [-c c]", |
|
"test-lazy-init-name-hash -s -m [-c c]", |
|
NULL |
|
}; |
|
struct option options[] = { |
|
OPT_BOOL('s', "single", &single, "run single-threaded code"), |
|
OPT_BOOL('m', "multi", &multi, "run multi-threaded code"), |
|
OPT_INTEGER('c', "count", &count, "number of passes"), |
|
OPT_BOOL('d', "dump", &dump, "dump hash tables"), |
|
OPT_BOOL('p', "perf", &perf, "compare single vs multi"), |
|
OPT_INTEGER('a', "analyze", &analyze, "analyze different multi sizes"), |
|
OPT_INTEGER(0, "step", &analyze_step, "analyze step factor"), |
|
OPT_END(), |
|
}; |
|
const char *prefix; |
|
uint64_t avg_single, avg_multi; |
|
|
|
prefix = setup_git_directory(); |
|
|
|
argc = parse_options(argc, argv, prefix, options, usage, 0); |
|
|
|
/* |
|
* istate->dir_hash is only created when ignore_case is set. |
|
*/ |
|
ignore_case = 1; |
|
|
|
if (dump) { |
|
if (perf || analyze > 0) |
|
die("cannot combine dump, perf, or analyze"); |
|
if (count > 1) |
|
die("count not valid with dump"); |
|
if (single && multi) |
|
die("cannot use both single and multi with dump"); |
|
if (!single && !multi) |
|
die("dump requires either single or multi"); |
|
dump_run(); |
|
return 0; |
|
} |
|
|
|
if (perf) { |
|
if (analyze > 0) |
|
die("cannot combine dump, perf, or analyze"); |
|
if (single || multi) |
|
die("cannot use single or multi with perf"); |
|
avg_single = time_runs(0); |
|
avg_multi = time_runs(1); |
|
if (avg_multi > avg_single) |
|
die("multi is slower"); |
|
return 0; |
|
} |
|
|
|
if (analyze) { |
|
if (analyze < 500) |
|
die("analyze must be at least 500"); |
|
if (!analyze_step) |
|
analyze_step = analyze; |
|
if (single || multi) |
|
die("cannot use single or multi with analyze"); |
|
analyze_run(); |
|
return 0; |
|
} |
|
|
|
if (!single && !multi) |
|
die("require either -s or -m or both"); |
|
|
|
if (single) |
|
time_runs(0); |
|
if (multi) |
|
time_runs(1); |
|
|
|
return 0; |
|
}
|
|
|