Explorar o código

- Cleanup the regression-based performance modeling facilities
- Only compute a non-linear regression-based model in case we have a
STARPU_NL_REGRESSION_BASED type since this is expensive (before, it would
have been computed as well in the case of an history-based model for
instance).
- Add a STARPU_NL_REGRESSION_BASED type of performance model for non-linear
performance models (y = a * size ^ b + c)
- STARPU_REGRESSION_BASED now refers to linear regressions
(y = alpha * size ^ beta)

Cédric Augonnet %!s(int64=14) %!d(string=hai) anos
pai
achega
e4d271543b

+ 4 - 2
include/starpu_perfmodel.h

@@ -61,10 +61,11 @@ struct starpu_regression_model_t {
 	/* y = alpha size ^ beta */
 	double alpha;
 	double beta;
+	unsigned valid;
 
 	/* y = a size ^b + c */
 	double a, b, c;
-	unsigned valid;
+	unsigned nl_valid;
 
 	unsigned nsample;
 };
@@ -84,7 +85,8 @@ typedef enum {
 	STARPU_PER_ARCH,	/* Application-provided per-arch cost model function */
 	STARPU_COMMON,		/* Application-provided common cost model function, with per-arch factor */
 	STARPU_HISTORY_BASED,	/* Automatic history-based cost model */
-	STARPU_REGRESSION_BASED	/* Automatic history-based regression cost model */
+	STARPU_REGRESSION_BASED,	/* Automatic linear regression-based cost model  (alpha * size ^ beta) */
+	STARPU_NL_REGRESSION_BASED	/* Automatic non-linear regression-based cost model (a * size ^ b + c) */
 } starpu_perfmodel_type;
 
 struct starpu_perfmodel_t {

+ 3 - 0
src/core/perfmodel/perfmodel.c

@@ -152,6 +152,9 @@ double starpu_task_expected_length(struct starpu_task *task, enum starpu_perf_ar
 			case STARPU_REGRESSION_BASED:
 				return _starpu_regression_based_job_expected_length(model, arch, j);
 
+			case STARPU_NL_REGRESSION_BASED:
+				return _starpu_non_linear_regression_based_job_expected_length(model, arch, j);
+
 			default:
 				STARPU_ABORT();
 		};

+ 2 - 0
src/core/perfmodel/perfmodel.h

@@ -97,6 +97,8 @@ void _starpu_deinitialize_registered_performance_models(void);
 
 double _starpu_regression_based_job_expected_length(struct starpu_perfmodel_t *model,
 					enum starpu_perf_archtype arch, struct starpu_job_s *j);
+double _starpu_non_linear_regression_based_job_expected_length(struct starpu_perfmodel_t *model,
+					enum starpu_perf_archtype arch, struct starpu_job_s *j);
 void _starpu_update_perfmodel_history(struct starpu_job_s *j, enum starpu_perf_archtype arch,
 				unsigned cpuid, double measured);
 

+ 146 - 83
src/core/perfmodel/perfmodel_history.c

@@ -55,22 +55,78 @@ static void insert_history_entry(struct starpu_history_entry_t *entry, struct st
 }
 
 
-static void dump_reg_model(FILE *f, struct starpu_regression_model_t *reg_model)
+static void dump_reg_model(FILE *f, struct starpu_perfmodel_t *model, unsigned arch)
 {
+	struct starpu_per_arch_perfmodel_t *per_arch_model;
+	per_arch_model = &model->per_arch[arch];
+
+	struct starpu_regression_model_t *reg_model;
+	reg_model = &per_arch_model->regression;
+
+	/*
+	 * Linear Regression model
+	 */
+
+	/* Unless we have enough measurements, we put NaN in the file to indicate the model is invalid */
+	double alpha = nan(""), beta = nan("");
+	if (model->type == STARPU_REGRESSION_BASED || model->type == STARPU_NL_REGRESSION_BASED)
+	{
+		if (reg_model->nsample > 1)
+		{
+			alpha = reg_model->alpha;
+			beta = reg_model->beta;
+		}
+	}
+
 	fprintf(f, "# sumlnx\tsumlnx2\t\tsumlny\t\tsumlnxlny\talpha\t\tbeta\t\tn\n");
-	fprintf(f, "%-15le\t%-15le\t%-15le\t%-15le\t%-15le\t%-15le\t%u\n", reg_model->sumlnx, reg_model->sumlnx2, reg_model->sumlny, reg_model->sumlnxlny, reg_model->alpha, reg_model->beta, reg_model->nsample);
+	fprintf(f, "%-15le\t%-15le\t%-15le\t%-15le\t%-15le\t%-15le\t%u\n", reg_model->sumlnx, reg_model->sumlnx2, reg_model->sumlny, reg_model->sumlnxlny, alpha, beta, reg_model->nsample);
+
+	/*
+	 * Non-Linear Regression model
+	 */
+
+	double a = nan(""), b = nan(""), c = nan("");
+
+	if (model->type == STARPU_NL_REGRESSION_BASED)
+		_starpu_regression_non_linear_power(per_arch_model->list, &a, &b, &c);
+
+	fprintf(f, "# a\t\tb\t\tc\n");
+	fprintf(f, "%-15le\t%-15le\t%-15le\n", a, b, c);
 }
 
 static void scan_reg_model(FILE *f, struct starpu_regression_model_t *reg_model)
 {
 	int res;
 
+	/*
+	 * Linear Regression model
+	 */
+
 	_starpu_drop_comments(f);
 
-	res = fscanf(f, "%le\t%le\t%le\t%le\t%le\t%le\t%u\n", &reg_model->sumlnx, &reg_model->sumlnx2, &reg_model->sumlny, &reg_model->sumlnxlny, &reg_model->alpha, &reg_model->beta, &reg_model->nsample);
+	res = fscanf(f, "%le\t%le\t%le\t%le\t%le\t%le\t%u\n",
+		&reg_model->sumlnx, &reg_model->sumlnx2, &reg_model->sumlny,
+		&reg_model->sumlnxlny, &reg_model->alpha, &reg_model->beta,
+		&reg_model->nsample);
 	STARPU_ASSERT(res == 7);
-}
 
+	/* If any of the parameters describing the linear regression model is NaN, the model is invalid */
+	unsigned invalid = (isnan(reg_model->alpha)||isnan(reg_model->beta));
+	reg_model->valid = !invalid;
+
+	/*
+	 * Non-Linear Regression model
+	 */
+
+	_starpu_drop_comments(f);
+
+	res = fscanf(f, "%le\t%le\t%le\n", &reg_model->a, &reg_model->b, &reg_model->c);
+	STARPU_ASSERT(res == 3);
+
+	/* If any of the parameters describing the non-linear regression model is NaN, the model is invalid */
+	unsigned nl_invalid = (isnan(reg_model->a)||isnan(reg_model->b)||isnan(reg_model->c));
+	reg_model->nl_valid = !nl_invalid;
+}
 
 static void dump_history_entry(FILE *f, struct starpu_history_entry_t *entry)
 {
@@ -127,22 +183,6 @@ static void parse_per_arch_model_file(FILE *f, struct starpu_per_arch_perfmodel_
 
 	scan_reg_model(f, &per_arch_model->regression);
 
-	_starpu_drop_comments(f);
-
-	res = fscanf(f, "%le\t%le\t%le\n", 
-		&per_arch_model->regression.a,
-		&per_arch_model->regression.b,
-		&per_arch_model->regression.c);
-	STARPU_ASSERT(res == 3);
-
-	if (isnan(per_arch_model->regression.a)||isnan(per_arch_model->regression.b)||isnan(per_arch_model->regression.c))
-	{
-		per_arch_model->regression.valid = 0;
-	}
-	else {
-		per_arch_model->regression.valid = 1;
-	}
-
 	/* parse cpu entries */
 	unsigned i;
 	for (i = 0; i < nentries; i++) {
@@ -168,34 +208,39 @@ static void parse_model_file(FILE *f, struct starpu_perfmodel_t *model, unsigned
 		parse_per_arch_model_file(f, &model->per_arch[arch], scan_history);
 }
 
-static void dump_per_arch_model_file(FILE *f, struct starpu_per_arch_perfmodel_t *per_arch_model)
+static void dump_per_arch_model_file(FILE *f, struct starpu_perfmodel_t *model, unsigned arch)
 {
+	struct starpu_per_arch_perfmodel_t *per_arch_model;
+	per_arch_model = &model->per_arch[arch];
+
 	/* count the number of elements in the lists */
-	struct starpu_history_list_t *ptr;
+	struct starpu_history_list_t *ptr = NULL;
 	unsigned nentries = 0;
 
-	ptr = per_arch_model->list;
-	while(ptr) {
-		nentries++;
-		ptr = ptr->next;
+	if (model->type == STARPU_HISTORY_BASED || model->type == STARPU_NL_REGRESSION_BASED)
+	{
+		/* Dump the list of all entries in the history */
+		ptr = per_arch_model->list;
+		while(ptr) {
+			nentries++;
+			ptr = ptr->next;
+		}
 	}
 
 	/* header */
 	fprintf(f, "# number of entries\n%u\n", nentries);
 
-	dump_reg_model(f, &per_arch_model->regression);
-
-	double a,b,c;
-	_starpu_regression_non_linear_power(per_arch_model->list, &a, &b, &c);
-	fprintf(f, "# a\t\tb\t\tc\n");
-	fprintf(f, "%-15le\t%-15le\t%-15le\n", a, b, c);
+	dump_reg_model(f, model, arch);
 
-	fprintf(f, "# hash\t\tsize\t\tmean\t\tdev\t\tsum\t\tsum2\t\tn\n");
-	ptr = per_arch_model->list;
-	while (ptr) {
-		//memcpy(&entries_array[i++], ptr->entry, sizeof(struct starpu_history_entry_t));
-		dump_history_entry(f, ptr->entry);
-		ptr = ptr->next;
+	/* Dump the history into the model file in case it is necessary */
+	if (model->type == STARPU_HISTORY_BASED || model->type == STARPU_NL_REGRESSION_BASED)
+	{
+		fprintf(f, "# hash\t\tsize\t\tmean\t\tdev\t\tsum\t\tsum2\t\tn\n");
+		ptr = per_arch_model->list;
+		while (ptr) {
+			dump_history_entry(f, ptr->entry);
+			ptr = ptr->next;
+		}
 	}
 }
 
@@ -209,7 +254,7 @@ static void dump_model_file(FILE *f, struct starpu_perfmodel_t *model)
 		char archname[32];
 		starpu_perfmodel_get_arch_name(arch, archname, 32);
 		fprintf(f, "# Model for %s\n", archname);
-		dump_per_arch_model_file(f, &model->per_arch[arch]);
+		dump_per_arch_model_file(f, model, arch);
 		fprintf(f, "\n##################\n");
 	}
 }
@@ -556,6 +601,22 @@ double _starpu_regression_based_job_expected_length(struct starpu_perfmodel_t *m
 	regmodel = &model->per_arch[arch].regression;
 
 	if (regmodel->valid)
+		exp = regmodel->alpha*pow(size, regmodel->beta);
+
+	return exp;
+}
+
+double _starpu_non_linear_regression_based_job_expected_length(struct starpu_perfmodel_t *model, enum starpu_perf_archtype arch, struct starpu_job_s *j)
+{
+	double exp = -1.0;
+	size_t size = _starpu_job_get_data_size(j);
+	struct starpu_regression_model_t *regmodel;
+
+	load_history_based_model(model, 0);
+
+	regmodel = &model->per_arch[arch].regression;
+
+	if (regmodel->nl_valid)
 		exp = regmodel->a*pow(size, regmodel->b) + regmodel->c;
 
 	return exp;
@@ -596,64 +657,69 @@ void _starpu_update_perfmodel_history(starpu_job_t j, enum starpu_perf_archtype
 
 	if (model)
 	{
+		PTHREAD_RWLOCK_WRLOCK(&model->model_rwlock);
+
 		struct starpu_per_arch_perfmodel_t *per_arch_model = &model->per_arch[arch];
 
-		if (model->type == STARPU_HISTORY_BASED || model->type == STARPU_REGRESSION_BASED)
+		if (model->type == STARPU_HISTORY_BASED || model->type == STARPU_NL_REGRESSION_BASED)
 		{
 			uint32_t key = j->footprint;
 			struct starpu_history_entry_t *entry;
 
 			struct starpu_htbl32_node_s *history;
 			struct starpu_htbl32_node_s **history_ptr;
-			struct starpu_regression_model_t *reg_model;
 
 			struct starpu_history_list_t **list;
 
 
 			history = per_arch_model->history;
 			history_ptr = &per_arch_model->history;
-			reg_model = &per_arch_model->regression;
 			list = &per_arch_model->list;
 
-			PTHREAD_RWLOCK_WRLOCK(&model->model_rwlock);
-	
-				entry = _starpu_htbl_search_32(history, key);
-	
-				if (!entry)
-				{
-					/* this is the first entry with such a footprint */
-					entry = malloc(sizeof(struct starpu_history_entry_t));
-					STARPU_ASSERT(entry);
-						entry->mean = measured;
-						entry->sum = measured;
-	
-						entry->deviation = 0.0;
-						entry->sum2 = measured*measured;
-	
-						entry->size = _starpu_job_get_data_size(j);
-	
-						entry->footprint = key;
-						entry->nsample = 1;
-	
-					insert_history_entry(entry, list, history_ptr);
-	
-				}
-				else {
-					/* there is already some entry with the same footprint */
-					entry->sum += measured;
-					entry->sum2 += measured*measured;
-					entry->nsample++;
-	
-					unsigned n = entry->nsample;
-					entry->mean = entry->sum / n;
-					entry->deviation = sqrt((entry->sum2 - (entry->sum*entry->sum)/n)/n);
-				}
-			
+			entry = _starpu_htbl_search_32(history, key);
+
+			if (!entry)
+			{
+				/* this is the first entry with such a footprint */
+				entry = malloc(sizeof(struct starpu_history_entry_t));
 				STARPU_ASSERT(entry);
+					entry->mean = measured;
+					entry->sum = measured;
+
+					entry->deviation = 0.0;
+					entry->sum2 = measured*measured;
+
+					entry->size = _starpu_job_get_data_size(j);
+
+					entry->footprint = key;
+					entry->nsample = 1;
+
+				insert_history_entry(entry, list, history_ptr);
+
+			}
+			else {
+				/* there is already some entry with the same footprint */
+				entry->sum += measured;
+				entry->sum2 += measured*measured;
+				entry->nsample++;
+
+				unsigned n = entry->nsample;
+				entry->mean = entry->sum / n;
+				entry->deviation = sqrt((entry->sum2 - (entry->sum*entry->sum)/n)/n);
+			}
+			
+			STARPU_ASSERT(entry);
+		}
 			
-			/* update the regression model as well */
+		if (model->type == STARPU_REGRESSION_BASED || model->type == STARPU_NL_REGRESSION_BASED)
+		{
+			struct starpu_regression_model_t *reg_model;
+			reg_model = &per_arch_model->regression;
+
+			/* update the regression model */
+			size_t job_size = _starpu_job_get_data_size(j);
 			double logy, logx;
-			logx = log(entry->size);
+			logx = log(job_size);
 			logy = log(measured);
 
 			reg_model->sumlnx += logx;
@@ -669,16 +735,12 @@ void _starpu_update_perfmodel_history(starpu_job_t j, enum starpu_perf_archtype
 
 			reg_model->beta = num/denom;
 			reg_model->alpha = exp((reg_model->sumlny - reg_model->beta*reg_model->sumlnx)/n);
-			
-			PTHREAD_RWLOCK_UNLOCK(&model->model_rwlock);
 		}
 
 #ifdef STARPU_MODEL_DEBUG
 		struct starpu_task *task = j->task;
 		FILE * debug_file = per_arch_model->debug_file;
 
-		PTHREAD_RWLOCK_WRLOCK(&model->model_rwlock);
-
 		STARPU_ASSERT(j->footprint_is_computed);
 
 		fprintf(debug_file, "0x%x\t%lu\t%lf\t%lf\t%d\t\t", j->footprint, (unsigned long) _starpu_job_get_data_size(j), measured, task->predicted, cpuid);
@@ -694,7 +756,8 @@ void _starpu_update_perfmodel_history(starpu_job_t j, enum starpu_perf_archtype
 		}
 		fprintf(debug_file, "\n");	
 
-		PTHREAD_RWLOCK_UNLOCK(&model->model_rwlock);
 #endif
+		
+		PTHREAD_RWLOCK_UNLOCK(&model->model_rwlock);
 	}
 }

+ 0 - 2
src/core/perfmodel/regression.c

@@ -19,8 +19,6 @@
 #define MAXREGITER	1000
 #define EPS 1.0e-10
 
-//#define MIN(a,b) ((a)<(b)?(a):(b))
-
 static double compute_b(double c, unsigned n, unsigned *x, double *y)
 {
 	double b;

+ 2 - 2
src/sched_policies/deque_modeling_policy_data_aware.c

@@ -466,7 +466,7 @@ static int dm_push_prio_task(struct starpu_task *task)
 
 static int dm_push_task(struct starpu_task *task)
 {
-	if (task->priority == STARPU_MAX_PRIO)
+	if (task->priority > 0)
 		return _dm_push_task(task, 1);
 
 	return _dm_push_task(task, 0);
@@ -479,7 +479,7 @@ static int dmda_push_prio_task(struct starpu_task *task)
 
 static int dmda_push_task(struct starpu_task *task)
 {
-	if (task->priority == STARPU_MAX_PRIO)
+	if (task->priority > 0)
 		return _dmda_push_task(task, 1);
 
 	return _dmda_push_task(task, 0);

+ 12 - 4
tools/starpu_perfmodel_display.c

@@ -148,22 +148,30 @@ static void display_perf_model(struct starpu_perfmodel_t *model, enum starpu_per
 	if (parameter == NULL)
 	{
 		/* no specific parameter was requested, so we display everything */
-		fprintf(stderr, "\tRegression : #sample = %d (%s)\n",
-			arch_model->regression.nsample,
-			arch_model->regression.valid?"VALID":"STARPU_INVALID");
-	
+		fprintf(stderr, "\tRegression : #sample = %d\n",
+			arch_model->regression.nsample);
+
 		/* Only display the regression model if we could actually build a model */
 		if (arch_model->regression.valid)
 		{
 			fprintf(stderr, "\tLinear: y = alpha size ^ beta\n");
 			fprintf(stderr, "\t\talpha = %le\n", arch_model->regression.alpha);
 			fprintf(stderr, "\t\tbeta = %le\n", arch_model->regression.beta);
+		}
+		else {
+			fprintf(stderr, "\tLinear model is INVALID\n");
+		}
 	
+		if (arch_model->regression.nl_valid)
+		{
 			fprintf(stderr, "\tNon-Linear: y = a size ^b + c\n");
 			fprintf(stderr, "\t\ta = %le\n", arch_model->regression.a);
 			fprintf(stderr, "\t\tb = %le\n", arch_model->regression.b);
 			fprintf(stderr, "\t\tc = %le\n", arch_model->regression.c);
 		}
+		else {
+			fprintf(stderr, "\tNon-Linear model is INVALID\n");
+		}
 
 		display_history_based_perf_model(arch_model);