Browse Source

document commute algorithm

Samuel Thibault 10 years ago
parent
commit
2157700e4c

+ 56 - 38
src/core/dependencies/data_commute_concurrency.c

@@ -23,44 +23,62 @@
 
 //#define NO_LOCK_OR_DELEGATE
 
-/* Here are the high level algorithms which have been discussed in order
- * to manage the commutes.
-    Pour chaque handle h en commute:
-        mutex_lock(&arbiter)
-        relâcher h
-        Pour chaque tâche Tc en attente sur le handle:
-            // Juste tester si on peut prendre:
-            Pour chaque donnée Tc_h qu’il attend:
-                Si Tc_h est occupé, goto fail
-            // Vraiment prendre
-            Pour chaque donnée Tc_h qu’il attend:
-                lock(Tc_h)
-                prendre(h) (il devrait être encore disponible si tout le reste utilise bien le mutex arbiter)
-                lock(Tc_h)
-            // on a trouvé quelqu’un, on a fini!
-            _starpu_push_task(Tc);
-            break;
-            fail:
-                // Pas de bol, on essaie une autre tâche
-                continue;
-        // relâcher un peu le mutex arbiter de temps en temps
-        mutex_unlock(&arbiter)
-
-    mutex_lock(&arbiter)
-    Pour chaque handle h en commute:
-        lock(h)
-        essayer de prendre h, si échec goto fail;
-        unlock(h)
-        mutex_unlock(&arbiter)
-        return 0
-
-        fail:
-            // s’enregistrer sur la liste des requêtes de h
-            Pour chaque handle déjà pris:
-                lock(handle)
-                relâcher handle
-                unlock(handle)
-     mutex_unlock(&arbiter)
+/*
+ * This implements a solution for the dining philosophers problem (see
+ * data_concurrency.c for the rationale) based on a centralized arbiter.  This
+ * allows to get a more parallel solution than the Dijkstra solution, by
+ * avoiding strictly serialized executions, and instead opportunistically find
+ * which tasks can take data.
+ *
+ * These are the algorithms implemented below:
+ *
+ *
+ * at termination of task T:
+ *
+ * - for each handle h of T:
+ *   - mutex_lock(&arbiter)
+ *   - release reference on h
+ *   - for each task Tc waiting for h:
+ *     - for each data Tc_h it is waiting:
+ *       - if Tc_h is busy, goto fail
+ *     // Ok, now really take them
+ *     - For each data Tc_h it is waiting:
+ *       - lock(Tc_h)
+ *       - take reference on h (it should be still available since we hold the arbiter)
+ *       - unlock(Tc_h)
+ *     // Ok, we managed to find somebody, we're finished!
+ *     _starpu_push_task(Tc);
+ *     break;
+ *     fail:
+ *       // No luck, let's try another task
+ *       continue;
+ *   // Release the arbiter mutex a bit from time to time
+ *   - mutex_unlock(&arbiter)
+ *
+ *
+ * at submission of task T:
+ *
+ * - mutex_lock(&arbiter)
+ * - for each handle h of T:
+ *   - lock(h)
+ *   - try to take a reference on h, goto fail on failure
+ *   - unlock(h)
+ * // Success!
+ * - mutex_unlock(&arbiter);
+ * - return 0;
+ *
+ * fail:
+ * // couldn't take everything, abort and record task T
+ * // drop spurious references
+ * - for each handle h of T already taken:
+ *   - lock(h)
+ *   - release reference on h
+ *   - unlock(h)
+ * // record T on the list of requests for h
+ * - for each handle h of T:
+ *   - record T as waiting on h
+ * - mutex_unlock(&arbiter)
+ * - return 1;
  */
 
 /* Here are the LockOrDelegate functions

+ 3 - 0
src/core/dependencies/data_concurrency.c

@@ -50,6 +50,9 @@
  *
  * The same mechanism is used for application data aquisition
  * (starpu_data_acquire).
+ *
+ * For COMMUTE data, we have a second step, performed after this first step,
+ * implemented in data_commute_concurrency.c
  */
 
 /*