i915_syncmap.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /*
  2. * Copyright © 2017 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. * IN THE SOFTWARE.
  22. *
  23. */
  24. #include "../i915_selftest.h"
  25. #include "i915_random.h"
  26. static char *
  27. __sync_print(struct i915_syncmap *p,
  28. char *buf, unsigned long *sz,
  29. unsigned int depth,
  30. unsigned int last,
  31. unsigned int idx)
  32. {
  33. unsigned long len;
  34. unsigned int i, X;
  35. if (depth) {
  36. unsigned int d;
  37. for (d = 0; d < depth - 1; d++) {
  38. if (last & BIT(depth - d - 1))
  39. len = scnprintf(buf, *sz, "| ");
  40. else
  41. len = scnprintf(buf, *sz, " ");
  42. buf += len;
  43. *sz -= len;
  44. }
  45. len = scnprintf(buf, *sz, "%x-> ", idx);
  46. buf += len;
  47. *sz -= len;
  48. }
  49. /* We mark bits after the prefix as "X" */
  50. len = scnprintf(buf, *sz, "0x%016llx", p->prefix << p->height << SHIFT);
  51. buf += len;
  52. *sz -= len;
  53. X = (p->height + SHIFT) / 4;
  54. scnprintf(buf - X, *sz + X, "%*s", X, "XXXXXXXXXXXXXXXXX");
  55. if (!p->height) {
  56. for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) {
  57. len = scnprintf(buf, *sz, " %x:%x,",
  58. i, __sync_seqno(p)[i]);
  59. buf += len;
  60. *sz -= len;
  61. }
  62. buf -= 1;
  63. *sz += 1;
  64. }
  65. len = scnprintf(buf, *sz, "\n");
  66. buf += len;
  67. *sz -= len;
  68. if (p->height) {
  69. for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) {
  70. buf = __sync_print(__sync_child(p)[i], buf, sz,
  71. depth + 1,
  72. last << 1 | !!(p->bitmap >> (i + 1)),
  73. i);
  74. }
  75. }
  76. return buf;
  77. }
  78. static bool
  79. i915_syncmap_print_to_buf(struct i915_syncmap *p, char *buf, unsigned long sz)
  80. {
  81. if (!p)
  82. return false;
  83. while (p->parent)
  84. p = p->parent;
  85. __sync_print(p, buf, &sz, 0, 1, 0);
  86. return true;
  87. }
  88. static int check_syncmap_free(struct i915_syncmap **sync)
  89. {
  90. i915_syncmap_free(sync);
  91. if (*sync) {
  92. pr_err("sync not cleared after free\n");
  93. return -EINVAL;
  94. }
  95. return 0;
  96. }
  97. static int dump_syncmap(struct i915_syncmap *sync, int err)
  98. {
  99. char *buf;
  100. if (!err)
  101. return check_syncmap_free(&sync);
  102. buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  103. if (!buf)
  104. goto skip;
  105. if (i915_syncmap_print_to_buf(sync, buf, PAGE_SIZE))
  106. pr_err("%s", buf);
  107. kfree(buf);
  108. skip:
  109. i915_syncmap_free(&sync);
  110. return err;
  111. }
  112. static int igt_syncmap_init(void *arg)
  113. {
  114. struct i915_syncmap *sync = (void *)~0ul;
  115. /*
  116. * Cursory check that we can initialise a random pointer and transform
  117. * it into the root pointer of a syncmap.
  118. */
  119. i915_syncmap_init(&sync);
  120. return check_syncmap_free(&sync);
  121. }
  122. static int check_seqno(struct i915_syncmap *leaf, unsigned int idx, u32 seqno)
  123. {
  124. if (leaf->height) {
  125. pr_err("%s: not a leaf, height is %d\n",
  126. __func__, leaf->height);
  127. return -EINVAL;
  128. }
  129. if (__sync_seqno(leaf)[idx] != seqno) {
  130. pr_err("%s: seqno[%d], found %x, expected %x\n",
  131. __func__, idx, __sync_seqno(leaf)[idx], seqno);
  132. return -EINVAL;
  133. }
  134. return 0;
  135. }
  136. static int check_one(struct i915_syncmap **sync, u64 context, u32 seqno)
  137. {
  138. int err;
  139. err = i915_syncmap_set(sync, context, seqno);
  140. if (err)
  141. return err;
  142. if ((*sync)->height) {
  143. pr_err("Inserting first context=%llx did not return leaf (height=%d, prefix=%llx\n",
  144. context, (*sync)->height, (*sync)->prefix);
  145. return -EINVAL;
  146. }
  147. if ((*sync)->parent) {
  148. pr_err("Inserting first context=%llx created branches!\n",
  149. context);
  150. return -EINVAL;
  151. }
  152. if (hweight32((*sync)->bitmap) != 1) {
  153. pr_err("First bitmap does not contain a single entry, found %x (count=%d)!\n",
  154. (*sync)->bitmap, hweight32((*sync)->bitmap));
  155. return -EINVAL;
  156. }
  157. err = check_seqno((*sync), ilog2((*sync)->bitmap), seqno);
  158. if (err)
  159. return err;
  160. if (!i915_syncmap_is_later(sync, context, seqno)) {
  161. pr_err("Lookup of first context=%llx/seqno=%x failed!\n",
  162. context, seqno);
  163. return -EINVAL;
  164. }
  165. return 0;
  166. }
  167. static int igt_syncmap_one(void *arg)
  168. {
  169. I915_RND_STATE(prng);
  170. IGT_TIMEOUT(end_time);
  171. struct i915_syncmap *sync;
  172. unsigned long max = 1;
  173. int err;
  174. /*
  175. * Check that inserting a new id, creates a leaf and only that leaf.
  176. */
  177. i915_syncmap_init(&sync);
  178. do {
  179. u64 context = i915_prandom_u64_state(&prng);
  180. unsigned long loop;
  181. err = check_syncmap_free(&sync);
  182. if (err)
  183. goto out;
  184. for (loop = 0; loop <= max; loop++) {
  185. err = check_one(&sync, context,
  186. prandom_u32_state(&prng));
  187. if (err)
  188. goto out;
  189. }
  190. max++;
  191. } while (!__igt_timeout(end_time, NULL));
  192. pr_debug("%s: Completed %lu single insertions\n",
  193. __func__, max * (max - 1) / 2);
  194. out:
  195. return dump_syncmap(sync, err);
  196. }
  197. static int check_leaf(struct i915_syncmap **sync, u64 context, u32 seqno)
  198. {
  199. int err;
  200. err = i915_syncmap_set(sync, context, seqno);
  201. if (err)
  202. return err;
  203. if ((*sync)->height) {
  204. pr_err("Inserting context=%llx did not return leaf (height=%d, prefix=%llx\n",
  205. context, (*sync)->height, (*sync)->prefix);
  206. return -EINVAL;
  207. }
  208. if (hweight32((*sync)->bitmap) != 1) {
  209. pr_err("First entry into leaf (context=%llx) does not contain a single entry, found %x (count=%d)!\n",
  210. context, (*sync)->bitmap, hweight32((*sync)->bitmap));
  211. return -EINVAL;
  212. }
  213. err = check_seqno((*sync), ilog2((*sync)->bitmap), seqno);
  214. if (err)
  215. return err;
  216. if (!i915_syncmap_is_later(sync, context, seqno)) {
  217. pr_err("Lookup of first entry context=%llx/seqno=%x failed!\n",
  218. context, seqno);
  219. return -EINVAL;
  220. }
  221. return 0;
  222. }
  223. static int igt_syncmap_join_above(void *arg)
  224. {
  225. struct i915_syncmap *sync;
  226. unsigned int pass, order;
  227. int err;
  228. i915_syncmap_init(&sync);
  229. /*
  230. * When we have a new id that doesn't fit inside the existing tree,
  231. * we need to add a new layer above.
  232. *
  233. * 1: 0x00000001
  234. * 2: 0x00000010
  235. * 3: 0x00000100
  236. * 4: 0x00001000
  237. * ...
  238. * Each pass the common prefix shrinks and we have to insert a join.
  239. * Each join will only contain two branches, the latest of which
  240. * is always a leaf.
  241. *
  242. * If we then reuse the same set of contexts, we expect to build an
  243. * identical tree.
  244. */
  245. for (pass = 0; pass < 3; pass++) {
  246. for (order = 0; order < 64; order += SHIFT) {
  247. u64 context = BIT_ULL(order);
  248. struct i915_syncmap *join;
  249. err = check_leaf(&sync, context, 0);
  250. if (err)
  251. goto out;
  252. join = sync->parent;
  253. if (!join) /* very first insert will have no parents */
  254. continue;
  255. if (!join->height) {
  256. pr_err("Parent with no height!\n");
  257. err = -EINVAL;
  258. goto out;
  259. }
  260. if (hweight32(join->bitmap) != 2) {
  261. pr_err("Join does not have 2 children: %x (%d)\n",
  262. join->bitmap, hweight32(join->bitmap));
  263. err = -EINVAL;
  264. goto out;
  265. }
  266. if (__sync_child(join)[__sync_branch_idx(join, context)] != sync) {
  267. pr_err("Leaf misplaced in parent!\n");
  268. err = -EINVAL;
  269. goto out;
  270. }
  271. }
  272. }
  273. out:
  274. return dump_syncmap(sync, err);
  275. }
  276. static int igt_syncmap_join_below(void *arg)
  277. {
  278. struct i915_syncmap *sync;
  279. unsigned int step, order, idx;
  280. int err = -ENODEV;
  281. i915_syncmap_init(&sync);
  282. /*
  283. * Check that we can split a compacted branch by replacing it with
  284. * a join.
  285. */
  286. for (step = 0; step < KSYNCMAP; step++) {
  287. for (order = 64 - SHIFT; order > 0; order -= SHIFT) {
  288. u64 context = step * BIT_ULL(order);
  289. err = i915_syncmap_set(&sync, context, 0);
  290. if (err)
  291. goto out;
  292. if (sync->height) {
  293. pr_err("Inserting context=%llx (order=%d, step=%d) did not return leaf (height=%d, prefix=%llx\n",
  294. context, order, step, sync->height, sync->prefix);
  295. err = -EINVAL;
  296. goto out;
  297. }
  298. }
  299. }
  300. for (step = 0; step < KSYNCMAP; step++) {
  301. for (order = SHIFT; order < 64; order += SHIFT) {
  302. u64 context = step * BIT_ULL(order);
  303. if (!i915_syncmap_is_later(&sync, context, 0)) {
  304. pr_err("1: context %llx (order=%d, step=%d) not found\n",
  305. context, order, step);
  306. err = -EINVAL;
  307. goto out;
  308. }
  309. for (idx = 1; idx < KSYNCMAP; idx++) {
  310. if (i915_syncmap_is_later(&sync, context + idx, 0)) {
  311. pr_err("1: context %llx (order=%d, step=%d) should not exist\n",
  312. context + idx, order, step);
  313. err = -EINVAL;
  314. goto out;
  315. }
  316. }
  317. }
  318. }
  319. for (order = SHIFT; order < 64; order += SHIFT) {
  320. for (step = 0; step < KSYNCMAP; step++) {
  321. u64 context = step * BIT_ULL(order);
  322. if (!i915_syncmap_is_later(&sync, context, 0)) {
  323. pr_err("2: context %llx (order=%d, step=%d) not found\n",
  324. context, order, step);
  325. err = -EINVAL;
  326. goto out;
  327. }
  328. }
  329. }
  330. out:
  331. return dump_syncmap(sync, err);
  332. }
  333. static int igt_syncmap_neighbours(void *arg)
  334. {
  335. I915_RND_STATE(prng);
  336. IGT_TIMEOUT(end_time);
  337. struct i915_syncmap *sync;
  338. int err = -ENODEV;
  339. /*
  340. * Each leaf holds KSYNCMAP seqno. Check that when we create KSYNCMAP
  341. * neighbouring ids, they all fit into the same leaf.
  342. */
  343. i915_syncmap_init(&sync);
  344. do {
  345. u64 context = i915_prandom_u64_state(&prng) & ~MASK;
  346. unsigned int idx;
  347. if (i915_syncmap_is_later(&sync, context, 0)) /* Skip repeats */
  348. continue;
  349. for (idx = 0; idx < KSYNCMAP; idx++) {
  350. err = i915_syncmap_set(&sync, context + idx, 0);
  351. if (err)
  352. goto out;
  353. if (sync->height) {
  354. pr_err("Inserting context=%llx did not return leaf (height=%d, prefix=%llx\n",
  355. context, sync->height, sync->prefix);
  356. err = -EINVAL;
  357. goto out;
  358. }
  359. if (sync->bitmap != BIT(idx + 1) - 1) {
  360. pr_err("Inserting neighbouring context=0x%llx+%d, did not fit into the same leaf bitmap=%x (%d), expected %lx (%d)\n",
  361. context, idx,
  362. sync->bitmap, hweight32(sync->bitmap),
  363. BIT(idx + 1) - 1, idx + 1);
  364. err = -EINVAL;
  365. goto out;
  366. }
  367. }
  368. } while (!__igt_timeout(end_time, NULL));
  369. out:
  370. return dump_syncmap(sync, err);
  371. }
  372. static int igt_syncmap_compact(void *arg)
  373. {
  374. struct i915_syncmap *sync;
  375. unsigned int idx, order;
  376. int err = -ENODEV;
  377. i915_syncmap_init(&sync);
  378. /*
  379. * The syncmap are "space efficient" compressed radix trees - any
  380. * branch with only one child is skipped and replaced by the child.
  381. *
  382. * If we construct a tree with ids that are neighbouring at a non-zero
  383. * height, we form a join but each child of that join is directly a
  384. * leaf holding the single id.
  385. */
  386. for (order = SHIFT; order < 64; order += SHIFT) {
  387. err = check_syncmap_free(&sync);
  388. if (err)
  389. goto out;
  390. /* Create neighbours in the parent */
  391. for (idx = 0; idx < KSYNCMAP; idx++) {
  392. u64 context = idx * BIT_ULL(order) + idx;
  393. err = i915_syncmap_set(&sync, context, 0);
  394. if (err)
  395. goto out;
  396. if (sync->height) {
  397. pr_err("Inserting context=%llx (order=%d, idx=%d) did not return leaf (height=%d, prefix=%llx\n",
  398. context, order, idx,
  399. sync->height, sync->prefix);
  400. err = -EINVAL;
  401. goto out;
  402. }
  403. }
  404. sync = sync->parent;
  405. if (sync->parent) {
  406. pr_err("Parent (join) of last leaf was not the sync!\n");
  407. err = -EINVAL;
  408. goto out;
  409. }
  410. if (sync->height != order) {
  411. pr_err("Join does not have the expected height, found %d, expected %d\n",
  412. sync->height, order);
  413. err = -EINVAL;
  414. goto out;
  415. }
  416. if (sync->bitmap != BIT(KSYNCMAP) - 1) {
  417. pr_err("Join is not full!, found %x (%d) expected %lx (%d)\n",
  418. sync->bitmap, hweight32(sync->bitmap),
  419. BIT(KSYNCMAP) - 1, KSYNCMAP);
  420. err = -EINVAL;
  421. goto out;
  422. }
  423. /* Each of our children should be a leaf */
  424. for (idx = 0; idx < KSYNCMAP; idx++) {
  425. struct i915_syncmap *leaf = __sync_child(sync)[idx];
  426. if (leaf->height) {
  427. pr_err("Child %d is a not leaf!\n", idx);
  428. err = -EINVAL;
  429. goto out;
  430. }
  431. if (leaf->parent != sync) {
  432. pr_err("Child %d is not attached to us!\n",
  433. idx);
  434. err = -EINVAL;
  435. goto out;
  436. }
  437. if (!is_power_of_2(leaf->bitmap)) {
  438. pr_err("Child %d holds more than one id, found %x (%d)\n",
  439. idx, leaf->bitmap, hweight32(leaf->bitmap));
  440. err = -EINVAL;
  441. goto out;
  442. }
  443. if (leaf->bitmap != BIT(idx)) {
  444. pr_err("Child %d has wrong seqno idx, found %d, expected %d\n",
  445. idx, ilog2(leaf->bitmap), idx);
  446. err = -EINVAL;
  447. goto out;
  448. }
  449. }
  450. }
  451. out:
  452. return dump_syncmap(sync, err);
  453. }
  454. static int igt_syncmap_random(void *arg)
  455. {
  456. I915_RND_STATE(prng);
  457. IGT_TIMEOUT(end_time);
  458. struct i915_syncmap *sync;
  459. unsigned long count, phase, i;
  460. u32 seqno;
  461. int err;
  462. i915_syncmap_init(&sync);
  463. /*
  464. * Having tried to test the individual operations within i915_syncmap,
  465. * run a smoketest exploring the entire u64 space with random
  466. * insertions.
  467. */
  468. count = 0;
  469. phase = jiffies + HZ/100 + 1;
  470. do {
  471. u64 context = i915_prandom_u64_state(&prng);
  472. err = i915_syncmap_set(&sync, context, 0);
  473. if (err)
  474. goto out;
  475. count++;
  476. } while (!time_after(jiffies, phase));
  477. seqno = 0;
  478. phase = 0;
  479. do {
  480. I915_RND_STATE(ctx);
  481. u32 last_seqno = seqno;
  482. bool expect;
  483. seqno = prandom_u32_state(&prng);
  484. expect = seqno_later(last_seqno, seqno);
  485. for (i = 0; i < count; i++) {
  486. u64 context = i915_prandom_u64_state(&ctx);
  487. if (i915_syncmap_is_later(&sync, context, seqno) != expect) {
  488. pr_err("context=%llu, last=%u this=%u did not match expectation (%d)\n",
  489. context, last_seqno, seqno, expect);
  490. err = -EINVAL;
  491. goto out;
  492. }
  493. err = i915_syncmap_set(&sync, context, seqno);
  494. if (err)
  495. goto out;
  496. }
  497. phase++;
  498. } while (!__igt_timeout(end_time, NULL));
  499. pr_debug("Completed %lu passes, each of %lu contexts\n", phase, count);
  500. out:
  501. return dump_syncmap(sync, err);
  502. }
  503. int i915_syncmap_mock_selftests(void)
  504. {
  505. static const struct i915_subtest tests[] = {
  506. SUBTEST(igt_syncmap_init),
  507. SUBTEST(igt_syncmap_one),
  508. SUBTEST(igt_syncmap_join_above),
  509. SUBTEST(igt_syncmap_join_below),
  510. SUBTEST(igt_syncmap_neighbours),
  511. SUBTEST(igt_syncmap_compact),
  512. SUBTEST(igt_syncmap_random),
  513. };
  514. return i915_subtests(tests, NULL);
  515. }