Sfoglia il codice sorgente

Take machine idle consumption into account

Samuel Thibault 14 anni fa
parent
commit
7979bcafcb

+ 15 - 2
doc/starpu.texi

@@ -1381,6 +1381,13 @@ is the estimated task consumption in Joules. To tune this parameter, use
 (i.e kW during 1000us) is worth 3000us execution time penalty. Setting
 alpha and beta to zero permits to only take into account power consumption.
 
+This is however not sufficient to correctly optimize power: the scheduler would
+simply tend to run all computations on the most energy-conservative processing
+unit. To account for the consumption of the whole machine (including idle
+processing units), the idle power of the machine should be given by setting
+@code{export STARPU_IDLE_POWER=200} for 200W, for instance. This value can often
+be obtained from the machine power supplier.
+
 The power actually consumed by the total execution can be displayed by setting
 @code{export STARPU_PROFILING=1 STARPU_WORKER_STATS=1} .
 
@@ -3198,11 +3205,17 @@ not be above @code{STARPU_NMAXBUFS}.
 
 @item @code{model} (optional):
 This is a pointer to the task duration performance model associated to this
-codelet. This optional field is ignored when set to @code{NULL}. TODO
+codelet. This optional field is ignored when set to @code{NULL}.
+
+TODO
 
 @item @code{power_model} (optional):
 This is a pointer to the task power consumption performance model associated
-to this codelet. This optional field is ignored when set to @code{NULL}. TODO
+to this codelet. This optional field is ignored when set to @code{NULL}.
+In the case of parallel codelets, this has to account for all processing units
+involved in the parallel execution.
+
+TODO
 
 @end table
 @end table

+ 4 - 0
include/starpu_perfmodel.h

