Explorar o código

eager, random and ws now works. ws seems to have a problem with priorities

Simon Archipoff %!s(int64=12) %!d(string=hai) anos
pai
achega
09fbee829b

+ 9 - 3
src/Makefile.am

@@ -119,7 +119,8 @@ noinst_HEADERS = 						\
 	starpu_parameters.h					\
 	top/starpu_top_message_queue.h				\
 	top/starpu_top_connection.h				\
-	top/starpu_top_core.h
+	top/starpu_top_core.h					\
+	sched_policies/node_sched.h
 
 libstarpu_@STARPU_EFFECTIVE_VERSION@_la_SOURCES = 						\
 	common/barrier.c					\
@@ -219,8 +220,13 @@ libstarpu_@STARPU_EFFECTIVE_VERSION@_la_SOURCES = 						\
 	top/starpu_top_task.c					\
 	top/starpu_top_message_queue.c				\
 	top/starpu_top_connection.c                          	\
-	worker_collection/worker_list.c
-
+	worker_collection/worker_list.c				\
+	sched_policies/node_sched.c				\
+	sched_policies/node_eager.c				\
+	sched_policies/node_random.c				\
+	sched_policies/node_work_stealing.c			\
+	sched_policies/node_worker.c				\
+	sched_policies/node_fifo.c
 if STARPU_USE_CPU
 libstarpu_@STARPU_EFFECTIVE_VERSION@_la_SOURCES += drivers/cpu/driver_cpu.c
 endif

+ 1 - 1
src/core/jobs.c

@@ -444,7 +444,7 @@ int _starpu_push_local_task(struct _starpu_worker *worker, struct starpu_task *t
 
 	STARPU_PTHREAD_MUTEX_LOCK(&worker->sched_mutex);
 
-	if (back)
+	if (prio == starpu_sched_get_max_priority())
 		starpu_task_list_push_front(&worker->local_tasks, task);
 	else
 		starpu_task_list_push_back(&worker->local_tasks, task);

+ 3 - 0
src/core/sched_policy.c

@@ -43,6 +43,9 @@ static struct starpu_sched_policy *predefined_policies[] =
 	&_starpu_sched_dmda_sorted_policy,
 	&_starpu_sched_parallel_heft_policy,
 	&_starpu_sched_peager_policy,
+	&_starpu_sched_tree_eager_policy,
+	&_starpu_sched_tree_random_policy,
+	&_starpu_sched_tree_ws_policy,
 	NULL
 };
 

+ 3 - 1
src/core/sched_policy.h

@@ -65,6 +65,8 @@ extern struct starpu_sched_policy _starpu_sched_dmda_sorted_policy;
 extern struct starpu_sched_policy _starpu_sched_eager_policy;
 extern struct starpu_sched_policy _starpu_sched_parallel_heft_policy;
 extern struct starpu_sched_policy _starpu_sched_peager_policy;
-
+extern struct starpu_sched_policy _starpu_sched_tree_eager_policy;
+extern struct starpu_sched_policy _starpu_sched_tree_random_policy;
+extern struct starpu_sched_policy _starpu_sched_tree_ws_policy;
 
 #endif // __SCHED_POLICY_H__

+ 2 - 1
src/sched_policies/node_eager.c

@@ -1,6 +1,7 @@
-#include "node_sched.h"
 #include <common/thread.h>
 #include <core/sched_policy.h>
