summaryrefslogtreecommitdiff
path: root/benchmarks/gem_wsim.c
diff options
context:
space:
mode:
authorTvrtko Ursulin <tvrtko.ursulin@intel.com>2017-05-22 10:30:45 +0100
committerTvrtko Ursulin <tvrtko.ursulin@intel.com>2017-05-23 16:59:46 +0100
commit1c6c53c1e81cf9d91d2c3db0b67494db841a80c6 (patch)
tree9bf4a9b31f15ecacad78248509f1f5945eb843c4 /benchmarks/gem_wsim.c
parent01959de48a142139c0ed08cf32dc677dd4965779 (diff)
gem_wsim: Add global balancing mode
In this mode ('-G' on the command line) all balancing operations are routed via the first client so the complete balancing state is shared. In other words the overall balancing behaviours is like there is only one client submitting the aggregate workload. This can help with the observed metrics and lead to better balancing decisions in a lot of cases. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Diffstat (limited to 'benchmarks/gem_wsim.c')
-rw-r--r--benchmarks/gem_wsim.c159
1 files changed, 135 insertions, 24 deletions
diff --git a/benchmarks/gem_wsim.c b/benchmarks/gem_wsim.c
index ace06c15..b366a5d6 100644
--- a/benchmarks/gem_wsim.c
+++ b/benchmarks/gem_wsim.c
@@ -172,6 +172,10 @@ struct workload
struct igt_list requests[NUM_ENGINES];
unsigned int nrequest[NUM_ENGINES];
+ struct workload *global_wrk;
+ const struct workload_balancer *global_balancer;
+ pthread_mutex_t mutex;
+
union {
struct rtavg {
struct ewma_rt avg[NUM_ENGINES];
@@ -194,6 +198,7 @@ static int fd;
#define INITVCSRR (1<<5)
#define SYNCEDCLIENTS (1<<6)
#define HEARTBEAT (1<<7)
+#define GLOBAL_BALANCE (1<<8)
#define SEQNO_IDX(engine) ((engine) * 16)
#define SEQNO_OFFSET(engine) (SEQNO_IDX(engine) * sizeof(uint32_t))
@@ -729,7 +734,10 @@ eb_update_flags(struct w_step *w, enum intel_engine_id engine,
static struct drm_i915_gem_exec_object2 *
get_status_objects(struct workload *wrk)
{
- return wrk->status_object;
+ if (wrk->flags & GLOBAL_BALANCE)
+ return wrk->global_wrk->status_object;
+ else
+ return wrk->status_object;
}
static void
@@ -809,22 +817,31 @@ prepare_workload(unsigned int id, struct workload *wrk, unsigned int flags)
wrk->id = id;
wrk->prng = rand();
+ wrk->run = true;
if (flags & INITVCSRR)
wrk->vcs_rr = id & 1;
- if (flags & SEQNO) {
- uint32_t handle = gem_create(fd, 4096);
-
- gem_set_caching(fd, handle, I915_CACHING_CACHED);
- wrk->status_object[0].handle = handle;
- wrk->status_page = gem_mmap__cpu(fd, handle, 0, 4096,
- PROT_READ);
+ if (flags & GLOBAL_BALANCE) {
+ int ret = pthread_mutex_init(&wrk->mutex, NULL);
+ igt_assert(ret == 0);
+ }
- handle = gem_create(fd, 4096);
- wrk->status_object[1].handle = handle;
- wrk->status_cs = gem_mmap__wc(fd, handle,
- 0, 4096, PROT_WRITE);
+ if (flags & SEQNO) {
+ if (!(flags & GLOBAL_BALANCE) || id == 0) {
+ uint32_t handle;
+
+ handle = gem_create(fd, 4096);
+ gem_set_caching(fd, handle, I915_CACHING_CACHED);
+ wrk->status_object[0].handle = handle;
+ wrk->status_page = gem_mmap__cpu(fd, handle, 0, 4096,
+ PROT_READ);
+
+ handle = gem_create(fd, 4096);
+ wrk->status_object[1].handle = handle;
+ wrk->status_cs = gem_mmap__wc(fd, handle,
+ 0, 4096, PROT_WRITE);
+ }
}
for (i = 0, w = wrk->steps; i < wrk->nr_steps; i++, w++) {
@@ -895,13 +912,34 @@ static enum intel_engine_id get_vcs_engine(unsigned int n)
static uint32_t new_seqno(struct workload *wrk, enum intel_engine_id engine)
{
- return ++wrk->seqno[engine];
+ uint32_t seqno;
+ int ret;
+
+ if (wrk->flags & GLOBAL_BALANCE) {
+ igt_assert(wrk->global_wrk);
+ wrk = wrk->global_wrk;
+
+ ret = pthread_mutex_lock(&wrk->mutex);
+ igt_assert(ret == 0);
+ }
+
+ seqno = ++wrk->seqno[engine];
+
+ if (wrk->flags & GLOBAL_BALANCE) {
+ ret = pthread_mutex_unlock(&wrk->mutex);
+ igt_assert(ret == 0);
+ }
+
+ return seqno;
}
static uint32_t
current_seqno(struct workload *wrk, enum intel_engine_id engine)
{
- return wrk->seqno[engine];
+ if (wrk->flags & GLOBAL_BALANCE)
+ return wrk->global_wrk->seqno[engine];
+ else
+ return wrk->seqno[engine];
}
#define READ_ONCE(x) (*(volatile typeof(x) *)(&(x)))
@@ -909,7 +947,10 @@ current_seqno(struct workload *wrk, enum intel_engine_id engine)
static uint32_t
read_status_page(struct workload *wrk, unsigned int idx)
{
- return READ_ONCE(wrk->status_page[idx]);
+ if (wrk->flags & GLOBAL_BALANCE)
+ return READ_ONCE(wrk->global_wrk->status_page[idx]);
+ else
+ return READ_ONCE(wrk->status_page[idx]);
}
static uint32_t
@@ -994,8 +1035,8 @@ __qd_balance(const struct workload_balancer *balancer,
engine = __qd_select_engine(wrk, qd, random);
#ifdef DEBUG
- printf("qd_balance: 1:%ld 2:%ld rr:%u = %u\t(%lu - %u) (%lu - %u)\n",
- qd[VCS1], qd[VCS2], wrk->vcs_rr, engine,
+ printf("qd_balance[%u]: 1:%ld 2:%ld rr:%u = %u\t(%u - %u) (%u - %u)\n",
+ wrk->id, qd[VCS1], qd[VCS2], wrk->vcs_rr, engine,
current_seqno(wrk, VCS1), current_gpu_seqno(wrk, VCS1),
current_seqno(wrk, VCS2), current_gpu_seqno(wrk, VCS2));
#endif
@@ -1033,7 +1074,14 @@ qdavg_balance(const struct workload_balancer *balancer,
qd[engine] = ewma_rt_read(&wrk->rt.avg[engine]);
}
- return __qd_select_engine(wrk, qd, false);
+ engine = __qd_select_engine(wrk, qd, false);
+#ifdef DEBUG
+ printf("qdavg_balance[%u]: 1:%ld 2:%ld rr:%u = %u\t(%u - %u) (%u - %u)\n",
+ wrk->id, qd[VCS1], qd[VCS2], wrk->vcs_rr, engine,
+ current_seqno(wrk, VCS1), current_gpu_seqno(wrk, VCS1),
+ current_seqno(wrk, VCS2), current_gpu_seqno(wrk, VCS2));
+#endif
+ return engine;
}
static enum intel_engine_id
@@ -1229,6 +1277,48 @@ static const struct workload_balancer all_balancers[] = {
},
};
+static unsigned int
+global_get_qd(const struct workload_balancer *balancer,
+ struct workload *wrk, enum intel_engine_id engine)
+{
+ igt_assert(wrk->global_wrk);
+ igt_assert(wrk->global_balancer);
+
+ return wrk->global_balancer->get_qd(wrk->global_balancer,
+ wrk->global_wrk, engine);
+}
+
+static enum intel_engine_id
+global_balance(const struct workload_balancer *balancer,
+ struct workload *wrk, struct w_step *w)
+{
+ enum intel_engine_id engine;
+ int ret;
+
+ igt_assert(wrk->global_wrk);
+ igt_assert(wrk->global_balancer);
+
+ wrk = wrk->global_wrk;
+
+ ret = pthread_mutex_lock(&wrk->mutex);
+ igt_assert(ret == 0);
+
+ engine = wrk->global_balancer->balance(wrk->global_balancer, wrk, w);
+
+ ret = pthread_mutex_unlock(&wrk->mutex);
+ igt_assert(ret == 0);
+
+ return engine;
+}
+
+static const struct workload_balancer global_balancer = {
+ .id = ~0,
+ .name = "global",
+ .desc = "Global balancer",
+ .get_qd = global_get_qd,
+ .balance = global_balance,
+ };
+
static void
update_bb_seqno(struct w_step *w, enum intel_engine_id engine, uint32_t seqno)
{
@@ -1713,7 +1803,9 @@ static void print_help(void)
" -2 Remap VCS2 to BCS.\n"
" -R Round-robin initial VCS assignment per client.\n"
" -S Synchronize the sequence of random batch durations between\n"
-" clients."
+" clients.\n"
+" -G Global load balancing - a single load balancer will be shared\n"
+" between all clients and there will be a single seqno domain."
);
}
@@ -1848,7 +1940,7 @@ int main(int argc, char **argv)
init_clocks();
- while ((c = getopt(argc, argv, "hqv2RSHxc:n:r:w:W:a:t:b:p:")) != -1) {
+ while ((c = getopt(argc, argv, "hqv2RSHxGc:n:r:w:W:a:t:b:p:")) != -1) {
switch (c) {
case 'W':
if (master_workload >= 0) {
@@ -1907,6 +1999,9 @@ int main(int argc, char **argv)
case 'H':
flags |= HEARTBEAT;
break;
+ case 'G':
+ flags |= GLOBAL_BALANCE;
+ break;
case 'b':
i = find_balancer_by_name(optarg);
if (i < 0) {
@@ -1964,6 +2059,13 @@ int main(int argc, char **argv)
return 1;
}
+ if ((flags & GLOBAL_BALANCE) && !balancer) {
+ if (verbose)
+ fprintf(stderr,
+ "Balancer not specified in global balancing mode!\n");
+ return 1;
+ }
+
if (append_workload_arg) {
append_workload_arg = load_workload_descriptor(append_workload_arg);
if (!append_workload_arg) {
@@ -2017,7 +2119,10 @@ int main(int argc, char **argv)
printf("%u client%s.\n", clients, clients > 1 ? "s" : "");
if (flags & SWAPVCS)
printf("Swapping VCS rings between clients.\n");
- if (balancer)
+ if (flags & GLOBAL_BALANCE)
+ printf("Using %s balancer in global mode.\n",
+ balancer->name);
+ else if (balancer)
printf("Using %s balancer.\n", balancer->name);
}
@@ -2035,15 +2140,21 @@ int main(int argc, char **argv)
if (flags & SWAPVCS && i & 1)
flags_ &= ~SWAPVCS;
- prepare_workload(i, w[i], flags_);
+ if (flags & GLOBAL_BALANCE) {
+ w[i]->balancer = &global_balancer;
+ w[i]->global_wrk = w[0];
+ w[i]->global_balancer = balancer;
+ } else {
+ w[i]->balancer = balancer;
+ }
w[i]->flags = flags;
w[i]->repeat = repeat;
- w[i]->balancer = balancer;
- w[i]->run = true;
w[i]->background = master_workload >= 0 && i != master_workload;
w[i]->print_stats = verbose > 1 ||
(verbose > 0 && master_workload == i);
+
+ prepare_workload(i, w[i], flags_);
}
gem_quiescent_gpu(fd);