Przeglądaj źródła

first try of scheduler that suit topology
bugs fixes
more helpers function for tree

Simon Archipoff 12 lat temu
rodzic
commit
5fdc448a45

+ 2 - 1
src/Makefile.am

@@ -227,7 +227,8 @@ libstarpu_@STARPU_EFFECTIVE_VERSION@_la_SOURCES = 						\
 	sched_policies/node_random.c				\
 	sched_policies/node_work_stealing.c			\
 	sched_policies/node_fifo.c 				\
-	sched_policies/node_heft.c
+	sched_policies/node_heft.c				\
+	sched_policies/hierarchical_heft.c
 if STARPU_USE_CPU
 libstarpu_@STARPU_EFFECTIVE_VERSION@_la_SOURCES += drivers/cpu/driver_cpu.c
 endif

+ 180 - 0
src/sched_policies/hierarchical_heft.c

@@ -0,0 +1,180 @@
+#include "node_sched.h"
+#include <core/workers.h>
+
+#ifdef STARPU_HAVE_HWLOC
+#include <hwloc.h>
+/*
+ * this function attempt to create a scheduler with a heft node at top,
+ * and for eager for each homogeneous (same kind, same numa node) worker group below
+ */
+
+
+static hwloc_bitmap_t get_nodeset(int workerid)
+{
+	struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);;
+	struct _starpu_machine_config *config = _starpu_get_machine_config();
+	struct starpu_machine_topology *topology = &config->topology;
+
+	hwloc_obj_t obj = hwloc_get_obj_by_depth(topology->hwtopology, config->cpu_depth, worker->bindid);
+	STARPU_ASSERT(obj->userdata == worker);
+	return obj->nodeset;
+}
+
+
+struct _starpu_sched_node * _starpu_heft_eager_scheduler_add_worker(unsigned sched_ctx_id, struct _starpu_sched_node * root, int workerid)
+{
+	if(root == NULL)//first worker
+	{
+		root = _starpu_sched_node_heft_create();
+		struct _starpu_sched_node * fifo = _starpu_sched_node_fifo_create();
+		root->add_child(root, fifo, sched_ctx_id);
+		_starpu_sched_node_set_father(fifo, root, sched_ctx_id);
+		struct _starpu_sched_node *worker = _starpu_sched_node_worker_get(workerid);
+		fifo->add_child(fifo,worker,sched_ctx_id);
+		_starpu_sched_node_set_father(worker, fifo, sched_ctx_id);
+		return root;
+	}
+
+	hwloc_bitmap_t node = get_nodeset(workerid);
+	int i;
+	for(i = 0; i < root->nchilds; i++)
+	{
+		struct _starpu_sched_node * child = root->childs[i];
+		STARPU_ASSERT(child->nworkers > 0);
+		int wid = child->workerids[0];
+		hwloc_bitmap_t b = get_nodeset(child->workerids[0]);
+		if(hwloc_bitmap_intersects(b,node) && starpu_worker_get_type(wid) == starpu_worker_get_type(workerid))
+			break;
+	}
+	if(i < root->nchilds)//we already have a worker on the same place
+	{
+		struct _starpu_sched_node * fifo = root->childs[i];
+		STARPU_ASSERT(_starpu_sched_node_is_fifo(fifo));
+		fifo->add_child(fifo, _starpu_sched_node_worker_get(workerid),sched_ctx_id);
+		_starpu_sched_node_set_father(_starpu_sched_node_worker_get(workerid),
+					      fifo, sched_ctx_id);
+		return root;
+	}
+
+	STARPU_ASSERT(i ==root->nchilds);
+
+	{
+		struct _starpu_sched_node * fifo = _starpu_sched_node_fifo_create();
+		fifo->add_child(fifo, _starpu_sched_node_worker_get(workerid),sched_ctx_id);
+		_starpu_sched_node_set_father(_starpu_sched_node_worker_get(workerid), fifo, sched_ctx_id);
+		root->add_child(root,fifo, sched_ctx_id);
+		return root;
+	}
+}
+
+static void add_worker_heft(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
+{
+	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	unsigned i;
+	STARPU_PTHREAD_RWLOCK_WRLOCK(&t->lock);
+	for(i = 0; i < nworkers; i++)
+	{
+		t->root = _starpu_heft_eager_scheduler_add_worker(sched_ctx_id, t->root, workerids[i]);
+		_starpu_tree_update_after_modification(t);
+	}
+	STARPU_PTHREAD_RWLOCK_UNLOCK(&t->lock);
+}
+
+static void remove_worker_heft(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
+{
+	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	unsigned i;
+	STARPU_PTHREAD_RWLOCK_WRLOCK(&t->lock);
+	for(i = 0; i < nworkers; i++)
+	{
+		int workerid = workerids[i];
+		struct _starpu_sched_node * node = _starpu_sched_tree_remove_worker(t, workerid, sched_ctx_id);
+		if(node)
+		{
+			if(_starpu_sched_node_is_fifo(node))
+			{
+				STARPU_ASSERT(_starpu_sched_node_is_fifo(node));
+				struct starpu_task_list list = _starpu_sched_node_fifo_get_non_executable_tasks(node);
+				int res = _starpu_sched_node_push_tasks_to_firsts_suitable_parent(node, &list, sched_ctx_id);
+				STARPU_ASSERT(res); (void) res;
+			}
+		}
+		_starpu_node_destroy_rec(node, sched_ctx_id);
+	}
+	STARPU_PTHREAD_RWLOCK_UNLOCK(&t->lock);
+}
+
+#else
+static void add_worker_heft(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
+{
+	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	unsigned i;
+	STARPU_PTHREAD_RWLOCK_WRLOCK(&t->lock);
+	for(i = 0; i < nworkers; i++)
+	{
+		struct _starpu_sched_node * fifo = _starpu_sched_node_fifo_create();
+		struct _starpu_sched_node * worker =  _starpu_sched_node_worker_get(workerids[i]);
+
+		fifo->add_child(fifo, worker, sched_ctx_id);
+		_starpu_sched_node_set_father(worker, fifo, sched_ctx_id);
+
+		t->root->add_child(t->root, fifo, sched_ctx_id);
+		_starpu_sched_node_set_father(fifo, t->root, sched_ctx_id);
+
+	}
+	_starpu_tree_update_after_modification(t);
+	STARPU_PTHREAD_RWLOCK_UNLOCK(&t->lock);
+}
+
+static void remove_worker_heft(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
+{
+	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	unsigned i;
+	STARPU_PTHREAD_RWLOCK_WRLOCK(&t->lock);
+	for(i = 0; i < nworkers; i++)
+	{
+		int j;
+		for(j = 0; j < t->root->nchilds; j++)
+			if(t->root->childs[j]->workerids[0] == workerids[i])
+				break;
+		STARPU_ASSERT(j < t->root->nchilds);
+		struct _starpu_sched_node * fifo = t->root->childs[j];
+		_starpu_sched_node_set_father(fifo, NULL, sched_ctx_id);
+		t->root->remove_child(t->root, fifo, sched_ctx_id);
+	}
+	STARPU_PTHREAD_RWLOCK_UNLOCK(&t->lock);
+}
+#endif
+
+
+
+static void initialize_heft_center_policy(unsigned sched_ctx_id)
+{
+	starpu_sched_ctx_create_worker_collection(sched_ctx_id, STARPU_WORKER_LIST);
+	struct _starpu_sched_tree *data = malloc(sizeof(struct _starpu_sched_tree));
+	STARPU_PTHREAD_RWLOCK_INIT(&data->lock,NULL);
+	data->root = NULL;
+	starpu_sched_ctx_set_policy_data(sched_ctx_id, (void*)data);
+}
+
+static void deinitialize_heft_center_policy(unsigned sched_ctx_id)
+{
+	starpu_sched_ctx_delete_worker_collection(sched_ctx_id);
+}
+
+
+
+struct starpu_sched_policy _starpu_sched_tree_heft_policy =
+{
+	.init_sched = initialize_heft_center_policy,
+	.deinit_sched = deinitialize_heft_center_policy,
+	.add_workers = add_worker_heft,
+	.remove_workers = remove_worker_heft,
+	.push_task = _starpu_tree_push_task,
+	.pop_task = _starpu_tree_pop_task,
+	.pre_exec_hook = NULL,
+	.post_exec_hook = NULL,
+	.pop_every_task = NULL,
+	.policy_name = "tree-heft",
+	.policy_description = "heft tree policy"
+};

+ 24 - 2
src/sched_policies/node_fifo.c

@@ -111,12 +111,34 @@ static struct starpu_task * pop_task(struct _starpu_sched_node * node, unsigned
 	return NULL;
 }
 
+struct starpu_task_list  _starpu_sched_node_fifo_get_non_executable_tasks(struct _starpu_sched_node * node)
+{
+	struct starpu_task_list list;
+	starpu_task_list_init(&list);
+	struct _starpu_fifo_data * data = node->data;
+	struct _starpu_fifo_taskq * fifo = data->fifo;
+	struct starpu_task * task;
+	for (task  = starpu_task_list_begin(&fifo->taskq);
+	     task != starpu_task_list_end(&fifo->taskq);
+	     task  = starpu_task_list_next(task))
+	{
+		STARPU_ASSERT(task);
+		if(!_starpu_sched_node_can_execute_task(node, task))
+		{
+			starpu_task_list_erase(&fifo->taskq, task);
+			starpu_task_list_push_front(&list, task);
+			fifo->ntasks--;
+		}
+	}
+	return list;
+}
+
 int _starpu_sched_node_is_fifo(struct _starpu_sched_node * node)
 {
 	return node->estimated_execute_preds == estimated_execute_preds
 		|| node->estimated_load == estimated_load
-		|| node->push_task == node->push_task
-		|| node->pop_task == node->pop_task;
+		|| node->push_task == push_task
+		|| node->pop_task == pop_task;
 }
 
 struct _starpu_sched_node * _starpu_sched_node_fifo_create(void)

+ 6 - 71
src/sched_policies/node_heft.c

@@ -197,64 +197,7 @@ static void param_modified(struct starpu_top_param* d)
 }
 #endif /* !STARPU_USE_TOP */
 
-static void initialize_heft_center_policy(unsigned sched_ctx_id)
-{
-	starpu_sched_ctx_create_worker_collection(sched_ctx_id, STARPU_WORKER_LIST);
-	struct _starpu_sched_tree *data = malloc(sizeof(struct _starpu_sched_tree));
-	STARPU_PTHREAD_RWLOCK_INIT(&data->lock,NULL);
-
-
-	data->root = _starpu_sched_node_heft_create();
-	starpu_sched_ctx_set_policy_data(sched_ctx_id, (void*)data);
-}
-
-static void deinitialize_heft_center_policy(unsigned sched_ctx_id)
-{
-	struct _starpu_sched_tree *t = (struct _starpu_sched_tree*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
-	_starpu_tree_destroy(t, sched_ctx_id);
-	starpu_sched_ctx_delete_worker_collection(sched_ctx_id);
-}
-
-
-static void add_worker_heft(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
-{
-	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
-	unsigned i;
-	STARPU_PTHREAD_RWLOCK_WRLOCK(&t->lock);
-	for(i = 0; i < nworkers; i++)
-	{
-		struct _starpu_sched_node * fifo = _starpu_sched_node_fifo_create();
-		struct _starpu_sched_node * worker =  _starpu_sched_node_worker_get(workerids[i]);
-
-		fifo->add_child(fifo, worker, sched_ctx_id);
-		_starpu_sched_node_set_father(worker, fifo, sched_ctx_id);
 
-		t->root->add_child(t->root, fifo, sched_ctx_id);
-		_starpu_sched_node_set_father(fifo, t->root, sched_ctx_id);
-
-	}
-	_starpu_tree_update_after_modification(t);
-	STARPU_PTHREAD_RWLOCK_UNLOCK(&t->lock);
-}
-
-static void remove_worker_heft(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
-{
-	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
-	unsigned i;
-	STARPU_PTHREAD_RWLOCK_WRLOCK(&t->lock);
-	for(i = 0; i < nworkers; i++)
-	{
-		int j;
-		for(j = 0; j < t->root->nchilds; j++)
-			if(t->root->childs[j]->workerids[0] == workerids[i])
-				break;
-		STARPU_ASSERT(j < t->root->nchilds);
-		struct _starpu_sched_node * fifo = t->root->childs[j];
-		_starpu_sched_node_set_father(fifo, NULL, sched_ctx_id);
-		t->root->remove_child(t->root, fifo, sched_ctx_id);
-	}
-	STARPU_PTHREAD_RWLOCK_UNLOCK(&t->lock);
-}
 
 static void destroy_heft_node(struct _starpu_sched_node * node)
 {
@@ -317,18 +260,10 @@ struct _starpu_sched_node * _starpu_sched_node_heft_create()
 	return node;
 }
 
-
-struct starpu_sched_policy _starpu_sched_tree_heft_policy =
+int _starpu_sched_node_is_heft(struct _starpu_sched_node * node)
 {
-	.init_sched = initialize_heft_center_policy,
-	.deinit_sched = deinitialize_heft_center_policy,
-	.add_workers = add_worker_heft,
-	.remove_workers = remove_worker_heft,
-	.push_task = _starpu_tree_push_task,
-	.pop_task = _starpu_tree_pop_task,
-	.pre_exec_hook = NULL,
-	.post_exec_hook = NULL,
-	.pop_every_task = NULL,
-	.policy_name = "tree-heft",
-	.policy_description = "heft tree policy"
-};
+	return node->push_task == push_task
+		|| node->add_child == add_child
+		|| node->remove_child == remove_child
+		|| node->destroy_node == destroy_heft_node;
+}

+ 70 - 1
src/sched_policies/node_sched.c

@@ -81,6 +81,8 @@ int push_task(struct starpu_task * task)
 
 void _starpu_node_destroy_rec(struct _starpu_sched_node * node, unsigned sched_ctx_id)
 {
+	if(node == NULL)
+		return;
 	struct _starpu_sched_node ** stack = NULL;
 	int top = -1;
 #define PUSH(n) do{							\
@@ -322,7 +324,7 @@ void _starpu_sched_node_destroy(struct _starpu_sched_node *node)
 
 static int is_homogeneous(int * workerids, int nworkers)
 {
-	if(nworkers == 0)
+	if(nworkers < 2)
 		return 1;
 	int i = 0;
 	uint32_t last_worker = _starpu_get_worker_struct(workerids[i])->worker_mask;
@@ -375,3 +377,70 @@ void _starpu_tree_update_after_modification(struct _starpu_sched_tree * tree)
 {
 	_update_workerids_after_tree_modification(tree->root);
 }
+
+
+static struct _starpu_sched_node * _starpu_sched_node_remove_worker(struct _starpu_sched_node * node, int workerid, int sched_ctx_id)
+{
+	if(node == NULL)
+		return NULL;
+	if(node->nworkers == 1 && node->workerids[0] == workerid)//special case if there is only one worker left
+		return node;
+	int i;
+	for(i = 0; i < node->nchilds; i++)
+	{
+
+		struct _starpu_sched_node * child = node->childs[i];
+		if(in_tab(workerid, child->workerids, child->nworkers))
+		{
+			if(child->nworkers == 1)//we wants to remove this subtree
+			{
+				node->remove_child(node, child, sched_ctx_id);
+//				if(childs->fathers[sched_ctx_id] == node)
+//					_starpu_sched_node_set_father(child, NULL, sched_ctx_id);
+				return child;
+			}
+			else//we have several worker in this subtree
+			{
+				return _starpu_sched_node_remove_worker(child, workerid, sched_ctx_id);
+			}
+		}
+	}
+	return NULL;
+}
+
+struct _starpu_sched_node * _starpu_sched_tree_remove_worker(struct _starpu_sched_tree * t, int workerid, int sched_ctx_id)
+{
+	struct _starpu_sched_node * node = _starpu_sched_node_remove_worker(t->root, workerid, sched_ctx_id);
+	_starpu_tree_update_after_modification(t);
+	if(node == t->root)
+		t->root = NULL;
+	return node;
+}
+
+
+static int push_task_to_first_suitable_parent(struct _starpu_sched_node * node, struct starpu_task * task, int sched_ctx_id)
+{
+	if(node == NULL || node->fathers[sched_ctx_id] == NULL)
+		return 1;
+	
+	struct _starpu_sched_node * father = node->fathers[sched_ctx_id];
+	if(_starpu_sched_node_can_execute_task(father,task))
+		return father->push_task(father, task);
+	else
+		return push_task_to_first_suitable_parent(father, task, sched_ctx_id);
+}
+
+int _starpu_sched_node_push_tasks_to_firsts_suitable_parent(struct _starpu_sched_node * node, struct starpu_task_list *list, int sched_ctx_id)
+{
+	while(!starpu_task_list_empty(list))
+	{
+		struct starpu_task * task = starpu_task_list_pop_front(list);
+		int res = push_task_to_first_suitable_parent(node, task, sched_ctx_id);
+		if(res)
+		{
+			starpu_task_list_push_front(list,task);
+			return res;
+		}
+	}
+	return 0;
+}

+ 15 - 3
src/sched_policies/node_sched.h

@@ -108,6 +108,7 @@ int _starpu_sched_node_worker_get_workerid(struct _starpu_sched_node * worker_no
 
 struct _starpu_sched_node * _starpu_sched_node_fifo_create(void);
 int _starpu_sched_node_is_fifo(struct _starpu_sched_node * node);
+struct starpu_task_list  _starpu_sched_node_fifo_get_non_executable_tasks(struct _starpu_sched_node * fifo_node);
 
 /* struct _starpu_sched_node * _starpu_sched_node_work_stealing_create(void); */
 int _starpu_sched_node_is_work_stealing(struct _starpu_sched_node * node);
@@ -116,8 +117,9 @@ struct _starpu_sched_node * _starpu_sched_node_random_create(void);
 
 struct _starpu_sched_node * _starpu_sched_node_eager_create(void);
 
-struct _starpu_sched_node * _starpu_sched_node_heft_create();
+struct _starpu_sched_node * _starpu_sched_node_heft_create(void);
 
+int _starpu_sched_node_is_heft(struct _starpu_sched_node * node);
 
 /* compute predicted_end by taking in account the case of the predicted transfer and the predicted_end overlap
  */
@@ -133,9 +135,19 @@ void _starpu_node_destroy_rec(struct _starpu_sched_node * node, unsigned sched_c
 int _starpu_tree_push_task(struct starpu_task * task);
 struct starpu_task * _starpu_tree_pop_task(unsigned sched_ctx_id);
 
-//this function must be called after all modification of tree
+/* this function must be called after all modification of tree
+ * this function make a top bottom traversal , ence dont use .fathers field
+ * if the tree is partialy shared between contexts, this function have to be called in thoses contexts
+ */
 void _starpu_tree_update_after_modification(struct _starpu_sched_tree * tree);
+/* remove and return a subtree that contain only this worker and call starpu_tree_update_after_modification
+ * this function may be called several time
+ * this function dont update father fields in subtree
+ */
+struct _starpu_sched_node * _starpu_sched_tree_remove_worker(struct _starpu_sched_tree * tree, int workerid, int sched_ctx_id);
 
-
+/* push task of list lower as possible in the tree, a non null value is returned if some task couldn't be pushed
+ */
+int _starpu_sched_node_push_tasks_to_firsts_suitable_parent(struct _starpu_sched_node * node, struct starpu_task_list * list, int sched_ctx_id);
 
 #endif