+#include "node_sched.h"
+#include "fifo_queues.h"
 /*
 static void _starpu_wake_all_interested_workers(struct starpu_task * task){
 	struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(task->sched_ctx);

+ 11 - 4
src/sched_policies/node_fifo.c

@@ -1,10 +1,10 @@
-#include <node_sched.h>
+#include "node_sched.h"
 #include "fifo_queues.h"
 
 static int push_task(struct _starpu_sched_node * node, struct starpu_task * task)
 {
 	STARPU_PTHREAD_MUTEX_LOCK(&node->mutex);
-	int ret = _starpu_push_sorted_task(node->data, task);
+	int ret = _starpu_fifo_push_sorted_task(node->data, task);
 	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
 	return ret;
 }
@@ -12,11 +12,11 @@ static int push_task(struct _starpu_sched_node * node, struct starpu_task * task
 static struct starpu_task *  pop_task(struct _starpu_sched_node * node, unsigned sched_ctx_id)
 {
 	STARPU_PTHREAD_MUTEX_LOCK(&node->mutex);
-	struct starpu_task * task  = _starpu_pop(node->data, starpu_get_worker_id());
+	struct starpu_task * task  = _starpu_fifo_pop_task(node->data, starpu_worker_get_id());
 	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
 	if(task)
 		return task;
-	struct _starpu_sched_node * father = node->father[sched_ctx_id];
+	struct _starpu_sched_node * father = node->fathers[sched_ctx_id];
 	if(father)
 		return father->pop_task(father,sched_ctx_id);
 	return NULL;
@@ -31,3 +31,10 @@ struct _starpu_sched_node * _starpu_sched_node_fifo_create(void)
 	node->pop_task = pop_task;
 	return node;
 }
+
+
+struct _starpu_fifo_taskq *  _starpu_node_fifo_get_fifo(struct _starpu_sched_node * node)
+{
+	STARPU_ASSERT(node->push_task == push_task);
+	return node->data;
+}

+ 3 - 4
src/sched_policies/node_random.c

@@ -22,7 +22,7 @@ static double compute_relative_speedup(struct _starpu_sched_node * node)
 	return sum;
 }
 
-static void update_relative_childs_speedup(struct _starpu_sched_node * node,int former_nchilds STARPU_ATTRIBUTE_UNUSED)
+static void update_relative_childs_speedup(struct _starpu_sched_node * node)
 {
 	struct _starpu_random_data * rd = node->data;
 	rd->relative_speedup = realloc(rd->relative_speedup,sizeof(double) * node->nchilds);
@@ -98,7 +98,6 @@ struct _starpu_sched_node * _starpu_sched_node_random_create(void)
 	struct _starpu_random_data * rd = malloc(sizeof(struct _starpu_random_data));
 	rd->relative_speedup = NULL;
 	node->data = rd;
-	node->update_nchilds = update_relative_childs_speedup;
 	node->destroy_node = destroy_random_node;
 	node->push_task = push_task;
 	node->add_child = add_child;
@@ -131,7 +130,7 @@ static void add_worker_random(unsigned sched_ctx_id, int * workerids, unsigned n
 		_starpu_sched_node_add_child(t->root,
 					     _starpu_sched_node_worker_get(workerids[i]),
 					     sched_ctx_id);
-	update_relative_childs_speedup(t->root,42 /*unused*/);
+	update_relative_childs_speedup(t->root);
 	_starpu_tree_update_after_modification(t);
 }
 
@@ -143,7 +142,7 @@ static void remove_worker_random(unsigned sched_ctx_id, int * workerids, unsigne
 		_starpu_sched_node_remove_child(t->root,
 						_starpu_sched_node_worker_get(workerids[i]),
 						sched_ctx_id);
-	update_relative_childs_speedup(t->root,42 /*unused*/);
+	update_relative_childs_speedup(t->root);
 	_starpu_tree_update_after_modification(t);
 }
 

+ 1 - 5
src/sched_policies/node_sched.c

@@ -1,6 +1,6 @@
-#include "node_sched.h"
 #include <core/jobs.h>
 #include <core/workers.h>
+#include "node_sched.h"
 
 static void available(struct _starpu_sched_node * node)
 {
@@ -123,8 +123,6 @@ void _starpu_sched_node_add_child(struct _starpu_sched_node* node, struct _starp
 	node->childs[node->nchilds] = child;
 	child->fathers[sched_ctx_id] = node;
 	node->nchilds++;
-	if(node->update_nchilds)
-		node->update_nchilds(node, node->nchilds - 1);
 	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
 }
 void _starpu_sched_node_remove_child(struct _starpu_sched_node * node, struct _starpu_sched_node * child,unsigned sched_ctx_id)
@@ -137,8 +135,6 @@ void _starpu_sched_node_remove_child(struct _starpu_sched_node * node, struct _s
 	node->childs[pos] = node->childs[--node->nchilds];
 	STARPU_ASSERT(child->fathers[sched_ctx_id] == node);
 	child->fathers[sched_ctx_id] = NULL;
-	if(node->update_nchilds)
-		node->update_nchilds(node, node->nchilds + 1);
 	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
 }
 

+ 10 - 5
src/sched_policies/node_sched.h

@@ -74,10 +74,14 @@ void _starpu_sched_node_worker_destroy(struct _starpu_sched_node *);
 int _starpu_sched_node_is_worker(struct _starpu_sched_node * node);
 int _starpu_sched_node_worker_get_workerid(struct _starpu_sched_node * worker_node);
 
+struct _starpu_sched_node * _starpu_sched_node_fifo_create(void);
+struct _starpu_fifo_taskq *  _starpu_node_fifo_get_fifo(struct _starpu_sched_node *);
+
 //struct _starpu_sched_node * _starpu_sched_node_work_stealing_create(void);
 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_eager_create(void);
+
 
 
 void _starpu_tree_destroy(struct _starpu_sched_tree * tree, unsigned sched_ctx_id);
@@ -89,9 +93,10 @@ 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);
-void _starpu_tree_update_after_modification(struct _starpu_sched_tree * tree);
 
