cean_util.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. Copyright (c) 2014-2016 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->arr_desc = const_cast<Arr_Desc*>(ap);
  53. res->current_number = 0;
  54. res->range_size = length;
  55. res->last_noncont_ind = rank;
  56. // calculate number of contiguous ranges inside noncontiguous dimensions
  57. int count = 1;
  58. bool prev_is_cont = true;
  59. int64_t offset = 0;
  60. for (; rank >= 0; rank--) {
  61. res->Dim[rank].count = count;
  62. res->Dim[rank].size = ap->dim[rank].stride * ap->dim[rank].size;
  63. count *= (prev_is_cont && ap->dim[rank].stride == 1? 1 :
  64. (ap->dim[rank].upper - ap->dim[rank].lower +
  65. ap->dim[rank].stride) / ap->dim[rank].stride);
  66. prev_is_cont = false;
  67. offset +=(ap->dim[rank].lower - ap->dim[rank].lindex) *
  68. ap->dim[rank].size;
  69. }
  70. res->range_max_number = count;
  71. res -> ptr = (void*)ap->base;
  72. res -> init_offset = offset;
  73. return res;
  74. }
  75. // check if ranges described by 1 argument could be transferred into ranges
  76. // described by 2-nd one
  77. bool cean_ranges_match(
  78. CeanReadRanges * read_rng1,
  79. CeanReadRanges * read_rng2
  80. )
  81. {
  82. return ( read_rng1 == NULL || read_rng2 == NULL ||
  83. (read_rng1->range_size % read_rng2->range_size == 0 ||
  84. read_rng2->range_size % read_rng1->range_size == 0));
  85. }
  86. // Set next offset and length and returns true for next range.
  87. // Returns false if the ranges are over.
  88. bool get_next_range(
  89. CeanReadRanges * read_rng,
  90. int64_t *offset
  91. )
  92. {
  93. if (++read_rng->current_number > read_rng->range_max_number) {
  94. read_rng->current_number = 0;
  95. return false;
  96. }
  97. int rank = 0;
  98. int num = read_rng->current_number - 1;
  99. int64_t cur_offset = 0;
  100. int num_loc;
  101. for (; rank <= read_rng->last_noncont_ind; rank++) {
  102. num_loc = num / read_rng->Dim[rank].count;
  103. cur_offset += num_loc * read_rng->Dim[rank].size;
  104. num = num % read_rng->Dim[rank].count;
  105. }
  106. *offset = cur_offset + read_rng->init_offset;
  107. return true;
  108. }
  109. bool is_arr_desc_contiguous(const Arr_Desc *ap)
  110. {
  111. int64_t rank = ap->rank - 1;
  112. int64_t length = ap->dim[rank].size;
  113. for (; rank >= 0; rank--) {
  114. if (ap->dim[rank].stride > 1 &&
  115. ap->dim[rank].upper - ap->dim[rank].lower != 0) {
  116. return false;
  117. }
  118. else if (length != ap->dim[rank].size) {
  119. for (; rank >= 0; rank--) {
  120. if (ap->dim[rank].upper - ap->dim[rank].lower != 0) {
  121. return false;
  122. }
  123. }
  124. return true;
  125. }
  126. length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
  127. }
  128. return true;
  129. }
  130. int64_t cean_get_transf_size(CeanReadRanges * read_rng)
  131. {
  132. return(read_rng->range_max_number * read_rng->range_size);
  133. }
  134. static uint64_t last_left, last_right;
  135. typedef void (*fpp)(
  136. const char *spaces,
  137. uint64_t low,
  138. uint64_t high,
  139. int esize,
  140. bool print_values
  141. );
  142. static void generate_one_range(
  143. const char *spaces,
  144. uint64_t lrange,
  145. uint64_t rrange,
  146. fpp fp,
  147. int esize,
  148. bool print_values
  149. )
  150. {
  151. OFFLOAD_TRACE(3,
  152. "%s generate_one_range(lrange=%p, rrange=%p, esize=%d)\n",
  153. spaces, (void*)lrange, (void*)rrange, esize);
  154. if (last_left == -1) {
  155. // First range
  156. last_left = lrange;
  157. }
  158. else {
  159. if (lrange == last_right+1) {
  160. // Extend previous range, don't print
  161. }
  162. else {
  163. (*fp)(spaces, last_left, last_right, esize, print_values);
  164. last_left = lrange;
  165. }
  166. }
  167. last_right = rrange;
  168. }
  169. static bool element_is_contiguous(
  170. uint64_t rank,
  171. const struct Dim_Desc *ddp
  172. )
  173. {
  174. if (rank == 1) {
  175. return (ddp[0].lower == ddp[0].upper || ddp[0].stride == 1);
  176. }
  177. else {
  178. return ((ddp[0].size == (ddp[1].upper-ddp[1].lower+1)*ddp[1].size) &&
  179. element_is_contiguous(rank-1, ddp++));
  180. }
  181. }
  182. static void generate_mem_ranges_one_rank(
  183. const char *spaces,
  184. uint64_t base,
  185. uint64_t rank,
  186. const struct Dim_Desc *ddp,
  187. fpp fp,
  188. int esize,
  189. bool print_values
  190. )
  191. {
  192. uint64_t lindex = ddp->lindex;
  193. uint64_t lower = ddp->lower;
  194. uint64_t upper = ddp->upper;
  195. uint64_t stride = ddp->stride;
  196. uint64_t size = ddp->size;
  197. OFFLOAD_TRACE(3,
  198. "%s "
  199. "generate_mem_ranges_one_rank(base=%p, rank=%lld, lindex=%lld, "
  200. "lower=%lld, upper=%lld, stride=%lld, size=%lld, esize=%d)\n",
  201. spaces, (void*)base, rank, lindex, lower, upper, stride, size, esize);
  202. if (element_is_contiguous(rank, ddp)) {
  203. uint64_t lrange, rrange;
  204. lrange = base + (lower-lindex)*size;
  205. rrange = lrange + (upper-lower+1)*size - 1;
  206. generate_one_range(spaces, lrange, rrange, fp, esize, print_values);
  207. }
  208. else {
  209. if (rank == 1) {
  210. for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
  211. uint64_t lrange, rrange;
  212. lrange = base + i*size;
  213. rrange = lrange + size - 1;
  214. generate_one_range(spaces, lrange, rrange,
  215. fp, esize, print_values);
  216. }
  217. }
  218. else {
  219. for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
  220. generate_mem_ranges_one_rank(
  221. spaces, base+i*size, rank-1, ddp+1,
  222. fp, esize, print_values);
  223. }
  224. }
  225. }
  226. }
  227. static void generate_mem_ranges(
  228. const char *spaces,
  229. const Arr_Desc *adp,
  230. bool deref,
  231. fpp fp,
  232. bool print_values
  233. )
  234. {
  235. uint64_t esize;
  236. OFFLOAD_TRACE(3,
  237. "%s "
  238. "generate_mem_ranges(adp=%p, deref=%d, fp)\n",
  239. spaces, adp, deref);
  240. last_left = -1;
  241. last_right = -2;
  242. // Element size is derived from last dimension
  243. esize = adp->dim[adp->rank-1].size;
  244. generate_mem_ranges_one_rank(
  245. // For c_cean_var the base addr is the address of the data
  246. // For c_cean_var_ptr the base addr is dereferenced to get to the data
  247. spaces, deref ? *((uint64_t*)(adp->base)) : adp->base,
  248. adp->rank, &adp->dim[0], fp, esize, print_values);
  249. (*fp)(spaces, last_left, last_right, esize, print_values);
  250. }
  251. // returns offset and length of the data to be transferred
  252. void __arr_data_offset_and_length(
  253. const Arr_Desc *adp,
  254. int64_t &offset,
  255. int64_t &length
  256. )
  257. {
  258. int64_t rank = adp->rank - 1;
  259. int64_t size = adp->dim[rank].size;
  260. int64_t r_off = 0; // offset from right boundary
  261. // find the rightmost dimension which takes just part of its
  262. // range. We define it if the size of left rank is not equal
  263. // the range's length between upper and lower boungaries
  264. while (rank > 0) {
  265. size *= (adp->dim[rank].upper - adp->dim[rank].lower + 1);
  266. if (size != adp->dim[rank - 1].size) {
  267. break;
  268. }
  269. rank--;
  270. }
  271. offset = (adp->dim[rank].lower - adp->dim[rank].lindex) *
  272. adp->dim[rank].size;
  273. // find gaps both from the left - offset and from the right - r_off
  274. for (rank--; rank >= 0; rank--) {
  275. offset += (adp->dim[rank].lower - adp->dim[rank].lindex) *
  276. adp->dim[rank].size;
  277. r_off += adp->dim[rank].size -
  278. (adp->dim[rank + 1].upper - adp->dim[rank + 1].lindex + 1) *
  279. adp->dim[rank + 1].size;
  280. }
  281. length = (adp->dim[0].upper - adp->dim[0].lindex + 1) *
  282. adp->dim[0].size - offset - r_off;
  283. }
  284. #if OFFLOAD_DEBUG > 0
  285. static void print_range(
  286. const char *spaces,
  287. uint64_t low,
  288. uint64_t high,
  289. int esize,
  290. bool print_values
  291. )
  292. {
  293. char buffer[1024];
  294. char number[32];
  295. OFFLOAD_TRACE(3, "%s print_range(low=%p, high=%p, esize=%d)\n",
  296. spaces, (void*)low, (void*)high, esize);
  297. if (console_enabled < 4 || !print_values) {
  298. return;
  299. }
  300. OFFLOAD_TRACE(4, "%s values:\n", spaces);
  301. int count = 0;
  302. buffer[0] = '\0';
  303. while (low <= high)
  304. {
  305. switch (esize)
  306. {
  307. case 1:
  308. sprintf(number, "%d ", *((char *)low));
  309. low += 1;
  310. break;
  311. case 2:
  312. sprintf(number, "%d ", *((short *)low));
  313. low += 2;
  314. break;
  315. case 4:
  316. sprintf(number, "%d ", *((int *)low));
  317. low += 4;
  318. break;
  319. default:
  320. sprintf(number, "0x%016x ", *((uint64_t *)low));
  321. low += 8;
  322. break;
  323. }
  324. strcat(buffer, number);
  325. count++;
  326. if (count == 10) {
  327. OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
  328. count = 0;
  329. buffer[0] = '\0';
  330. }
  331. }
  332. if (count != 0) {
  333. OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
  334. }
  335. }
  336. void __arr_desc_dump(
  337. const char *spaces,
  338. const char *name,
  339. const Arr_Desc *adp,
  340. bool deref,
  341. bool print_values
  342. )
  343. {
  344. OFFLOAD_TRACE(2, "%s%s CEAN expression %p\n", spaces, name, adp);
  345. if (adp != 0) {
  346. OFFLOAD_TRACE(2, "%s base=%llx, rank=%lld\n",
  347. spaces, adp->base, adp->rank);
  348. for (int i = 0; i < adp->rank; i++) {
  349. OFFLOAD_TRACE(2,
  350. "%s dimension %d: size=%lld, lindex=%lld, "
  351. "lower=%lld, upper=%lld, stride=%lld\n",
  352. spaces, i, adp->dim[i].size, adp->dim[i].lindex,
  353. adp->dim[i].lower, adp->dim[i].upper,
  354. adp->dim[i].stride);
  355. }
  356. // For c_cean_var the base addr is the address of the data
  357. // For c_cean_var_ptr the base addr is dereferenced to get to the data
  358. generate_mem_ranges(spaces, adp, deref, &print_range, print_values);
  359. }
  360. }
  361. void noncont_struct_dump(
  362. const char *spaces,
  363. const char *name,
  364. struct NonContigDesc *desc_p)
  365. {
  366. OFFLOAD_TRACE(2, "%s%s NonCont Struct expression %p\n",
  367. spaces, name, desc_p->base);
  368. if (desc_p) {
  369. OFFLOAD_TRACE(2, "%s%s base=%p\n", spaces, name, desc_p->base);
  370. for (int i = 0; i < desc_p->interval_cnt; i++) {
  371. OFFLOAD_TRACE(2,"%s dimension %d: lower=%lld, size=%lld\n",
  372. spaces, i, desc_p->interval[i].lower, desc_p->interval[i].size);
  373. }
  374. }
  375. }
  376. int64_t get_noncont_struct_size(struct NonContigDesc *desc_p)
  377. {
  378. int index = desc_p->interval_cnt - 1;
  379. return(desc_p->interval[index].lower + desc_p->interval[index].size);
  380. }
  381. #endif // OFFLOAD_DEBUG