add comment about cache analysis
This commit is contained in:
parent
48f333adfe
commit
8e2f918dd3
|
@ -51,7 +51,6 @@ void sampler_parallel(double (*sampler)(uint64_t* seed), double* results, int n_
|
||||||
// - xorshift can't start with 0
|
// - xorshift can't start with 0
|
||||||
// - the seeds should be reasonably separated and not correlated
|
// - the seeds should be reasonably separated and not correlated
|
||||||
cache_box[i].seed = (uint64_t)rand() * (UINT64_MAX / RAND_MAX);
|
cache_box[i].seed = (uint64_t)rand() * (UINT64_MAX / RAND_MAX);
|
||||||
// printf("#%ld: %lu\n",i, *seeds[i]);
|
|
||||||
|
|
||||||
// Other initializations tried:
|
// Other initializations tried:
|
||||||
// *seeds[i] = 1 + i;
|
// *seeds[i] = 1 + i;
|
||||||
|
@ -69,17 +68,40 @@ void sampler_parallel(double (*sampler)(uint64_t* seed), double* results, int n_
|
||||||
|
|
||||||
for (int j = lower_bound_inclusive; j < upper_bound_not_inclusive; j++) {
|
for (int j = lower_bound_inclusive; j < upper_bound_not_inclusive; j++) {
|
||||||
results[j] = sampler(&(cache_box[i].seed));
|
results[j] = sampler(&(cache_box[i].seed));
|
||||||
// In principle, these results[j] could also result in two threads competing for the same cache line.
|
/*
|
||||||
// In practice, though,
|
t starts at 0 and ends at T
|
||||||
// a) this would happen infrequently
|
at t=0,
|
||||||
// b) trying to unroll loops actually makes the code slower
|
thread i accesses: results[i*quotient +0],
|
||||||
// c) 8 results[j] are 8 doubles, which fit a cache line. If n_samples/n_threads
|
thread i+1 acccesses: results[(i+1)*quotient +0]
|
||||||
|
at t=T
|
||||||
|
thread i accesses: results[(i+1)*quotient -1]
|
||||||
|
thread i+1 acccesses: results[(i+2)*quotient -1]
|
||||||
|
The results[j] that are directly adjacent are
|
||||||
|
results[(i+1)*quotient -1] (accessed by thread i at time T)
|
||||||
|
results[(i+1)*quotient +0] (accessed by thread i+1 at time 0)
|
||||||
|
and these are themselves adjacent to
|
||||||
|
results[(i+1)*quotient -2] (accessed by thread i at time T-1)
|
||||||
|
results[(i+1)*quotient +1] (accessed by thread i+1 at time 2)
|
||||||
|
If T is large enough, which it is, two threads won't access the same
|
||||||
|
cache line at the same time.
|
||||||
|
Pictorially:
|
||||||
|
at t=0 ....i.........I.........
|
||||||
|
at t=T .............i.........I
|
||||||
|
and the two never overlap
|
||||||
|
Note that results[j] is a double, a double has 8 bytes (64 bits)
|
||||||
|
8 doubles fill a cache line of 64 bytes.
|
||||||
|
So we specifically won't get problems as long as n_samples/n_threads > 8
|
||||||
|
n_threads is normally 16, so n_samples > 128
|
||||||
|
Note also that this is only a problem in terms of speed, if n_samples<128
|
||||||
|
the results are still computed, it'll just be slower
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int j = divisor_multiple; j < n_samples; j++) {
|
for (int j = divisor_multiple; j < n_samples; j++) {
|
||||||
results[j] = sampler(&(cache_box[0].seed));
|
results[j] = sampler(&(cache_box[0].seed));
|
||||||
// we can just reuse a seed, this isn't problematic because we are not doing multithreading
|
// we can just reuse a seed,
|
||||||
|
// this isn't problematic because we;ve now stopped doing multithreading
|
||||||
}
|
}
|
||||||
|
|
||||||
free(cache_box);
|
free(cache_box);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user