-
-extern struct starpu_sched_policy _starpu_sched_tree_eager_policy;
-extern struct starpu_sched_policy _starpu_sched_tree_random_policy;
+//this function must be called after all modification of tree
+void _starpu_tree_update_after_modification(struct _starpu_sched_tree * tree);
+;
+//extern struct starpu_sched_policy _starpu_sched_tree_eager_policy;
+//extern struct starpu_sched_policy _starpu_sched_tree_random_policy;
 #endif

+ 341 - 66
src/sched_policies/node_work_stealing.c

@@ -1,57 +1,291 @@
 #include "node_sched.h"
+#include "fifo_queues.h"
+#include <starpu_scheduler.h>
 
 struct _starpu_work_stealing_data
 {
 	/* keep track of the work performed from the beginning of the algorithm to make
-	 * better decisions about which queue to select when stealing or deferring work
+	 * better decisions about which queue to child when stealing or deferring work
 	 */
 	
 	unsigned performed_total;
-	unsigned last_pop_worker;
-	unsigned last_push_worker;
+	unsigned last_pop_child;
+	unsigned last_push_child;
 };
-//
-///* little dirty hack here, fifo_nodes under the workstealing node need to know wich child they are in order to push task on themselfs
-// */
-//struct _starpu_fifo_ws_data {
-//	struct _starpu_fifo_taskq *fifo;
-//	int rank;
-//};
-//
-//static void destroy_fifo_ws(struct _starpu_sched_node * node)
-//{
-//	struct _starpu_fifo_ws_data * fwsd = node->data;
-//	_starpu_destroy_fifo(fwsd->fifo);
-//	free(fwsd);
-//	_starpu_sched_node_destroy(node);
-//}
-//
-//static int fifo_ws_push_task(struct _starpu_sched_node * node,
-//			     struct starpu_task * task)
-//{
-//	STARPU_PTHREAD_MUTEX_LOCK(&node->mutex);
-//	struct _starpu_fifo_ws_data * fwsd = node->data;
-//	int ret_val =  _starpu_push_sorted_task(node->data, task);
-//	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
-//	return ret_val;
-//}
-//
-//static starpu_task * fifo_ws_pop_task(struct _starpu_sched_node * node,
-//				      unsigned sched_ctx_id)
-//{
-//	STARPU_PTHREAD_MUTEX_LOCK(&node->mutex);
-//	int ret_val =  _starpu_push_sorted_task(node->data, task);
-//	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
-//	return ret_val;
-//}
-//
 
 
+
+#ifdef USE_OVERLOAD
+/**
+ * Minimum number of task we wait for being processed before we start assuming
+ * on which child the computation would be faster.
+ */
+static int calibration_value = 0;
+
+#endif /* USE_OVERLOAD */
+
+
+/**
+ * Return a child from which a task can be stolen.
+ * Selecting a worker is done in a round-robin fashion, unless
+ * the child previously selected doesn't own any task,
+ * then we return the first non-empty worker.
+ * and take his mutex
+ *
+ * if no child have task, return -1 and dont take any mutex
+ */
+static unsigned select_victim_round_robin(struct _starpu_sched_node *node)
+{
+	struct _starpu_work_stealing_data *ws = node->data;
+	int i = (ws->last_pop_child + 1) % node->nchilds;
+
+	starpu_pthread_mutex_t *victim_sched_mutex;
+
+	/* If the worker's queue is empty, let's try
+	 * the next ones */
+	while (1)
+	{
+		unsigned ntasks;
+		struct _starpu_sched_node * child = node->childs[i];
+		struct _starpu_fifo_taskq * fifo = _starpu_node_fifo_get_fifo(child);
+		victim_sched_mutex = &child->mutex;
+		STARPU_PTHREAD_MUTEX_LOCK(victim_sched_mutex);
+		ntasks = fifo->ntasks;
+		if (ntasks)
+			break;
+		STARPU_PTHREAD_MUTEX_UNLOCK(victim_sched_mutex);
+		i = (i + 1) % node->nchilds;
+		if ((unsigned) i == ws->last_pop_child)
+		{
+			/* We got back to the first worker,
+			 * don't go in infinite loop */
+			return -1;
+		}
+	}
+
+	ws->last_pop_child = i;
+
+	return i;
+}
+
+/**
+ * Return a worker to whom add a task.
+ * Selecting a worker is done in a round-robin fashion.
+ */
+static unsigned select_worker_round_robin(struct _starpu_sched_node * node)
+{
+	struct _starpu_work_stealing_data *ws = (struct _starpu_work_stealing_data*)node->data;
+	unsigned i = (ws->last_push_child + 1) % node->nchilds ;
+	ws->last_push_child = i;
+	return i;
+}
+#undef USE_OVERLOAD
+#ifdef USE_OVERLOAD
+
+/**
+ * Return a ratio helpful to determine whether a worker is suitable to steal
+ * tasks from or to put some tasks in its queue.
+ *
+ * \return	a ratio with a positive or negative value, describing the current state of the worker :
+ * 		a smaller value implies a faster worker with an relatively emptier queue : more suitable to put tasks in
+ * 		a bigger value implies a slower worker with an reletively more replete queue : more suitable to steal tasks from
+ */
+static float overload_metric(unsigned sched_ctx_id, unsigned id)
+{
+	struct _starpu_work_stealing_data *ws = (struct _starpu_work_stealing_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	float execution_ratio = 0.0f;
+	float current_ratio = 0.0f;
+
+	int nprocessed = _starpu_get_deque_nprocessed(ws->queue_array[id]);
+	unsigned njobs = _starpu_get_deque_njobs(ws->queue_array[id]);
+
+	/* Did we get enough information ? */
+	if (performed_total > 0 && nprocessed > 0)
+	{
+		/* How fast or slow is the worker compared to the other workers */
+		execution_ratio = (float) nprocessed / performed_total;
+		/* How replete is its queue */
+		current_ratio = (float) njobs / nprocessed;
+	}
+	else
+	{
+		return 0.0f;
+	}
+
+	return (current_ratio - execution_ratio);
+}
+
+/**
+ * Return the most suitable worker from which a task can be stolen.
+ * The number of previously processed tasks, total and local,
+ * and the number of tasks currently awaiting to be processed
+ * by the tasks are taken into account to select the most suitable
+ * worker to steal task from.
+ */
+static unsigned select_victim_overload(unsigned sched_ctx_id)
+{
+	unsigned worker;
+	float  worker_ratio;
+	unsigned best_worker = 0;
+	float best_ratio = FLT_MIN;
+
+	/* Don't try to play smart until we get
+	 * enough informations. */
+	if (performed_total < calibration_value)
+		return select_victim_round_robin(sched_ctx_id);
+
+	struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx_id);
+
+	struct starpu_sched_ctx_iterator it;
+        if(workers->init_iterator)
+                workers->init_iterator(workers, &it);
+
+	while(workers->has_next(workers, &it))
+        {
+                worker = workers->get_next(workers, &it);
+		worker_ratio = overload_metric(sched_ctx_id, worker);
+
+		if (worker_ratio > best_ratio)
+		{
+			best_worker = worker;
+			best_ratio = worker_ratio;
+		}
+	}
+
+	return best_worker;
+}
+
+/**
+ * Return the most suitable worker to whom add a task.
+ * The number of previously processed tasks, total and local,
+ * and the number of tasks currently awaiting to be processed
+ * by the tasks are taken into account to select the most suitable
+ * worker to add a task to.
+ */
+static unsigned select_worker_overload(unsigned sched_ctx_id)
+{
+	unsigned worker;
+	float  worker_ratio;
+	unsigned best_worker = 0;
+	float best_ratio = FLT_MAX;
+
+	/* Don't try to play smart until we get
+	 * enough informations. */
+	if (performed_total < calibration_value)
+		return select_worker_round_robin(sched_ctx_id);
+
+	struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx_id);
+
+	struct starpu_sched_ctx_iterator it;
+        if(workers->init_iterator)
+                workers->init_iterator(workers, &it);
+
+	while(workers->has_next(workers, &it))
+        {
+                worker = workers->get_next(workers, &it);
+
+		worker_ratio = overload_metric(sched_ctx_id, worker);
+
+		if (worker_ratio < best_ratio)
+		{
+			best_worker = worker;
+			best_ratio = worker_ratio;
+		}
+	}
+
+	return best_worker;
+}
+
+#endif /* USE_OVERLOAD */
+
+
+/**
+ * Return a worker from which a task can be stolen.
+ * This is a phony function used to call the right
+ * function depending on the value of USE_OVERLOAD.
+ */
+static inline int select_victim(struct _starpu_sched_node * node)
+{
+#ifdef USE_OVERLOAD
+	return select_victim_overload(node);
+#else
+	return select_victim_round_robin(node);
+#endif /* USE_OVERLOAD */
+}
+
+/**
+ * Return a worker from which a task can be stolen.
+ * This is a phony function used to call the right
+ * function depending on the value of USE_OVERLOAD.
+ */
+static inline unsigned select_worker(struct _starpu_sched_node * node)
+{
+#ifdef USE_OVERLOAD
+	return select_worker_overload(node);
+#else
+	return select_worker_round_robin(node);
+#endif /* USE_OVERLOAD */
+}
+
+
+static struct starpu_task * pop_task(struct _starpu_sched_node * node, unsigned sched_ctx_id)
+{
+	int victim = select_victim(node);
+	if(victim < 0)
+	{
+		if(node->fathers[sched_ctx_id])
+			return node->fathers[sched_ctx_id]->pop_task(node->fathers[sched_ctx_id],sched_ctx_id);
+		else
+			return NULL;
+	}
+	struct _starpu_sched_node * child = node->childs[victim];
+	struct _starpu_fifo_taskq * fifo = _starpu_node_fifo_get_fifo(child);
+	struct starpu_task * task = _starpu_fifo_pop_task(fifo,
+							  starpu_worker_get_id());
+	fifo->nprocessed--;
+	STARPU_PTHREAD_MUTEX_UNLOCK(&child->mutex);
+	return task;
+}
+
+
+static int push_task(struct _starpu_sched_node * node, struct starpu_task * task)
+{
+	struct _starpu_work_stealing_data * wsd = node->data;
+	int ret = -1;
+	int start = wsd->last_push_child;
+	
+	int i;
+	for(i = (start+1)%node->nchilds; i != start; i = (i+1)%node->nchilds)
+	{
+		struct _starpu_sched_node * child = node->childs[i];
+		if(_starpu_sched_node_can_execute_task(child,task))
+		{
+			ret = child->push_task(child,task);
+			break;
+		}
+	}
+	if(i == start)
+		ret = -ENODEV;
+	wsd->last_push_child = i;
+	return ret;
+}
+
+
+static void add_child(struct _starpu_sched_node *node,
+		      struct _starpu_sched_node *child,
+		      unsigned sched_ctx_id);
+//compute if le father is a work_stealing node
+static int is_my_fifo_node(struct _starpu_sched_node * node, unsigned sched_ctx_id)
+{
+	if(node->fathers[sched_ctx_id] == NULL)
+		return 0;
+	return node->fathers[sched_ctx_id]->add_child == add_child;
+}
+
 //this function is special, when a worker call it, we want to push the task in his fifo
