sort_data_handles.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2010-2011, 2014-2016 Université de Bordeaux
  4. * Copyright (C) 2010, 2011, 2015 CNRS
  5. * Copyright (C) 2015 Inria
  6. *
  7. * StarPU is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation; either version 2.1 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * StarPU is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. *
  16. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  17. */
  18. #include <starpu.h>
  19. #include <common/config.h>
  20. #include <datawizard/filters.h>
  21. #include <datawizard/sort_data_handles.h>
  22. /* To avoid deadlocks in case we have multiple tasks accessing the same piece
  23. * of data (eg. task T1 needs A and B, and T2 needs B and A), we need to lock
  24. * them in order, so that we need a total order over data. We must also not
  25. * lock a child before its parent. */
  26. static void find_data_path(struct _starpu_data_state *data, unsigned path[])
  27. {
  28. unsigned depth = data->depth;
  29. struct _starpu_data_state *current = data;
  30. /* Compute the path from the root to the data */
  31. unsigned level; /* level is the distance between the node and the current node */
  32. for (level = 0; level < depth; level++)
  33. {
  34. path[depth - level - 1] = current->sibling_index;
  35. current = current->father_handle;
  36. }
  37. }
  38. static int _compar_data_paths(const unsigned pathA[], unsigned depthA,
  39. const unsigned pathB[], unsigned depthB)
  40. {
  41. unsigned level;
  42. unsigned depth = STARPU_MIN(depthA, depthB);
  43. for (level = 0; level < depth; level++)
  44. {
  45. if (pathA[level] != pathB[level])
  46. return (pathA[level] < pathB[level])?-1:1;
  47. }
  48. /* If this is the same path */
  49. if (depthA == depthB)
  50. return 0;
  51. /* A is a subdata of B or B is a subdata of A, so the smallest one is
  52. * the father of the other (we take this convention). */
  53. return (depthA < depthB)?-1:1;
  54. }
  55. /* A comparision function between two handles makes it possible to use qsort to
  56. * sort a list of handles */
  57. static int _starpu_compar_handles(const struct _starpu_data_descr *descrA,
  58. const struct _starpu_data_descr *descrB)
  59. {
  60. struct _starpu_data_state *dataA = descrA->handle;
  61. struct _starpu_data_state *dataB = descrB->handle;
  62. /* Perhaps we have the same piece of data */
  63. if (dataA == dataB)
  64. {
  65. /* Process write requests first, this is needed for proper
  66. * locking, see _submit_job_enforce_data_deps,
  67. * _starpu_fetch_task_input, and _starpu_push_task_output */
  68. if (descrA->mode & STARPU_W)
  69. {
  70. if (descrB->mode & STARPU_W)
  71. /* Both A and B write, take the reader first */
  72. if (descrA->mode & STARPU_R)
  73. return -1;
  74. else
  75. return 1;
  76. else
  77. /* Only A writes, take it first */
  78. return -1;
  79. }
  80. else
  81. /* A doesn't write, take B before */
  82. return 1;
  83. }
  84. /* Put arbitered accesses after non-arbitered */
  85. if (dataA->arbiter && !(dataB->arbiter))
  86. return 1;
  87. if (dataB->arbiter && !(dataA->arbiter))
  88. return -1;
  89. if (dataA->arbiter != dataB->arbiter)
  90. /* Both are arbitered, sort by arbiter pointer order */
  91. return ((dataA->arbiter < dataB->arbiter)?-1:1);
  92. /* If both are arbitered by the same arbiter (or they are both not
  93. * arbitered), we'll sort them by handle */
  94. /* In case we have data/subdata from different trees */
  95. if (dataA->root_handle != dataB->root_handle)
  96. return ((dataA->root_handle < dataB->root_handle)?-1:1);
  97. /* Things get more complicated: we need to find the location of dataA
  98. * and dataB within the tree. */
  99. unsigned dataA_path[dataA->depth];
  100. unsigned dataB_path[dataB->depth];
  101. find_data_path(dataA, dataA_path);
  102. find_data_path(dataB, dataB_path);
  103. return _compar_data_paths(dataA_path, dataA->depth, dataB_path, dataB->depth);
  104. }
  105. static int _starpu_compar_buffer_descr(const void *_descrA, const void *_descrB)
  106. {
  107. const struct _starpu_data_descr *descrA = (const struct _starpu_data_descr *) _descrA;
  108. const struct _starpu_data_descr *descrB = (const struct _starpu_data_descr *) _descrB;
  109. return _starpu_compar_handles(descrA, descrB);
  110. }
  111. /* The descr array will be overwritten, so this must be a copy ! */
  112. void _starpu_sort_task_handles(struct _starpu_data_descr descr[], unsigned nbuffers)
  113. {
  114. qsort(descr, nbuffers, sizeof(descr[0]), _starpu_compar_buffer_descr);
  115. }