i915_timeline.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * SPDX-License-Identifier: MIT
  3. *
  4. * Copyright © 2017-2018 Intel Corporation
  5. */
  6. #include "../i915_selftest.h"
  7. #include "i915_random.h"
  8. #include "mock_gem_device.h"
  9. #include "mock_timeline.h"
  10. struct __igt_sync {
  11. const char *name;
  12. u32 seqno;
  13. bool expected;
  14. bool set;
  15. };
  16. static int __igt_sync(struct i915_timeline *tl,
  17. u64 ctx,
  18. const struct __igt_sync *p,
  19. const char *name)
  20. {
  21. int ret;
  22. if (__i915_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) {
  23. pr_err("%s: %s(ctx=%llu, seqno=%u) expected passed %s but failed\n",
  24. name, p->name, ctx, p->seqno, yesno(p->expected));
  25. return -EINVAL;
  26. }
  27. if (p->set) {
  28. ret = __i915_timeline_sync_set(tl, ctx, p->seqno);
  29. if (ret)
  30. return ret;
  31. }
  32. return 0;
  33. }
  34. static int igt_sync(void *arg)
  35. {
  36. const struct __igt_sync pass[] = {
  37. { "unset", 0, false, false },
  38. { "new", 0, false, true },
  39. { "0a", 0, true, true },
  40. { "1a", 1, false, true },
  41. { "1b", 1, true, true },
  42. { "0b", 0, true, false },
  43. { "2a", 2, false, true },
  44. { "4", 4, false, true },
  45. { "INT_MAX", INT_MAX, false, true },
  46. { "INT_MAX-1", INT_MAX-1, true, false },
  47. { "INT_MAX+1", (u32)INT_MAX+1, false, true },
  48. { "INT_MAX", INT_MAX, true, false },
  49. { "UINT_MAX", UINT_MAX, false, true },
  50. { "wrap", 0, false, true },
  51. { "unwrap", UINT_MAX, true, false },
  52. {},
  53. }, *p;
  54. struct i915_timeline tl;
  55. int order, offset;
  56. int ret = -ENODEV;
  57. mock_timeline_init(&tl, 0);
  58. for (p = pass; p->name; p++) {
  59. for (order = 1; order < 64; order++) {
  60. for (offset = -1; offset <= (order > 1); offset++) {
  61. u64 ctx = BIT_ULL(order) + offset;
  62. ret = __igt_sync(&tl, ctx, p, "1");
  63. if (ret)
  64. goto out;
  65. }
  66. }
  67. }
  68. mock_timeline_fini(&tl);
  69. mock_timeline_init(&tl, 0);
  70. for (order = 1; order < 64; order++) {
  71. for (offset = -1; offset <= (order > 1); offset++) {
  72. u64 ctx = BIT_ULL(order) + offset;
  73. for (p = pass; p->name; p++) {
  74. ret = __igt_sync(&tl, ctx, p, "2");
  75. if (ret)
  76. goto out;
  77. }
  78. }
  79. }
  80. out:
  81. mock_timeline_fini(&tl);
  82. return ret;
  83. }
  84. static unsigned int random_engine(struct rnd_state *rnd)
  85. {
  86. return i915_prandom_u32_max_state(I915_NUM_ENGINES, rnd);
  87. }
  88. static int bench_sync(void *arg)
  89. {
  90. struct rnd_state prng;
  91. struct i915_timeline tl;
  92. unsigned long end_time, count;
  93. u64 prng32_1M;
  94. ktime_t kt;
  95. int order, last_order;
  96. mock_timeline_init(&tl, 0);
  97. /* Lookups from cache are very fast and so the random number generation
  98. * and the loop itself becomes a significant factor in the per-iteration
  99. * timings. We try to compensate the results by measuring the overhead
  100. * of the prng and subtract it from the reported results.
  101. */
  102. prandom_seed_state(&prng, i915_selftest.random_seed);
  103. count = 0;
  104. kt = ktime_get();
  105. end_time = jiffies + HZ/10;
  106. do {
  107. u32 x;
  108. /* Make sure the compiler doesn't optimise away the prng call */
  109. WRITE_ONCE(x, prandom_u32_state(&prng));
  110. count++;
  111. } while (!time_after(jiffies, end_time));
  112. kt = ktime_sub(ktime_get(), kt);
  113. pr_debug("%s: %lu random evaluations, %lluns/prng\n",
  114. __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
  115. prng32_1M = div64_ul(ktime_to_ns(kt) << 20, count);
  116. /* Benchmark (only) setting random context ids */
  117. prandom_seed_state(&prng, i915_selftest.random_seed);
  118. count = 0;
  119. kt = ktime_get();
  120. end_time = jiffies + HZ/10;
  121. do {
  122. u64 id = i915_prandom_u64_state(&prng);
  123. __i915_timeline_sync_set(&tl, id, 0);
  124. count++;
  125. } while (!time_after(jiffies, end_time));
  126. kt = ktime_sub(ktime_get(), kt);
  127. kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
  128. pr_info("%s: %lu random insertions, %lluns/insert\n",
  129. __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
  130. /* Benchmark looking up the exact same context ids as we just set */
  131. prandom_seed_state(&prng, i915_selftest.random_seed);
  132. end_time = count;
  133. kt = ktime_get();
  134. while (end_time--) {
  135. u64 id = i915_prandom_u64_state(&prng);
  136. if (!__i915_timeline_sync_is_later(&tl, id, 0)) {
  137. mock_timeline_fini(&tl);
  138. pr_err("Lookup of %llu failed\n", id);
  139. return -EINVAL;
  140. }
  141. }
  142. kt = ktime_sub(ktime_get(), kt);
  143. kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
  144. pr_info("%s: %lu random lookups, %lluns/lookup\n",
  145. __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
  146. mock_timeline_fini(&tl);
  147. cond_resched();
  148. mock_timeline_init(&tl, 0);
  149. /* Benchmark setting the first N (in order) contexts */
  150. count = 0;
  151. kt = ktime_get();
  152. end_time = jiffies + HZ/10;
  153. do {
  154. __i915_timeline_sync_set(&tl, count++, 0);
  155. } while (!time_after(jiffies, end_time));
  156. kt = ktime_sub(ktime_get(), kt);
  157. pr_info("%s: %lu in-order insertions, %lluns/insert\n",
  158. __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
  159. /* Benchmark looking up the exact same context ids as we just set */
  160. end_time = count;
  161. kt = ktime_get();
  162. while (end_time--) {
  163. if (!__i915_timeline_sync_is_later(&tl, end_time, 0)) {
  164. pr_err("Lookup of %lu failed\n", end_time);
  165. mock_timeline_fini(&tl);
  166. return -EINVAL;
  167. }
  168. }
  169. kt = ktime_sub(ktime_get(), kt);
  170. pr_info("%s: %lu in-order lookups, %lluns/lookup\n",
  171. __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
  172. mock_timeline_fini(&tl);
  173. cond_resched();
  174. mock_timeline_init(&tl, 0);
  175. /* Benchmark searching for a random context id and maybe changing it */
  176. prandom_seed_state(&prng, i915_selftest.random_seed);
  177. count = 0;
  178. kt = ktime_get();
  179. end_time = jiffies + HZ/10;
  180. do {
  181. u32 id = random_engine(&prng);
  182. u32 seqno = prandom_u32_state(&prng);
  183. if (!__i915_timeline_sync_is_later(&tl, id, seqno))
  184. __i915_timeline_sync_set(&tl, id, seqno);
  185. count++;
  186. } while (!time_after(jiffies, end_time));
  187. kt = ktime_sub(ktime_get(), kt);
  188. kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
  189. pr_info("%s: %lu repeated insert/lookups, %lluns/op\n",
  190. __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
  191. mock_timeline_fini(&tl);
  192. cond_resched();
  193. /* Benchmark searching for a known context id and changing the seqno */
  194. for (last_order = 1, order = 1; order < 32;
  195. ({ int tmp = last_order; last_order = order; order += tmp; })) {
  196. unsigned int mask = BIT(order) - 1;
  197. mock_timeline_init(&tl, 0);
  198. count = 0;
  199. kt = ktime_get();
  200. end_time = jiffies + HZ/10;
  201. do {
  202. /* Without assuming too many details of the underlying
  203. * implementation, try to identify its phase-changes
  204. * (if any)!
  205. */
  206. u64 id = (u64)(count & mask) << order;
  207. __i915_timeline_sync_is_later(&tl, id, 0);
  208. __i915_timeline_sync_set(&tl, id, 0);
  209. count++;
  210. } while (!time_after(jiffies, end_time));
  211. kt = ktime_sub(ktime_get(), kt);
  212. pr_info("%s: %lu cyclic/%d insert/lookups, %lluns/op\n",
  213. __func__, count, order,
  214. (long long)div64_ul(ktime_to_ns(kt), count));
  215. mock_timeline_fini(&tl);
  216. cond_resched();
  217. }
  218. return 0;
  219. }
  220. int i915_gem_timeline_mock_selftests(void)
  221. {
  222. static const struct i915_subtest tests[] = {
  223. SUBTEST(igt_sync),
  224. SUBTEST(bench_sync),
  225. };
  226. return i915_subtests(tests, NULL);
  227. }