-//because he deserve it.
 int _starpu_ws_push_task(struct starpu_task *task)
 {
-	int workerid = starpu_get_worker_id();
+	int workerid = starpu_worker_get_id();
 	if(workerid == -1)
 		return _starpu_tree_push_task(task);
 	unsigned sched_ctx_id = task->sched_ctx;
@@ -59,25 +293,16 @@ int _starpu_ws_push_task(struct starpu_task *task)
 	while(node->fathers[sched_ctx_id] != NULL)
 	{
 		node = node->fathers[sched_ctx_id];
-		if(is_my_fifo_node(node))
+		if(is_my_fifo_node(node,sched_ctx_id))
 		{
 			STARPU_PTHREAD_MUTEX_LOCK(&node->mutex);
-			int ret_val =  _starpu_push_sorted_task(node->data, task);
+			int ret_val =  _starpu_fifo_push_sorted_task(node->data, task);
 			STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
 			return ret_val;
 		}
 	}
 	//there were a problem here, dont know what to do
 	return _starpu_tree_push_task(task);
-
-}
-static struct _starpu_sched_node * fifo_ws_create(void)
-{
-	struct _starpu_sched_node * node = _starpu_sched_node_create();
-	struct _starpu_fifo_ws_data * fwsd = malloc(sizeof(struct _starpu_fifo_ws_data));
-	fwsd->fifo = _starpu_create_fifo();
-	node->data = fwsd;
-	return node;
 }
 
 
