cean_util.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. Copyright (c) 2014 Intel Corporation. All Rights Reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions
  5. are met:
  6. * Redistributions of source code must retain the above copyright
  7. notice, this list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. * Neither the name of Intel Corporation nor the names of its
  12. contributors may be used to endorse or promote products derived
  13. from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  15. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  16. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  17. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  18. HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  19. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  20. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "cean_util.h"
  27. #include "offload_common.h"
  28. // 1. allocate element of CeanReadRanges type
  29. // 2. initialized it for reading consequently contiguous ranges
  30. // described by "ap" argument
  31. CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap)
  32. {
  33. CeanReadRanges * res;
  34. // find the max contiguous range
  35. int64_t rank = ap->rank - 1;
  36. int64_t length = ap->dim[rank].size;
  37. for (; rank >= 0; rank--) {
  38. if (ap->dim[rank].stride == 1) {
  39. length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
  40. if (rank > 0 && length != ap->dim[rank - 1].size) {
  41. break;
  42. }
  43. }
  44. else {
  45. break;
  46. }
  47. }
  48. res =(CeanReadRanges *)malloc(sizeof(CeanReadRanges) +
  49. (ap->rank - rank) * sizeof(CeanReadDim));
  50. if (res == NULL)
  51. LIBOFFLOAD_ERROR(c_malloc);
  52. res->current_number = 0;
  53. res->range_size = length;
  54. res->last_noncont_ind = rank;
  55. // calculate number of contiguous ranges inside noncontiguous dimensions
  56. int count = 1;
  57. bool prev_is_cont = true;
  58. int64_t offset = 0;
  59. for (; rank >= 0; rank--) {
  60. res->Dim[rank].count = count;
  61. res->Dim[rank].size = ap->dim[rank].stride * ap->dim[rank].size;
  62. count *= (prev_is_cont && ap->dim[rank].stride == 1? 1 :
  63. (ap->dim[rank].upper - ap->dim[rank].lower +
  64. ap->dim[rank].stride) / ap->dim[rank].stride);
  65. prev_is_cont = false;
  66. offset +=(ap->dim[rank].lower - ap->dim[rank].lindex) *
  67. ap->dim[rank].size;
  68. }
  69. res->range_max_number = count;
  70. res -> ptr = (void*)ap->base;
  71. res -> init_offset = offset;
  72. return res;
  73. }
  74. // check if ranges described by 1 argument could be transfered into ranges
  75. // described by 2-nd one
  76. bool cean_ranges_match(
  77. CeanReadRanges * read_rng1,
  78. CeanReadRanges * read_rng2
  79. )
  80. {
  81. return ( read_rng1 == NULL || read_rng2 == NULL ||
  82. (read_rng1->range_size % read_rng2->range_size == 0 ||
  83. read_rng2->range_size % read_rng1->range_size == 0));
  84. }
  85. // Set next offset and length and returns true for next range.
  86. // Returns false if the ranges are over.
  87. bool get_next_range(
  88. CeanReadRanges * read_rng,
  89. int64_t *offset
  90. )
  91. {
  92. if (++read_rng->current_number > read_rng->range_max_number) {
  93. read_rng->current_number = 0;
  94. return false;
  95. }
  96. int rank = 0;
  97. int num = read_rng->current_number - 1;
  98. int64_t cur_offset = 0;
  99. int num_loc;
  100. for (; rank <= read_rng->last_noncont_ind; rank++) {
  101. num_loc = num / read_rng->Dim[rank].count;
  102. cur_offset += num_loc * read_rng->Dim[rank].size;
  103. num = num % read_rng->Dim[rank].count;
  104. }
  105. *offset = cur_offset + read_rng->init_offset;
  106. return true;
  107. }
  108. bool is_arr_desc_contiguous(const arr_desc *ap)
  109. {
  110. int64_t rank = ap->rank - 1;
  111. int64_t length = ap->dim[rank].size;
  112. for (; rank >= 0; rank--) {
  113. if (ap->dim[rank].stride > 1 &&
  114. ap->dim[rank].upper - ap->dim[rank].lower != 0) {
  115. return false;
  116. }
  117. else if (length != ap->dim[rank].size) {
  118. for (; rank >= 0; rank--) {
  119. if (ap->dim[rank].upper - ap->dim[rank].lower != 0) {
  120. return false;
  121. }
  122. }
  123. return true;
  124. }
  125. length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
  126. }
  127. return true;
  128. }
  129. int64_t cean_get_transf_size(CeanReadRanges * read_rng)
  130. {
  131. return(read_rng->range_max_number * read_rng->range_size);
  132. }
  133. static uint64_t last_left, last_right;
  134. typedef void (*fpp)(const char *spaces, uint64_t low, uint64_t high, int esize);
  135. static void generate_one_range(
  136. const char *spaces,
  137. uint64_t lrange,
  138. uint64_t rrange,
  139. fpp fp,
  140. int esize
  141. )
  142. {
  143. OFFLOAD_TRACE(3,
  144. "%s generate_one_range(lrange=%p, rrange=%p, esize=%d)\n",
  145. spaces, (void*)lrange, (void*)rrange, esize);
  146. if (last_left == -1) {
  147. // First range
  148. last_left = lrange;
  149. }
  150. else {
  151. if (lrange == last_right+1) {
  152. // Extend previous range, don't print
  153. }
  154. else {
  155. (*fp)(spaces, last_left, last_right, esize);
  156. last_left = lrange;
  157. }
  158. }
  159. last_right = rrange;
  160. }
  161. static void generate_mem_ranges_one_rank(
  162. const char *spaces,
  163. uint64_t base,
  164. uint64_t rank,
  165. const struct dim_desc *ddp,
  166. fpp fp,
  167. int esize
  168. )
  169. {
  170. uint64_t lindex = ddp->lindex;
  171. uint64_t lower = ddp->lower;
  172. uint64_t upper = ddp->upper;
  173. uint64_t stride = ddp->stride;
  174. uint64_t size = ddp->size;
  175. OFFLOAD_TRACE(3,
  176. "%s "
  177. "generate_mem_ranges_one_rank(base=%p, rank=%lld, lindex=%lld, "
  178. "lower=%lld, upper=%lld, stride=%lld, size=%lld, esize=%d)\n",
  179. spaces, (void*)base, rank, lindex, lower, upper, stride, size, esize);
  180. if (rank == 1) {
  181. uint64_t lrange, rrange;
  182. if (stride == 1) {
  183. lrange = base + (lower-lindex)*size;
  184. rrange = lrange + (upper-lower+1)*size - 1;
  185. generate_one_range(spaces, lrange, rrange, fp, esize);
  186. }
  187. else {
  188. for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
  189. lrange = base + i*size;
  190. rrange = lrange + size - 1;
  191. generate_one_range(spaces, lrange, rrange, fp, esize);
  192. }
  193. }
  194. }
  195. else {
  196. for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
  197. generate_mem_ranges_one_rank(
  198. spaces, base+i*size, rank-1, ddp+1, fp, esize);
  199. }
  200. }
  201. }
  202. static void generate_mem_ranges(
  203. const char *spaces,
  204. const arr_desc *adp,
  205. bool deref,
  206. fpp fp
  207. )
  208. {
  209. uint64_t esize;
  210. OFFLOAD_TRACE(3,
  211. "%s "
  212. "generate_mem_ranges(adp=%p, deref=%d, fp)\n",
  213. spaces, adp, deref);
  214. last_left = -1;
  215. last_right = -2;
  216. // Element size is derived from last dimension
  217. esize = adp->dim[adp->rank-1].size;
  218. generate_mem_ranges_one_rank(
  219. // For c_cean_var the base addr is the address of the data
  220. // For c_cean_var_ptr the base addr is dereferenced to get to the data
  221. spaces, deref ? *((uint64_t*)(adp->base)) : adp->base,
  222. adp->rank, &adp->dim[0], fp, esize);
  223. (*fp)(spaces, last_left, last_right, esize);
  224. }
  225. // returns offset and length of the data to be transferred
  226. void __arr_data_offset_and_length(
  227. const arr_desc *adp,
  228. int64_t &offset,
  229. int64_t &length
  230. )
  231. {
  232. int64_t rank = adp->rank - 1;
  233. int64_t size = adp->dim[rank].size;
  234. int64_t r_off = 0; // offset from right boundary
  235. // find the rightmost dimension which takes just part of its
  236. // range. We define it if the size of left rank is not equal
  237. // the range's length between upper and lower boungaries
  238. while (rank > 0) {
  239. size *= (adp->dim[rank].upper - adp->dim[rank].lower + 1);
  240. if (size != adp->dim[rank - 1].size) {
  241. break;
  242. }
  243. rank--;
  244. }
  245. offset = (adp->dim[rank].lower - adp->dim[rank].lindex) *
  246. adp->dim[rank].size;
  247. // find gaps both from the left - offset and from the right - r_off
  248. for (rank--; rank >= 0; rank--) {
  249. offset += (adp->dim[rank].lower - adp->dim[rank].lindex) *
  250. adp->dim[rank].size;
  251. r_off += adp->dim[rank].size -
  252. (adp->dim[rank + 1].upper - adp->dim[rank + 1].lindex + 1) *
  253. adp->dim[rank + 1].size;
  254. }
  255. length = (adp->dim[0].upper - adp->dim[0].lindex + 1) *
  256. adp->dim[0].size - offset - r_off;
  257. }
  258. #if OFFLOAD_DEBUG > 0
  259. void print_range(
  260. const char *spaces,
  261. uint64_t low,
  262. uint64_t high,
  263. int esize
  264. )
  265. {
  266. char buffer[1024];
  267. char number[32];
  268. OFFLOAD_TRACE(3, "%s print_range(low=%p, high=%p, esize=%d)\n",
  269. spaces, (void*)low, (void*)high, esize);
  270. if (console_enabled < 4) {
  271. return;
  272. }
  273. OFFLOAD_TRACE(4, "%s values:\n", spaces);
  274. int count = 0;
  275. buffer[0] = '\0';
  276. while (low <= high)
  277. {
  278. switch (esize)
  279. {
  280. case 1:
  281. sprintf(number, "%d ", *((char *)low));
  282. low += 1;
  283. break;
  284. case 2:
  285. sprintf(number, "%d ", *((short *)low));
  286. low += 2;
  287. break;
  288. case 4:
  289. sprintf(number, "%d ", *((int *)low));
  290. low += 4;
  291. break;
  292. default:
  293. sprintf(number, "0x%016x ", *((uint64_t *)low));
  294. low += 8;
  295. break;
  296. }
  297. strcat(buffer, number);
  298. count++;
  299. if (count == 10) {
  300. OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
  301. count = 0;
  302. buffer[0] = '\0';
  303. }
  304. }
  305. if (count != 0) {
  306. OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
  307. }
  308. }
  309. void __arr_desc_dump(
  310. const char *spaces,
  311. const char *name,
  312. const arr_desc *adp,
  313. bool deref
  314. )
  315. {
  316. OFFLOAD_TRACE(2, "%s%s CEAN expression %p\n", spaces, name, adp);
  317. if (adp != 0) {
  318. OFFLOAD_TRACE(2, "%s base=%llx, rank=%lld\n",
  319. spaces, adp->base, adp->rank);
  320. for (int i = 0; i < adp->rank; i++) {
  321. OFFLOAD_TRACE(2,
  322. "%s dimension %d: size=%lld, lindex=%lld, "
  323. "lower=%lld, upper=%lld, stride=%lld\n",
  324. spaces, i, adp->dim[i].size, adp->dim[i].lindex,
  325. adp->dim[i].lower, adp->dim[i].upper,
  326. adp->dim[i].stride);
  327. }
  328. // For c_cean_var the base addr is the address of the data
  329. // For c_cean_var_ptr the base addr is dereferenced to get to the data
  330. generate_mem_ranges(spaces, adp, deref, &print_range);
  331. }
  332. }
  333. #endif // OFFLOAD_DEBUG