@@ -116,9 +116,13 @@ void starpu_perfmodel_debugfilepath(struct starpu_perfmodel_t *model,
 void starpu_perfmodel_get_arch_name(enum starpu_perf_archtype arch,
 		char *archname, size_t maxlen);
 int starpu_list_models(void);
+/* Returns expected task duration in µs */
 double starpu_task_expected_length(struct starpu_task *task, enum starpu_perf_archtype arch);
+/* Returns an estimated speedup factor relative to CPU speed */
 double starpu_worker_get_relative_speedup(enum starpu_perf_archtype perf_archtype);
+/* Returns expected data transfer time in µs */
 double starpu_data_expected_penalty(uint32_t memory_node, struct starpu_task *task);
+/* Returns expected power consumption in J */
 double starpu_task_expected_power(struct starpu_task *task, enum starpu_perf_archtype arch);
 
 void starpu_force_bus_sampling(void);

+ 3 - 0
include/starpu_task.h

@@ -75,7 +75,10 @@ typedef struct starpu_codelet_t {
 	/* how many buffers do the codelet takes as argument ? */
 	unsigned nbuffers;
 
+	/* performance model of the codelet */
 	struct starpu_perfmodel_t *model;
+	/* consumption model of the codelet.
+	 * In the case of parallel codelets, accounts for all units. */
 	struct starpu_perfmodel_t *power_model;
 
 	/* statistics collected at runtime: this is filled by StarPU and should

+ 14 - 0
src/sched_policies/deque_modeling_policy_data_aware.c

@@ -33,6 +33,7 @@ static pthread_mutex_t sched_mutex[STARPU_NMAXWORKERS];
 static double alpha = STARPU_DEFAULT_ALPHA;
 static double beta = STARPU_DEFAULT_BETA;
 static double _gamma = STARPU_DEFAULT_GAMMA;
+static double idle_power = 0.0;
 
 #ifdef STARPU_VERBOSE
 static long int total_task_cnt = 0;
@@ -392,6 +393,7 @@ static int _dmda_push_task(struct starpu_task *task, unsigned prio)
 	double local_data_penalty[nworkers];
 	double local_power[nworkers];
 	double exp_end[nworkers];
+	double max_exp_end = 0.0;
 
 	double fitness[nworkers];
 
@@ -413,6 +415,8 @@ static int _dmda_push_task(struct starpu_task *task, unsigned prio)
 		/* Sometimes workers didn't take the tasks as early as we expected */
 		fifo->exp_start = STARPU_MAX(fifo->exp_start, starpu_timing_now());
 		fifo->exp_end = fifo->exp_start + fifo->exp_len;
+		if (fifo->exp_end > max_exp_end)
+			max_exp_end = fifo->exp_end;
 
 		if (!starpu_worker_may_execute_task(worker, task))
 		{
@@ -485,6 +489,12 @@ static int _dmda_push_task(struct starpu_task *task, unsigned prio)
 					+ beta*(local_data_penalty[worker])
 					+ _gamma*(local_power[worker]);
 
+			if (exp_end[worker] > max_exp_end)
+				/* This placement will make the computation
+				 * longer, take into account the idle
+				 * consumption of other cpus */
+				fitness[worker] += _gamma * idle_power * (exp_end[worker] - max_exp_end) / 1000000.0;
+
 			if (best == -1 || fitness[worker] < best_fitness)
 			{
 				/* we found a better solution */
@@ -565,6 +575,10 @@ static void initialize_dmda_policy(struct starpu_machine_topology_s *topology,
 	if (strval_gamma)
 		_gamma = atof(strval_gamma);
 
+	const char *strval_idle_power = getenv("STARPU_IDLE_POWER");
+	if (strval_idle_power)
+		idle_power = atof(strval_idle_power);
+
 	unsigned workerid;
 	for (workerid = 0; workerid < nworkers; workerid++)
 	{

+ 27 - 2
src/sched_policies/parallel_heft.c

@@ -36,7 +36,8 @@ static pthread_mutex_t sched_mutex[STARPU_NMAXWORKERS];
 
 static double alpha = STARPU_DEFAULT_ALPHA;
 static double beta = STARPU_DEFAULT_BETA;
-/* TODO: Gamma */
+static double _gamma = STARPU_DEFAULT_GAMMA;
+static double idle_power = 0.0;
 
 static struct starpu_task *parallel_heft_pop_task(void)
 {
@@ -226,9 +227,12 @@ static int _parallel_heft_push_task(struct starpu_task *task, unsigned prio)
 
 	double local_task_length[nworkers+ncombinedworkers];
 	double local_data_penalty[nworkers+ncombinedworkers];
+	double local_power[nworkers+ncombinedworkers];
 	double exp_end[nworkers+ncombinedworkers];
 	double fitness[nworkers+ncombinedworkers];
 
+	double max_exp_end = 0.0;
+
 	int skip_worker[nworkers+ncombinedworkers];
 
 	double best_exp_end = DBL_MAX;
@@ -249,6 +253,8 @@ static int _parallel_heft_push_task(struct starpu_task *task, unsigned prio)
 		/* Sometimes workers didn't take the tasks as early as we expected */
 		fifo->exp_start = STARPU_MAX(fifo->exp_start, starpu_timing_now());
 		fifo->exp_end = fifo->exp_start + fifo->exp_len;
+		if (fifo->exp_end > max_exp_end)
+			max_exp_end = fifo->exp_end;
 	}
 
 	for (worker = 0; worker < (nworkers+ncombinedworkers); worker++)
@@ -301,6 +307,10 @@ static int _parallel_heft_push_task(struct starpu_task *task, unsigned prio)
 			/* a better solution was found */
 			best_exp_end = exp_end[worker];
 		}
+
+		local_power[worker] = starpu_task_expected_power(task, perf_arch);
+		if (local_power[worker] == -1.0)
+			local_power[worker] = 0.;
 	}
 
 	if (unknown)
@@ -320,7 +330,14 @@ static int _parallel_heft_push_task(struct starpu_task *task, unsigned prio)
 			}
 	
 			fitness[worker] = alpha*(exp_end[worker] - best_exp_end) 
-					+ beta*(local_data_penalty[worker]);
+					+ beta*(local_data_penalty[worker])
+					+ _gamma*(local_power[worker]);
+
+			if (exp_end[worker] > max_exp_end)
+				/* This placement will make the computation
+				 * longer, take into account the idle
+				 * consumption of other cpus */
+				fitness[worker] += _gamma * idle_power * (exp_end[worker] - max_exp_end) / 1000000.0;
 
 			if (best == -1 || fitness[worker] < best_fitness)
 			{
@@ -378,6 +395,14 @@ static void initialize_parallel_heft_policy(struct starpu_machine_topology_s *to
 	if (strval_beta)
 		beta = atof(strval_beta);
 
+	const char *strval_gamma = getenv("STARPU_SCHED_GAMMA");
+	if (strval_gamma)
+		_gamma = atof(strval_gamma);
+
+	const char *strval_idle_power = getenv("STARPU_IDLE_POWER");
+	if (strval_idle_power)
+		idle_power = atof(strval_idle_power);
+
 	_starpu_sched_find_worker_combinations(topology);
 
 	ncombinedworkers = topology->ncombinedworkers;