All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
To: Chris Wilson <chris@chris-wilson.co.uk>, intel-gfx@lists.freedesktop.org
Cc: igt-dev@lists.freedesktop.org
Subject: Re: [igt-dev] [Intel-gfx] [PATCH i-g-t] benchmarks/wsim: Simulate and interpret .wsim
Date: Fri, 11 May 2018 09:31:52 +0100	[thread overview]
Message-ID: <203943cb-da94-14e0-bc62-4705ef4e8a8c@linux.intel.com> (raw)
In-Reply-To: <20180511071141.24581-1-chris@chris-wilson.co.uk>


On 11/05/2018 08:11, Chris Wilson wrote:
> A little tool I've been meaning to write for a while... Convert the
> .wsim into their dag and find the longest chains and evaluate them on an
> simulated machine.

Very cool!

But I think you need to handle the 's' command which appears in the 
interesting workloads. Maybe you could just fake it as a zero duration 
batch with a data dependency.

Fence related commands would also be useful but more difficult I guess. 
As would throttling.

Delays could maybe be faked as batches as well by adding input 
dependency to everything preceding it.

Regards,

Tvrtko

> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   benchmarks/Makefile.sources |   1 +
>   benchmarks/sim_wsim.c       | 434 ++++++++++++++++++++++++++++++++++++
>   2 files changed, 435 insertions(+)
>   create mode 100644 benchmarks/sim_wsim.c
> 
> diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
> index d150035aa..b80a7644c 100644
> --- a/benchmarks/Makefile.sources
> +++ b/benchmarks/Makefile.sources
> @@ -17,6 +17,7 @@ benchmarks_prog_list =			\
>   	gem_wsim			\
>   	kms_vblank			\
>   	prime_lookup			\
> +	sim_wsim			\
>   	vgem_mmap			\
>   	$(NULL)
>   
> diff --git a/benchmarks/sim_wsim.c b/benchmarks/sim_wsim.c
> new file mode 100644
> index 000000000..cb8e7adc4
> --- /dev/null
> +++ b/benchmarks/sim_wsim.c
> @@ -0,0 +1,434 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "igt_aux.h"
> +
> +#if 0
> +#define DBG(...) printf(__VA_ARGS__)
> +#else
> +#define DBG(...) do { } while(0)
> +#endif
> +
> +struct dependency {
> +	struct task *signal;
> +	struct igt_list link;
> +};
> +
> +struct task {
> +	struct igt_list link;
> +	struct igt_list sched;
> +	struct igt_list signals;
> +	int step;
> +	int ctx;
> +	int class;
> +	int instance;
> +	long min, max;
> +	long duration;
> +	long deadline;
> +	bool visited;
> +};
> +
> +struct work {
> +	struct task **tasks;
> +	unsigned int count, size;
> +
> +	struct igt_list ends;
> +};
> +
> +static void add_dependency(struct task *task, struct task *signal)
> +{
> +	struct dependency *dep;
> +
> +	DBG("%s %d (context %d, engine %d) -> %d (context %d, engine %d)\n",
> +	    __func__,
> +	    signal->step, signal->ctx, signal->class,
> +	    task->step, task->ctx, task->class);
> +
> +	dep = malloc(sizeof(*dep));
> +	dep->signal = signal;
> +	igt_list_add(&dep->link, &task->signals);
> +	igt_list_del(&signal->link);
> +	igt_list_init(&signal->link);
> +}
> +
> +enum class {
> +	RCS,
> +	BCS,
> +	VCS,
> +	VECS,
> +};
> +
> +static void add_task(struct work *work, char *line)
> +{
> +	static const char *engines[] = {
> +		[RCS]  = "rcs",
> +		[BCS]  = "bcs",
> +		[VCS]  = "vcs",
> +		[VECS] = "vecs",
> +	};
> +	struct task *task;
> +	char *token;
> +	int i;
> +
> +	task = malloc(sizeof(*task));
> +
> +	igt_list_init(&task->signals);
> +	igt_list_init(&task->sched);
> +	task->step = work->count;
> +	task->visited = false;
> +
> +	/*
> +	 * 1.RCS.2800-3100.-1.0
> +	 * - context
> +	 * - engine
> +	 * - delay
> +	 * - dependencies
> +	 * - sync
> +	 */
> +	DBG("line='%s'\n", line);
> +
> +	/* context */
> +	token = strtok(line, ".");
> +	DBG("context='%s'\n", token);
> +	task->ctx  = atoi(token);
> +	if (!task->ctx)
> +		return;
> +
> +	/* engine */
> +	token = strtok(NULL, ".");
> +	DBG("engine='%s'\n", token);
> +	task->class = -1;
> +	for (i = 0; i < sizeof(engines)/sizeof(*engines); i++) {
> +		const int len = strlen(engines[i]);
> +		if (!strncasecmp(token, engines[i], len)) {
> +			task->class = i;
> +			if (token[len])
> +				task->instance = atoi(token + len);
> +			else
> +				task->instance = -1;
> +			break;
> +		}
> +	}
> +
> +	/* delay */
> +	token = strtok(NULL, ".");
> +	DBG("delay='%s'\n", token);
> +	task->min = strtol(token, &token, 0);
> +	if (*token)
> +		task->max = strtol(token + 1, NULL, 0);
> +	else
> +		task->max = task->min;
> +	task->duration = (task->min + task->max) / 2;
> +	DBG("min=%lu, max=%lu; duration=%lu\n", task->min, task->max, task->duration);
> +
> +	/* dependencies */
> +	token = strtok(NULL, ".");
> +	DBG("deps='%s'\n", token);
> +	while ((i = strtol(token, &token, 0))) {
> +		add_dependency(task, work->tasks[work->count + i]);
> +		if (*token)
> +			token++;
> +	}
> +
> +	/* add a dependency for the context+engine timeline */
> +	for (i = work->count; --i >= 0; ) {
> +		if (work->tasks[i]->ctx == task->ctx &&
> +		    work->tasks[i]->class == task->class) {
> +			add_dependency(task, work->tasks[i]);
> +			break;
> +		}
> +	}
> +
> +	igt_list_add(&task->link, &work->ends);
> +	work->tasks[work->count++] = task;
> +}
> +
> +static struct work *parse_work(FILE *file)
> +{
> +	struct work *work;
> +	char *line = NULL;
> +	size_t len = 0;
> +
> +	work = malloc(sizeof(*work));
> +	igt_list_init(&work->ends);
> +
> +	work->size = 64;
> +	work->count = 0;
> +	work->tasks = malloc(sizeof(*work->tasks) * work->size);
> +
> +	while (getline(&line, &len, file) != -1) {
> +		if (work->count == work->size) {
> +			work->tasks = realloc(work->tasks,
> +					      sizeof(*work->tasks) * work->size);
> +			work->size *= 2;
> +		}
> +		add_task(work, line);
> +	}
> +
> +	free(line);
> +
> +	DBG("%d tasks\n", work->count);
> +	return work;
> +}
> +
> +static unsigned long sum_durations(struct task *task)
> +{
> +	unsigned long max_duration = 0;
> +	struct task *signal = NULL;
> +	struct dependency *dep;
> +
> +	igt_list_for_each(dep, &task->signals, link) {
> +		if (dep->signal->duration > max_duration) {
> +			signal = dep->signal;
> +			max_duration = signal->duration;
> +		}
> +	}
> +
> +	return task->duration + (signal ? sum_durations(signal) : 0);
> +}
> +
> +static void ideal_depth(struct work *work)
> +{
> +	unsigned long total_duration;
> +	unsigned long max_duration;
> +	struct task *task;
> +	int i;
> +
> +	/*
> +	 * The ideal depth is the longest chain of dependencies as the
> +	 * dependency chain requires sequential task execution. Each
> +	 * chain is assumed to be run in parallel on an infinite set of
> +	 * engines, so the ratelimiting step is its longest path.
> +	 */
> +	max_duration = 0;
> +	igt_list_for_each(task, &work->ends, link) {
> +		unsigned long duration = sum_durations(task);
> +		if (duration > max_duration)
> +			max_duration = duration;
> +	}
> +
> +	total_duration = 0;
> +	for (i = 0; i < work->count; i++)
> +		total_duration += work->tasks[i]->duration;
> +
> +	printf("Single client\n");
> +	printf("   total duration %luus; %.2f wps\n", total_duration, 1e6/total_duration);
> +	printf("   ideal duration %luus; %.2f wps\n", max_duration, 1e6/max_duration);
> +}
> +
> +struct sim_class {
> +	int ninstance;
> +	unsigned int instances[4];
> +};
> +
> +static void single_client(struct work *work)
> +{
> +	struct sim_class sim[] = {
> +		[RCS]  = { 1 },
> +		[BCS]  = { 1 },
> +		[VCS]  = { 2 },
> +		[VECS] = { 1 },
> +	}, *class;
> +	IGT_LIST(sched);
> +	struct task *task;
> +	unsigned long max;
> +	int i, j;
> +
> +	for (i = 0; i < work->count; i++)
> +		igt_list_init(&work->tasks[i]->sched);
> +
> +	igt_list_for_each(task, &work->ends, link) {
> +		igt_list_add_tail(&task->sched, &sched);
> +	}
> +
> +	igt_list_for_each(task, &sched, sched) {
> +		struct dependency *dep;
> +
> +		igt_list_for_each(dep, &task->signals, link)
> +			igt_list_move_tail(&dep->signal->sched, &sched);
> +	}
> +
> +	igt_list_for_each_reverse(task, &sched, sched) {
> +		struct dependency *dep;
> +		int instance;
> +
> +		class = &sim[task->class];
> +		max = class->instances[0];
> +
> +		instance = task->instance;
> +		if (instance < 0) {
> +			instance = 0;
> +			for (i = 1; i < class->ninstance; i++) {
> +				if (class->instances[i] < max) {
> +					max = class->instances[i];
> +					instance = i;
> +				}
> +			}
> +		}
> +
> +		/*
> +		 * Greedy (first available), not true optimal scheduling.
> +		 *
> +		 * For optimal, we do have to compute the global optimal
> +		 * ordering by checking every permutation...
> +		 */
> +		igt_list_for_each(dep, &task->signals, link) {
> +			if (dep->signal->deadline > max)
> +				max = dep->signal->deadline;
> +		}
> +
> +		DBG("task %d: engine %d, instance %d; finish %lu\n",
> +		    task->step, task->class, instance, max);
> +
> +		task->deadline = max + task->duration;
> +		class->instances[instance] = task->deadline;
> +	}
> +
> +	max = 0;
> +	for (i = 0; i < sizeof(sim)/sizeof(sim[0]); i++) {
> +		class = &sim[i];
> +		for (j = 0; j < class->ninstance; j++) {
> +			if (class->instances[j] > max)
> +				max = class->instances[j];
> +		}
> +	}
> +
> +	printf("Simulated client:\n");
> +	printf("   duration %luus; %.2f wps\n", max, 1e6/max);
> +}
> +
> +static void packed_clients(struct work *work)
> +{
> +	struct sim_class sim[] = {
> +		[RCS]  = { 1 },
> +		[BCS]  = { 1 },
> +		[VCS]  = { 2 },
> +		[VECS] = { 1 },
> +	}, *class;
> +	IGT_LIST(sched);
> +	struct task *task;
> +	unsigned long min;
> +	int i, j;
> +
> +	for (i = 0; i < work->count; i++)
> +		igt_list_init(&work->tasks[i]->sched);
> +
> +	igt_list_for_each(task, &work->ends, link)
> +		igt_list_add_tail(&task->sched, &sched);
> +
> +	igt_list_for_each(task, &sched, sched) {
> +		struct dependency *dep;
> +
> +		igt_list_for_each(dep, &task->signals, link)
> +			igt_list_move_tail(&dep->signal->sched, &sched);
> +	}
> +
> +	/*
> +	 * Compute the maximum duration required on any engine.
> +	 *
> +	 * With sufficient clients forcing maximum occupancy under their weight,
> +	 * the ratelimiting step becomes a single engine and how many clients
> +	 * it takes to fill.
> +	 */
> +	igt_list_for_each_reverse(task, &sched, sched) {
> +		int instance;
> +
> +		class = &sim[task->class];
> +		instance = task->instance;
> +		if (instance < 0) {
> +			instance = 0;
> +			min = class->instances[0];
> +			for (i = 1; i < class->ninstance; i++) {
> +				if (class->instances[i] < min) {
> +					min = class->instances[i];
> +					instance = i;
> +				}
> +			}
> +		}
> +
> +		class->instances[instance] += task->duration;
> +	}
> +
> +	min = 0;
> +	for (i = 0; i < sizeof(sim)/sizeof(sim[0]); i++) {
> +		class = &sim[i];
> +		for (j = 0; j < class->ninstance; j++) {
> +			if (class->instances[j] > min)
> +				min = class->instances[j];
> +		}
> +	}
> +
> +	printf("Packed clients:\n");
> +	printf("   duration %luus; %.2f wps\n", min, 1e6/min);
> +}
> +
> +static void graphviz(struct work *work)
> +{
> +#if 0
> +	int i, j;
> +
> +	printf("digraph {\n");
> +	printf("  rankdir=LR;\n");
> +	printf("  splines=line;\n");
> +	printf("\n");
> +
> +	for (i = 0; i < work->count; i++) {
> +		struct task *task = work->tasks[i];
> +
> +		if (task->visited)
> +			goto skip;
> +
> +		printf("  subgraph cluster_%d {\n", task->ctx);
> +		printf("    label=\"Context %d\"\n", task->ctx);
> +		for (j = i; j < work->count; j++) {
> +			if (work->tasks[j]->ctx == task->ctx) {
> +				printf("    task_%03d;\n", j);
> +				work->tasks[j]->visited = true;
> +			}
> +		}
> +		printf("  }\n\n");
> +
> +skip:
> +		task->visited = false;
> +	}
> +
> +	for (i = 0; i < work->count; i++) {
> +		struct task *task = work->tasks[i];
> +		struct dependency *dep;
> +
> +		igt_list_for_each(dep, &task->signals, link) {
> +			printf("  task_%03d -> task_%03d;\n",
> +			       dep->signal->step, task->step);
> +		}
> +	}
> +
> +	printf("}\n");
> +#endif
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int i;
> +
> +	for (i = 1; i < argc; i++) {
> +		FILE *file = fopen(argv[i], "r");
> +		struct work *work;
> +
> +		if (!file) {
> +			perror(argv[i]);
> +			return 1;
> +		}
> +
> +		work = parse_work(file);
> +		fclose(file);
> +
> +		graphviz(work);
> +
> +		ideal_depth(work);
> +		single_client(work);
> +		packed_clients(work);
> +	}
> +
> +	return 0;
> +}
> 
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