@@ -95,6 +320,9 @@ static void add_child(struct _starpu_sched_node *node,
 			       sizeof(struct _starpu_sched_node*)
 			       * (node->nchilds + 1));
 	struct _starpu_sched_node * fifo_node = _starpu_sched_node_fifo_create();
+	_starpu_sched_node_add_child(fifo_node, child, sched_ctx_id);
+
+
 	_starpu_sched_node_set_father(fifo_node, node, sched_ctx_id);
 	node->childs[node->nchilds] = fifo_node;
 	node->nchilds++;
@@ -114,7 +342,7 @@ static void remove_child(struct _starpu_sched_node *node,
 	STARPU_ASSERT(pos != node->nchilds);
 	struct _starpu_sched_node * fifo_node = node->childs[pos];
 	node->childs[pos] = node->childs[--node->nchilds];
-	STARPU_ASSERT(fifo_node->fathers[sched_ctx_id] == node;
+	STARPU_ASSERT(fifo_node->fathers[sched_ctx_id] == node);
 	fifo_node->fathers[sched_ctx_id] = NULL;
 	STARPU_PTHREAD_MUTEX_UNLOCK(&node->mutex);
 }
@@ -126,23 +354,70 @@ struct _starpu_sched_node * _starpu_sched_node_work_stealing_create(void)
 	struct _starpu_sched_node * node = _starpu_sched_node_create();
 	struct _starpu_work_stealing_data * wsd = malloc(sizeof(*wsd));
 	wsd->performed_total = 0;
-	wsd->last_pop_worker = 0;
-	wsd->last_push_worker = 0;
+	wsd->last_pop_child = 0;
+	wsd->last_push_child = 0;
+	node->data = wsd;
+	node->pop_task = pop_task;
+	node->push_task = push_task;
+	node->add_child = add_child;
+	node->remove_child = remove_child;
 	return node;
 }
 
