memory_manager.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2013,2015 Inria
  4. * Copyright (C) 2012,2013,2015-2017 CNRS
  5. * Copyright (C) 2013-2015,2017,2018 Université de Bordeaux
  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/utils.h>
  20. #include <common/thread.h>
  21. #include <common/fxt.h>
  22. #include <datawizard/memory_manager.h>
  23. #include <core/workers.h>
  24. #include <starpu_stdlib.h>
  25. static size_t global_size[STARPU_MAXNODES];
  26. static size_t used_size[STARPU_MAXNODES];
  27. /* This is used as an optimization to avoid to wake up allocating threads for
  28. * each and every deallocation, only to find that there is still not enough
  29. * room. */
  30. /* Minimum amount being waited for */
  31. static size_t waiting_size[STARPU_MAXNODES];
  32. static starpu_pthread_mutex_t lock_nodes[STARPU_MAXNODES];
  33. static starpu_pthread_cond_t cond_nodes[STARPU_MAXNODES];
  34. int _starpu_memory_manager_init()
  35. {
  36. int i;
  37. for(i=0 ; i<STARPU_MAXNODES ; i++)
  38. {
  39. global_size[i] = 0;
  40. used_size[i] = 0;
  41. /* This is accessed for statistics outside the lock, don't care
  42. * about that */
  43. STARPU_HG_DISABLE_CHECKING(used_size[i]);
  44. STARPU_HG_DISABLE_CHECKING(global_size[i]);
  45. waiting_size[i] = 0;
  46. STARPU_PTHREAD_MUTEX_INIT(&lock_nodes[i], NULL);
  47. STARPU_PTHREAD_COND_INIT(&cond_nodes[i], NULL);
  48. }
  49. return 0;
  50. }
  51. void _starpu_memory_manager_set_global_memory_size(unsigned node, size_t size)
  52. {
  53. STARPU_PTHREAD_MUTEX_LOCK(&lock_nodes[node]);
  54. if (!global_size[node])
  55. {
  56. global_size[node] = size;
  57. _STARPU_DEBUG("Global size for node %u is %ld\n", node, (long)global_size[node]);
  58. }
  59. else
  60. {
  61. STARPU_ASSERT(global_size[node] == size);
  62. }
  63. STARPU_PTHREAD_MUTEX_UNLOCK(&lock_nodes[node]);
  64. }
  65. size_t _starpu_memory_manager_get_global_memory_size(unsigned node)
  66. {
  67. return global_size[node];
  68. }
  69. int starpu_memory_allocate(unsigned node, size_t size, int flags)
  70. {
  71. int ret;
  72. STARPU_PTHREAD_MUTEX_LOCK(&lock_nodes[node]);
  73. if (flags & STARPU_MEMORY_WAIT)
  74. {
  75. struct _starpu_worker *worker = _starpu_get_local_worker_key();
  76. enum _starpu_worker_status old_status = STATUS_UNKNOWN;
  77. if (worker)
  78. {
  79. old_status = worker->status;
  80. _starpu_set_worker_status(worker, STATUS_WAITING);
  81. }
  82. while (used_size[node] + size > global_size[node])
  83. {
  84. /* Tell deallocators we need this amount */
  85. if (!waiting_size[node] || size < waiting_size[node])
  86. waiting_size[node] = size;
  87. /* Wait for it */
  88. STARPU_PTHREAD_COND_WAIT(&cond_nodes[node], &lock_nodes[node]);
  89. }
  90. if (worker)
  91. {
  92. _starpu_set_worker_status(worker, old_status);
  93. }
  94. /* And take it */
  95. used_size[node] += size;
  96. _STARPU_TRACE_USED_MEM(node, used_size[node]);
  97. ret = 0;
  98. }
  99. else if (flags & STARPU_MEMORY_OVERFLOW
  100. || global_size[node] == 0
  101. || used_size[node] + size <= global_size[node])
  102. {
  103. used_size[node] += size;
  104. _STARPU_TRACE_USED_MEM(node, used_size[node]);
  105. ret = 0;
  106. }
  107. else
  108. {
  109. ret = -ENOMEM;
  110. }
  111. STARPU_PTHREAD_MUTEX_UNLOCK(&lock_nodes[node]);
  112. return ret;
  113. }
  114. void starpu_memory_deallocate(unsigned node, size_t size)
  115. {
  116. STARPU_PTHREAD_MUTEX_LOCK(&lock_nodes[node]);
  117. used_size[node] -= size;
  118. _STARPU_TRACE_USED_MEM(node, used_size[node]);
  119. /* If there's now room for waiters, wake them */
  120. if (waiting_size[node] &&
  121. global_size[node] - used_size[node] >= waiting_size[node])
  122. {
  123. /* And have those not happy enough tell us the size again */
  124. waiting_size[node] = 0;
  125. STARPU_PTHREAD_COND_BROADCAST(&cond_nodes[node]);
  126. }
  127. STARPU_PTHREAD_MUTEX_UNLOCK(&lock_nodes[node]);
  128. }
  129. starpu_ssize_t starpu_memory_get_total(unsigned node)
  130. {
  131. if (global_size[node] == 0)
  132. return -1;
  133. else
  134. return global_size[node];
  135. }
  136. starpu_ssize_t starpu_memory_get_total_all_nodes()
  137. {
  138. unsigned memnodes, i;
  139. memnodes = starpu_memory_nodes_get_count();
  140. starpu_ssize_t total = 0;
  141. for(i=0 ; i<memnodes ; i++)
  142. {
  143. starpu_ssize_t node = starpu_memory_get_total(i);
  144. if (node != -1)
  145. total += node;
  146. }
  147. return total;
  148. }
  149. starpu_ssize_t starpu_memory_get_available(unsigned node)
  150. {
  151. starpu_ssize_t ret;
  152. if (global_size[node] == 0)
  153. return -1;
  154. ret = global_size[node] - used_size[node];
  155. return ret;
  156. }
  157. starpu_ssize_t starpu_memory_get_available_all_nodes()
  158. {
  159. unsigned memnodes, i;
  160. memnodes = starpu_memory_nodes_get_count();
  161. starpu_ssize_t avail = 0;
  162. for(i=0 ; i<memnodes ; i++)
  163. {
  164. starpu_ssize_t node = starpu_memory_get_available(i);
  165. if (node != -1)
  166. avail += node;
  167. }
  168. return avail;
  169. }
  170. void starpu_memory_wait_available(unsigned node, size_t size)
  171. {
  172. STARPU_PTHREAD_MUTEX_LOCK(&lock_nodes[node]);
  173. while (used_size[node] + size > global_size[node])
  174. {
  175. /* Tell deallocators we need this amount */
  176. if (!waiting_size[node] || size < waiting_size[node])
  177. waiting_size[node] = size;
  178. /* Wait for it */
  179. STARPU_PTHREAD_COND_WAIT(&cond_nodes[node], &lock_nodes[node]);
  180. }
  181. STARPU_PTHREAD_MUTEX_UNLOCK(&lock_nodes[node]);
  182. }
  183. int _starpu_memory_manager_test_allocate_size(unsigned node, size_t size)
  184. {
  185. int ret;
  186. if (global_size[node] == 0)
  187. ret = 1;
  188. else if (used_size[node] + size <= global_size[node])
  189. ret = 1;
  190. else
  191. ret = 0;
  192. return ret;
  193. }