WARNING: multiple messages have this Message-ID (diff)
From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
To: Chris Wilson <chris@chris-wilson.co.uk>, intel-gfx@lists.freedesktop.org
Cc: igt-dev@lists.freedesktop.org
Subject: Re: [PATCH i-g-t] benchmarks/wsim: Simulate and interpret .wsim
Date: Fri, 11 May 2018 09:31:52 +0100	[thread overview]
Message-ID: <203943cb-da94-14e0-bc62-4705ef4e8a8c@linux.intel.com> (raw)
In-Reply-To: <20180511071141.24581-1-chris@chris-wilson.co.uk>


On 11/05/2018 08:11, Chris Wilson wrote:
> A little tool I've been meaning to write for a while... Convert the
> .wsim into their dag and find the longest chains and evaluate them on an
> simulated machine.

Very cool!

But I think you need to handle the 's' command which appears in the 
interesting workloads. Maybe you could just fake it as a zero duration 
batch with a data dependency.

Fence related commands would also be useful but more difficult I guess. 
As would throttling.

Delays could maybe be faked as batches as well by adding input 
dependency to everything preceding it.

Regards,

Tvrtko

> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   benchmarks/Makefile.sources |   1 +
>   benchmarks/sim_wsim.c       | 434 ++++++++++++++++++++++++++++++++++++
>   2 files changed, 435 insertions(+)
>   create mode 100644 benchmarks/sim_wsim.c
> 
> diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
> index d150035aa..b80a7644c 100644
> --- a/benchmarks/Makefile.sources
> +++ b/benchmarks/Makefile.sources
> @@ -17,6 +17,7 @@ benchmarks_prog_list =			\
>   	gem_wsim			\
>   	kms_vblank			\
>   	prime_lookup			\
> +	sim_wsim			\
>   	vgem_mmap			\
>   	$(NULL)
>   
> diff --git a/benchmarks/sim_wsim.c b/benchmarks/sim_wsim.c
> new file mode 100644
> index 000000000..cb8e7adc4
> --- /dev/null
> +++ b/benchmarks/sim_wsim.c
> @@ -0,0 +1,434 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include "igt_aux.h"
> +
> +#if 0
> +#define DBG(...) printf(__VA_ARGS__)
> +#else
> +#define DBG(...) do { } while(0)
> +#endif
> +
> +struct dependency {
> +	struct task *signal;
> +	struct igt_list link;
> +};
> +
> +struct task {
> +	struct igt_list link;
> +	struct igt_list sched;
> +	struct igt_list signals;
> +	int step;
> +	int ctx;
> +	int class;
> +	int instance;
> +	long min, max;
> +	long duration;
> +	long deadline;
> +	bool visited;
> +};
> +
> +struct work {
> +	struct task **tasks;
> +	unsigned int count, size;
> +
> +	struct igt_list ends;
> +};
> +
> +static void add_dependency(struct task *task, struct task *signal)
> +{
> +	struct dependency *dep;
> +
> +	DBG("%s %d (context %d, engine %d) -> %d (context %d, engine %d)\n",
> +	    __func__,
> +	    signal->step, signal->ctx, signal->class,
> +	    task->step, task->ctx, task->class);
> +
> +	dep = malloc(sizeof(*dep));
> +	dep->signal = signal;
> +	igt_list_add(&dep->link, &task->signals);
> +	igt_list_del(&signal->link);
> +	igt_list_init(&signal->link);
> +}
> +
> +enum class {
> +	RCS,
> +	BCS,
> +	VCS,
> +	VECS,
> +};
> +
> +static void add_task(struct work *work, char *line)
> +{
> +	static const char *engines[] = {
> +		[RCS]  = "rcs",
> +		[BCS]  = "bcs",
> +		[VCS]  = "vcs",
> +		[VECS] = "vecs",
> +	};
> +	struct task *task;
> +	char *token;
> +	int i;
> +
> +	task = malloc(sizeof(*task));
> +
> +	igt_list_init(&task->signals);
> +	igt_list_init(&task->sched);
> +	task->step = work->count;
> +	task->visited = false;
> +
> +	/*
> +	 * 1.RCS.2800-3100.-1.0
> +	 * - context
> +	 * - engine
> +	 * - delay
> +	 * - dependencies
> +	 * - sync
> +	 */
> +	DBG("line='%s'\n", line);
> +
> +	/* context */
> +	token = strtok(line, ".");
> +	DBG("context='%s'\n", token);
> +	task->ctx  = atoi(token);
> +	if (!task->ctx)
> +		return;
> +
> +	/* engine */
> +	token = strtok(NULL, ".");
> +	DBG("engine='%s'\n", token);
> +	task->class = -1;
> +	for (i = 0; i < sizeof(engines)/sizeof(*engines); i++) {
> +		const int len = strlen(engines[i]);
> +		if (!strncasecmp(token, engines[i], len)) {
> +			task->class = i;
> +			if (token[len])
> +				task->instance = atoi(token + len);
> +			else
> +				task->instance = -1;
> +			break;
> +		}
> +	}
> +
> +	/* delay */
> +	token = strtok(NULL, ".");
> +	DBG("delay='%s'\n", token);
> +	task->min = strtol(token, &token, 0);
> +	if (*token)
> +		task->max = strtol(token + 1, NULL, 0);
> +	else
> +		task->max = task->min;
> +	task->duration = (task->min + task->max) / 2;
> +	DBG("min=%lu, max=%lu; duration=%lu\n", task->min, task->max, task->duration);
> +
> +	/* dependencies */
> +	token = strtok(NULL, ".");
> +	DBG("deps='%s'\n", token);
> +	while ((i = strtol(token, &token, 0))) {
> +		add_dependency(task, work->tasks[work->count + i]);
> +		if (*token)
> +			token++;
> +	}
> +
> +	/* add a dependency for the context+engine timeline */
> +	for (i = work->count; --i >= 0; ) {
> +		if (work->tasks[i]->ctx == task->ctx &&
> +		    work->tasks[i]->class == task->class) {
> +			add_dependency(task, work->tasks[i]);
> +			break;
> +		}
> +	}
> +
> +	igt_list_add(&task->link, &work->ends);
> +	work->tasks[work->count++] = task;
> +}
> +
> +static struct work *parse_work(FILE *file)
> +{
> +	struct work *work;
> +	char *line = NULL;
> +	size_t len = 0;
> +
> +	work = malloc(sizeof(*work));
> +	igt_list_init(&work->ends);
> +
> +	work->size = 64;
> +	work->count = 0;
> +	work->tasks = malloc(sizeof(*work->tasks) * work->size);
> +
> +	while (getline(&line, &len, file) != -1) {
> +		if (work->count == work->size) {
> +			work->tasks = realloc(work->tasks,
> +					      sizeof(*work->tasks) * work->size);
> +			work->size *= 2;
> +		}
> +		add_task(work, line);
> +	}
> +
> +	free(line);
> +
> +	DBG("%d tasks\n", work->count);
> +	return work;
> +}
> +
> +static unsigned long sum_durations(struct task *task)
> +{
> +	unsigned long max_duration = 0;
> +	struct task *signal = NULL;
> +	struct dependency *dep;
> +
> +	igt_list_for_each(dep, &task->signals, link) {
> +		if (dep->signal->duration > max_duration) {
> +			signal = dep->signal;
> +			max_duration = signal->duration;
> +		}
> +	}
> +
> +	return task->duration + (signal ? sum_durations(signal) : 0);
> +}
> +
> +static void ideal_depth(struct work *work)
> +{
> +	unsigned long total_duration;
> +	unsigned long max_duration;
> +	struct task *task;
> +	int i;
> +
> +	/*
> +	 * The ideal depth is the longest chain of dependencies as the
> +	 * dependency chain requires sequential task execution. Each
> +	 * chain is assumed to be run in parallel on an infinite set of
> +	 * engines, so the ratelimiting step is its longest path.
> +	 */
> +	max_duration = 0;
> +	igt_list_for_each(task, &work->ends, link) {
> +		unsigned long duration = sum_durations(task);
> +		if (duration > max_duration)
> +			max_duration = duration;
> +	}
> +
> +	total_duration = 0;
> +	for (i = 0; i < work->count; i++)
> +		total_duration += work->tasks[i]->duration;
> +
> +	printf("Single client\n");
> +	printf("   total duration %luus; %.2f wps\n", total_duration, 1e6/total_duration);
> +	printf("   ideal duration %luus; %.2f wps\n", max_duration, 1e6/max_duration);
> +}
> +
> +struct sim_class {
> +	int ninstance;
> +	unsigned int instances[4];
> +};
> +
> +static void single_client(struct work *work)
> +{
> +	struct sim_class sim[] = {
> +		[RCS]  = { 1 },
> +		[BCS]  = { 1 },
> +		[VCS]  = { 2 },
> +		[VECS] = { 1 },
> +	}, *class;
> +	IGT_LIST(sched);
> +	struct task *task;
> +	unsigned long max;
> +	int i, j;
> +
> +	for (i = 0; i < work->count; i++)
> +		igt_list_init(&work->tasks[i]->sched);
> +
> +	igt_list_for_each(task, &work->ends, link) {
> +		igt_list_add_tail(&task->sched, &sched);
> +	}
> +
> +	igt_list_for_each(task, &sched, sched) {
> +		struct dependency *dep;
> +
> +		igt_list_for_each(dep, &task->signals, link)
> +			igt_list_move_tail(&dep->signal->sched, &sched);
> +	}
> +
> +	igt_list_for_each_reverse(task, &sched, sched) {
> +		struct dependency *dep;
> +		int instance;
> +
> +		class = &sim[task->class];
> +		max = class->instances[0];
> +
> +		instance = task->instance;
> +		if (instance < 0) {
> +			instance = 0;
> +			for (i = 1; i < class->ninstance; i++) {
> +				if (class->instances[i] < max) {
> +					max = class->instances[i];
> +					instance = i;
> +				}
> +			}
> +		}
> +
> +		/*
> +		 * Greedy (first available), not true optimal scheduling.
> +		 *
> +		 * For optimal, we do have to compute the global optimal
> +		 * ordering by checking every permutation...
> +		 */
> +		igt_list_for_each(dep, &task->signals, link) {
> +			if (dep->signal->deadline > max)
> +				max = dep->signal->deadline;
> +		}
> +
> +		DBG("task %d: engine %d, instance %d; finish %lu\n",
> +		    task->step, task->class, instance, max);
> +
> +		task->deadline = max + task->duration;
> +		class->instances[instance] = task->deadline;
> +	}
> +
> +	max = 0;
> +	for (i = 0; i < sizeof(sim)/sizeof(sim[0]); i++) {
> +		class = &sim[i];
> +		for (j = 0; j < class->ninstance; j++) {
> +			if (class->instances[j] > max)
> +				max = class->instances[j];
> +		}
> +	}
> +
> +	printf("Simulated client:\n");
> +	printf("   duration %luus; %.2f wps\n", max, 1e6/max);
> +}
> +
> +static void packed_clients(struct work *work)
> +{
> +	struct sim_class sim[] = {
> +		[RCS]  = { 1 },
> +		[BCS]  = { 1 },
> +		[VCS]  = { 2 },
> +		[VECS] = { 1 },
> +	}, *class;
> +	IGT_LIST(sched);
> +	struct task *task;
> +	unsigned long min;
> +	int i, j;
> +
> +	for (i = 0; i < work->count; i++)
> +		igt_list_init(&work->tasks[i]->sched);
> +
> +	igt_list_for_each(task, &work->ends, link)
> +		igt_list_add_tail(&task->sched, &sched);
> +
> +	igt_list_for_each(task, &sched, sched) {
> +		struct dependency *dep;
> +
> +		igt_list_for_each(dep, &task->signals, link)
> +			igt_list_move_tail(&dep->signal->sched, &sched);
> +	}
> +
> +	/*
> +	 * Compute the maximum duration required on any engine.
> +	 *
> +	 * With sufficient clients forcing maximum occupancy under their weight,
> +	 * the ratelimiting step becomes a single engine and how many clients
> +	 * it takes to fill.
> +	 */
> +	igt_list_for_each_reverse(task, &sched, sched) {
> +		int instance;
> +
> +		class = &sim[task->class];
> +		instance = task->instance;
> +		if (instance < 0) {
> +			instance = 0;
> +			min = class->instances[0];
> +			for (i = 1; i < class->ninstance; i++) {
> +				if (class->instances[i] < min) {
> +					min = class->instances[i];
> +					instance = i;
> +				}
> +			}
> +		}
> +
> +		class->instances[instance] += task->duration;
> +	}
> +
> +	min = 0;
> +	for (i = 0; i < sizeof(sim)/sizeof(sim[0]); i++) {
> +		class = &sim[i];
> +		for (j = 0; j < class->ninstance; j++) {
> +			if (class->instances[j] > min)
> +				min = class->instances[j];
> +		}
> +	}
> +
> +	printf("Packed clients:\n");
> +	printf("   duration %luus; %.2f wps\n", min, 1e6/min);
> +}
> +
> +static void graphviz(struct work *work)
> +{
> +#if 0
> +	int i, j;
> +
> +	printf("digraph {\n");
> +	printf("  rankdir=LR;\n");
> +	printf("  splines=line;\n");
> +	printf("\n");
> +
> +	for (i = 0; i < work->count; i++) {
> +		struct task *task = work->tasks[i];
> +
> +		if (task->visited)
> +			goto skip;
> +
> +		printf("  subgraph cluster_%d {\n", task->ctx);
> +		printf("    label=\"Context %d\"\n", task->ctx);
> +		for (j = i; j < work->count; j++) {
> +			if (work->tasks[j]->ctx == task->ctx) {
> +				printf("    task_%03d;\n", j);
> +				work->tasks[j]->visited = true;
> +			}
> +		}
> +		printf("  }\n\n");
> +
> +skip:
> +		task->visited = false;
> +	}
> +
> +	for (i = 0; i < work->count; i++) {
> +		struct task *task = work->tasks[i];
> +		struct dependency *dep;
> +
> +		igt_list_for_each(dep, &task->signals, link) {
> +			printf("  task_%03d -> task_%03d;\n",
> +			       dep->signal->step, task->step);
> +		}
> +	}
> +
> +	printf("}\n");
> +#endif
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int i;
> +
> +	for (i = 1; i < argc; i++) {
> +		FILE *file = fopen(argv[i], "r");
> +		struct work *work;
> +
> +		if (!file) {
> +			perror(argv[i]);
> +			return 1;
> +		}
> +
> +		work = parse_work(file);
> +		fclose(file);
> +
> +		graphviz(work);
> +
> +		ideal_depth(work);
> +		single_client(work);
> +		packed_clients(work);
> +	}
> +
> +	return 0;
> +}
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2018-05-11  8:31 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-11  7:11 [Intel-gfx] [PATCH i-g-t] benchmarks/wsim: Simulate and interpret .wsim Chris Wilson
2018-05-11  7:11 ` Chris Wilson
2018-05-11  7:33 ` [igt-dev] ✓ Fi.CI.BAT: success for " Patchwork
2018-05-11  8:27 ` [Intel-gfx] [PATCH i-g-t] " Chris Wilson
2018-05-11  8:27   ` Chris Wilson
2018-05-11  8:31 ` Tvrtko Ursulin [this message]
2018-05-11  8:31   ` Tvrtko Ursulin
2018-05-11  9:04   ` [Intel-gfx] " Chris Wilson
2018-05-11  9:04     ` Chris Wilson
2018-05-11  9:21     ` [igt-dev] [Intel-gfx] " Tvrtko Ursulin
2018-05-11  9:21       ` Tvrtko Ursulin
2018-05-11  9:33       ` [igt-dev] [Intel-gfx] " Chris Wilson
2018-05-11  9:33         ` Chris Wilson
2018-05-11 11:56         ` [igt-dev] [Intel-gfx] " Tvrtko Ursulin
2018-05-11 11:56           ` Tvrtko Ursulin
2018-07-10 13:47   ` [igt-dev] [Intel-gfx] " Chris Wilson
2018-07-10 13:47     ` Chris Wilson
2018-07-10 15:38     ` [Intel-gfx] " Tvrtko Ursulin
2018-07-10 15:38       ` Tvrtko Ursulin
2018-07-10 15:40       ` [Intel-gfx] " Chris Wilson
2018-07-10 15:40         ` Chris Wilson
2018-07-10 16:05         ` [igt-dev] [Intel-gfx] " Tvrtko Ursulin
2018-07-10 16:05           ` Tvrtko Ursulin
2018-05-11  8:45 ` [igt-dev] ✗ Fi.CI.IGT: failure for " Patchwork
2018-05-11  9:46 ` [igt-dev] ✓ Fi.CI.BAT: success for benchmarks/wsim: Simulate and interpret .wsim (rev2) Patchwork
2018-05-11 11:24 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=203943cb-da94-14e0-bc62-4705ef4e8a8c@linux.intel.com \
    --to=tvrtko.ursulin@linux.intel.com \
    --cc=chris@chris-wilson.co.uk \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.