-static int push_task(struct _starpu_sched_node * node, struct starpu_task * task)
+
+
+static void initialize_ws_center_policy(unsigned sched_ctx_id)
 {
-	struct _starpu_work_stealing_data * wsd = node->data;
-	int ret = -1;
-	int start = wsd->last_pop_worker;
-	
-	int i;
-	for(i = start + 1; i != start; (i+1)%node->nchilds)
-	{
-		if(!childs[i]->fifo)
-			continue;
-		ret = _starpu_fifo_push_sorted_task(childs[i]->fifo, task);
-	}
+	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_MUTEX_INIT(&data->mutex,NULL);
+ 	data->root = _starpu_sched_node_work_stealing_create();
 	
+	starpu_sched_ctx_set_policy_data(sched_ctx_id, (void*)data);
 }
+
+static void deinitialize_ws_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_ws(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
+{
+	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	unsigned i;
+	for(i = 0; i < nworkers; i++)
+		t->root->add_child(t->root,
+				   _starpu_sched_node_worker_get(workerids[i]),
+				   sched_ctx_id);
+	_starpu_tree_update_after_modification(t);
+}
+
+static void remove_worker_ws(unsigned sched_ctx_id, int * workerids, unsigned nworkers)
+{
+	struct _starpu_sched_tree *t = starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	unsigned i;
+	for(i = 0; i < nworkers; i++)
+		t->root->remove_child(t->root,
+				   _starpu_sched_node_worker_get(workerids[i]),
+				   sched_ctx_id);
+
+}
+
+
+struct starpu_sched_policy _starpu_sched_tree_ws_policy =
+{
+	.init_sched = initialize_ws_center_policy,
+	.deinit_sched = deinitialize_ws_center_policy,
+	.add_workers = add_worker_ws,
+	.remove_workers = remove_worker_ws,
+	.push_task = _starpu_ws_push_task,
+	.pop_task = _starpu_tree_pop_task,
+	.pre_exec_hook = NULL,
+	.post_exec_hook = NULL,
+	.pop_every_task = NULL,
+	.policy_name = "tree-ws",
+	.policy_description = "work stealing tree policy"
+};