i915_syncmap.c (14600B)
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 25#include "../i915_selftest.h" 26#include "i915_random.h" 27 28static char * 29__sync_print(struct i915_syncmap *p, 30 char *buf, unsigned long *sz, 31 unsigned int depth, 32 unsigned int last, 33 unsigned int idx) 34{ 35 unsigned long len; 36 unsigned int i, X; 37 38 if (depth) { 39 unsigned int d; 40 41 for (d = 0; d < depth - 1; d++) { 42 if (last & BIT(depth - d - 1)) 43 len = scnprintf(buf, *sz, "| "); 44 else 45 len = scnprintf(buf, *sz, " "); 46 buf += len; 47 *sz -= len; 48 } 49 len = scnprintf(buf, *sz, "%x-> ", idx); 50 buf += len; 51 *sz -= len; 52 } 53 54 /* We mark bits after the prefix as "X" */ 55 len = scnprintf(buf, *sz, "0x%016llx", p->prefix << p->height << SHIFT); 56 buf += len; 57 *sz -= len; 58 X = (p->height + SHIFT) / 4; 59 scnprintf(buf - X, *sz + X, "%*s", X, "XXXXXXXXXXXXXXXXX"); 60 61 if (!p->height) { 62 for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) { 63 len = scnprintf(buf, *sz, " %x:%x,", 64 i, __sync_seqno(p)[i]); 65 buf += len; 66 *sz -= len; 67 } 68 buf -= 1; 69 *sz += 1; 70 } 71 72 len = scnprintf(buf, *sz, "\n"); 73 buf += len; 74 *sz -= len; 75 76 if (p->height) { 77 for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) { 78 buf = __sync_print(__sync_child(p)[i], buf, sz, 79 depth + 1, 80 last << 1 | !!(p->bitmap >> (i + 1)), 81 i); 82 } 83 } 84 85 return buf; 86} 87 88static bool 89i915_syncmap_print_to_buf(struct i915_syncmap *p, char *buf, unsigned long sz) 90{ 91 if (!p) 92 return false; 93 94 while (p->parent) 95 p = p->parent; 96 97 __sync_print(p, buf, &sz, 0, 1, 0); 98 return true; 99} 100 101static int check_syncmap_free(struct i915_syncmap **sync) 102{ 103 i915_syncmap_free(sync); 104 if (*sync) { 105 pr_err("sync not cleared after free\n"); 106 return -EINVAL; 107 } 108 109 return 0; 110} 111 112static int dump_syncmap(struct i915_syncmap *sync, int err) 113{ 114 char *buf; 115 116 if (!err) 117 return check_syncmap_free(&sync); 118 119 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 120 if (!buf) 121 goto skip; 122 123 if (i915_syncmap_print_to_buf(sync, buf, PAGE_SIZE)) 124 pr_err("%s", buf); 125 126 kfree(buf); 127 128skip: 129 i915_syncmap_free(&sync); 130 return err; 131} 132 133static int igt_syncmap_init(void *arg) 134{ 135 struct i915_syncmap *sync = (void *)~0ul; 136 137 /* 138 * Cursory check that we can initialise a random pointer and transform 139 * it into the root pointer of a syncmap. 140 */ 141 142 i915_syncmap_init(&sync); 143 return check_syncmap_free(&sync); 144} 145 146static int check_seqno(struct i915_syncmap *leaf, unsigned int idx, u32 seqno) 147{ 148 if (leaf->height) { 149 pr_err("%s: not a leaf, height is %d\n", 150 __func__, leaf->height); 151 return -EINVAL; 152 } 153 154 if (__sync_seqno(leaf)[idx] != seqno) { 155 pr_err("%s: seqno[%d], found %x, expected %x\n", 156 __func__, idx, __sync_seqno(leaf)[idx], seqno); 157 return -EINVAL; 158 } 159 160 return 0; 161} 162 163static int check_one(struct i915_syncmap **sync, u64 context, u32 seqno) 164{ 165 int err; 166 167 err = i915_syncmap_set(sync, context, seqno); 168 if (err) 169 return err; 170 171 if ((*sync)->height) { 172 pr_err("Inserting first context=%llx did not return leaf (height=%d, prefix=%llx\n", 173 context, (*sync)->height, (*sync)->prefix); 174 return -EINVAL; 175 } 176 177 if ((*sync)->parent) { 178 pr_err("Inserting first context=%llx created branches!\n", 179 context); 180 return -EINVAL; 181 } 182 183 if (hweight32((*sync)->bitmap) != 1) { 184 pr_err("First bitmap does not contain a single entry, found %x (count=%d)!\n", 185 (*sync)->bitmap, hweight32((*sync)->bitmap)); 186 return -EINVAL; 187 } 188 189 err = check_seqno((*sync), ilog2((*sync)->bitmap), seqno); 190 if (err) 191 return err; 192 193 if (!i915_syncmap_is_later(sync, context, seqno)) { 194 pr_err("Lookup of first context=%llx/seqno=%x failed!\n", 195 context, seqno); 196 return -EINVAL; 197 } 198 199 return 0; 200} 201 202static int igt_syncmap_one(void *arg) 203{ 204 I915_RND_STATE(prng); 205 IGT_TIMEOUT(end_time); 206 struct i915_syncmap *sync; 207 unsigned long max = 1; 208 int err; 209 210 /* 211 * Check that inserting a new id, creates a leaf and only that leaf. 212 */ 213 214 i915_syncmap_init(&sync); 215 216 do { 217 u64 context = i915_prandom_u64_state(&prng); 218 unsigned long loop; 219 220 err = check_syncmap_free(&sync); 221 if (err) 222 goto out; 223 224 for (loop = 0; loop <= max; loop++) { 225 err = check_one(&sync, context, 226 prandom_u32_state(&prng)); 227 if (err) 228 goto out; 229 } 230 max++; 231 } while (!__igt_timeout(end_time, NULL)); 232 pr_debug("%s: Completed %lu single insertions\n", 233 __func__, max * (max - 1) / 2); 234out: 235 return dump_syncmap(sync, err); 236} 237 238static int check_leaf(struct i915_syncmap **sync, u64 context, u32 seqno) 239{ 240 int err; 241 242 err = i915_syncmap_set(sync, context, seqno); 243 if (err) 244 return err; 245 246 if ((*sync)->height) { 247 pr_err("Inserting context=%llx did not return leaf (height=%d, prefix=%llx\n", 248 context, (*sync)->height, (*sync)->prefix); 249 return -EINVAL; 250 } 251 252 if (hweight32((*sync)->bitmap) != 1) { 253 pr_err("First entry into leaf (context=%llx) does not contain a single entry, found %x (count=%d)!\n", 254 context, (*sync)->bitmap, hweight32((*sync)->bitmap)); 255 return -EINVAL; 256 } 257 258 err = check_seqno((*sync), ilog2((*sync)->bitmap), seqno); 259 if (err) 260 return err; 261 262 if (!i915_syncmap_is_later(sync, context, seqno)) { 263 pr_err("Lookup of first entry context=%llx/seqno=%x failed!\n", 264 context, seqno); 265 return -EINVAL; 266 } 267 268 return 0; 269} 270 271static int igt_syncmap_join_above(void *arg) 272{ 273 struct i915_syncmap *sync; 274 unsigned int pass, order; 275 int err; 276 277 i915_syncmap_init(&sync); 278 279 /* 280 * When we have a new id that doesn't fit inside the existing tree, 281 * we need to add a new layer above. 282 * 283 * 1: 0x00000001 284 * 2: 0x00000010 285 * 3: 0x00000100 286 * 4: 0x00001000 287 * ... 288 * Each pass the common prefix shrinks and we have to insert a join. 289 * Each join will only contain two branches, the latest of which 290 * is always a leaf. 291 * 292 * If we then reuse the same set of contexts, we expect to build an 293 * identical tree. 294 */ 295 for (pass = 0; pass < 3; pass++) { 296 for (order = 0; order < 64; order += SHIFT) { 297 u64 context = BIT_ULL(order); 298 struct i915_syncmap *join; 299 300 err = check_leaf(&sync, context, 0); 301 if (err) 302 goto out; 303 304 join = sync->parent; 305 if (!join) /* very first insert will have no parents */ 306 continue; 307 308 if (!join->height) { 309 pr_err("Parent with no height!\n"); 310 err = -EINVAL; 311 goto out; 312 } 313 314 if (hweight32(join->bitmap) != 2) { 315 pr_err("Join does not have 2 children: %x (%d)\n", 316 join->bitmap, hweight32(join->bitmap)); 317 err = -EINVAL; 318 goto out; 319 } 320 321 if (__sync_child(join)[__sync_branch_idx(join, context)] != sync) { 322 pr_err("Leaf misplaced in parent!\n"); 323 err = -EINVAL; 324 goto out; 325 } 326 } 327 } 328out: 329 return dump_syncmap(sync, err); 330} 331 332static int igt_syncmap_join_below(void *arg) 333{ 334 struct i915_syncmap *sync; 335 unsigned int step, order, idx; 336 int err = -ENODEV; 337 338 i915_syncmap_init(&sync); 339 340 /* 341 * Check that we can split a compacted branch by replacing it with 342 * a join. 343 */ 344 for (step = 0; step < KSYNCMAP; step++) { 345 for (order = 64 - SHIFT; order > 0; order -= SHIFT) { 346 u64 context = step * BIT_ULL(order); 347 348 err = i915_syncmap_set(&sync, context, 0); 349 if (err) 350 goto out; 351 352 if (sync->height) { 353 pr_err("Inserting context=%llx (order=%d, step=%d) did not return leaf (height=%d, prefix=%llx\n", 354 context, order, step, sync->height, sync->prefix); 355 err = -EINVAL; 356 goto out; 357 } 358 } 359 } 360 361 for (step = 0; step < KSYNCMAP; step++) { 362 for (order = SHIFT; order < 64; order += SHIFT) { 363 u64 context = step * BIT_ULL(order); 364 365 if (!i915_syncmap_is_later(&sync, context, 0)) { 366 pr_err("1: context %llx (order=%d, step=%d) not found\n", 367 context, order, step); 368 err = -EINVAL; 369 goto out; 370 } 371 372 for (idx = 1; idx < KSYNCMAP; idx++) { 373 if (i915_syncmap_is_later(&sync, context + idx, 0)) { 374 pr_err("1: context %llx (order=%d, step=%d) should not exist\n", 375 context + idx, order, step); 376 err = -EINVAL; 377 goto out; 378 } 379 } 380 } 381 } 382 383 for (order = SHIFT; order < 64; order += SHIFT) { 384 for (step = 0; step < KSYNCMAP; step++) { 385 u64 context = step * BIT_ULL(order); 386 387 if (!i915_syncmap_is_later(&sync, context, 0)) { 388 pr_err("2: context %llx (order=%d, step=%d) not found\n", 389 context, order, step); 390 err = -EINVAL; 391 goto out; 392 } 393 } 394 } 395 396out: 397 return dump_syncmap(sync, err); 398} 399 400static int igt_syncmap_neighbours(void *arg) 401{ 402 I915_RND_STATE(prng); 403 IGT_TIMEOUT(end_time); 404 struct i915_syncmap *sync; 405 int err = -ENODEV; 406 407 /* 408 * Each leaf holds KSYNCMAP seqno. Check that when we create KSYNCMAP 409 * neighbouring ids, they all fit into the same leaf. 410 */ 411 412 i915_syncmap_init(&sync); 413 do { 414 u64 context = i915_prandom_u64_state(&prng) & ~MASK; 415 unsigned int idx; 416 417 if (i915_syncmap_is_later(&sync, context, 0)) /* Skip repeats */ 418 continue; 419 420 for (idx = 0; idx < KSYNCMAP; idx++) { 421 err = i915_syncmap_set(&sync, context + idx, 0); 422 if (err) 423 goto out; 424 425 if (sync->height) { 426 pr_err("Inserting context=%llx did not return leaf (height=%d, prefix=%llx\n", 427 context, sync->height, sync->prefix); 428 err = -EINVAL; 429 goto out; 430 } 431 432 if (sync->bitmap != BIT(idx + 1) - 1) { 433 pr_err("Inserting neighbouring context=0x%llx+%d, did not fit into the same leaf bitmap=%x (%d), expected %lx (%d)\n", 434 context, idx, 435 sync->bitmap, hweight32(sync->bitmap), 436 BIT(idx + 1) - 1, idx + 1); 437 err = -EINVAL; 438 goto out; 439 } 440 } 441 } while (!__igt_timeout(end_time, NULL)); 442out: 443 return dump_syncmap(sync, err); 444} 445 446static int igt_syncmap_compact(void *arg) 447{ 448 struct i915_syncmap *sync; 449 unsigned int idx, order; 450 int err = -ENODEV; 451 452 i915_syncmap_init(&sync); 453 454 /* 455 * The syncmap are "space efficient" compressed radix trees - any 456 * branch with only one child is skipped and replaced by the child. 457 * 458 * If we construct a tree with ids that are neighbouring at a non-zero 459 * height, we form a join but each child of that join is directly a 460 * leaf holding the single id. 461 */ 462 for (order = SHIFT; order < 64; order += SHIFT) { 463 err = check_syncmap_free(&sync); 464 if (err) 465 goto out; 466 467 /* Create neighbours in the parent */ 468 for (idx = 0; idx < KSYNCMAP; idx++) { 469 u64 context = idx * BIT_ULL(order) + idx; 470 471 err = i915_syncmap_set(&sync, context, 0); 472 if (err) 473 goto out; 474 475 if (sync->height) { 476 pr_err("Inserting context=%llx (order=%d, idx=%d) did not return leaf (height=%d, prefix=%llx\n", 477 context, order, idx, 478 sync->height, sync->prefix); 479 err = -EINVAL; 480 goto out; 481 } 482 } 483 484 sync = sync->parent; 485 if (sync->parent) { 486 pr_err("Parent (join) of last leaf was not the sync!\n"); 487 err = -EINVAL; 488 goto out; 489 } 490 491 if (sync->height != order) { 492 pr_err("Join does not have the expected height, found %d, expected %d\n", 493 sync->height, order); 494 err = -EINVAL; 495 goto out; 496 } 497 498 if (sync->bitmap != BIT(KSYNCMAP) - 1) { 499 pr_err("Join is not full!, found %x (%d) expected %lx (%d)\n", 500 sync->bitmap, hweight32(sync->bitmap), 501 BIT(KSYNCMAP) - 1, KSYNCMAP); 502 err = -EINVAL; 503 goto out; 504 } 505 506 /* Each of our children should be a leaf */ 507 for (idx = 0; idx < KSYNCMAP; idx++) { 508 struct i915_syncmap *leaf = __sync_child(sync)[idx]; 509 510 if (leaf->height) { 511 pr_err("Child %d is a not leaf!\n", idx); 512 err = -EINVAL; 513 goto out; 514 } 515 516 if (leaf->parent != sync) { 517 pr_err("Child %d is not attached to us!\n", 518 idx); 519 err = -EINVAL; 520 goto out; 521 } 522 523 if (!is_power_of_2(leaf->bitmap)) { 524 pr_err("Child %d holds more than one id, found %x (%d)\n", 525 idx, leaf->bitmap, hweight32(leaf->bitmap)); 526 err = -EINVAL; 527 goto out; 528 } 529 530 if (leaf->bitmap != BIT(idx)) { 531 pr_err("Child %d has wrong seqno idx, found %d, expected %d\n", 532 idx, ilog2(leaf->bitmap), idx); 533 err = -EINVAL; 534 goto out; 535 } 536 } 537 } 538out: 539 return dump_syncmap(sync, err); 540} 541 542static int igt_syncmap_random(void *arg) 543{ 544 I915_RND_STATE(prng); 545 IGT_TIMEOUT(end_time); 546 struct i915_syncmap *sync; 547 unsigned long count, phase, i; 548 u32 seqno; 549 int err; 550 551 i915_syncmap_init(&sync); 552 553 /* 554 * Having tried to test the individual operations within i915_syncmap, 555 * run a smoketest exploring the entire u64 space with random 556 * insertions. 557 */ 558 559 count = 0; 560 phase = jiffies + HZ/100 + 1; 561 do { 562 u64 context = i915_prandom_u64_state(&prng); 563 564 err = i915_syncmap_set(&sync, context, 0); 565 if (err) 566 goto out; 567 568 count++; 569 } while (!time_after(jiffies, phase)); 570 seqno = 0; 571 572 phase = 0; 573 do { 574 I915_RND_STATE(ctx); 575 u32 last_seqno = seqno; 576 bool expect; 577 578 seqno = prandom_u32_state(&prng); 579 expect = seqno_later(last_seqno, seqno); 580 581 for (i = 0; i < count; i++) { 582 u64 context = i915_prandom_u64_state(&ctx); 583 584 if (i915_syncmap_is_later(&sync, context, seqno) != expect) { 585 pr_err("context=%llu, last=%u this=%u did not match expectation (%d)\n", 586 context, last_seqno, seqno, expect); 587 err = -EINVAL; 588 goto out; 589 } 590 591 err = i915_syncmap_set(&sync, context, seqno); 592 if (err) 593 goto out; 594 } 595 596 phase++; 597 } while (!__igt_timeout(end_time, NULL)); 598 pr_debug("Completed %lu passes, each of %lu contexts\n", phase, count); 599out: 600 return dump_syncmap(sync, err); 601} 602 603int i915_syncmap_mock_selftests(void) 604{ 605 static const struct i915_subtest tests[] = { 606 SUBTEST(igt_syncmap_init), 607 SUBTEST(igt_syncmap_one), 608 SUBTEST(igt_syncmap_join_above), 609 SUBTEST(igt_syncmap_join_below), 610 SUBTEST(igt_syncmap_neighbours), 611 SUBTEST(igt_syncmap_compact), 612 SUBTEST(igt_syncmap_random), 613 }; 614 615 return i915_subtests(tests, NULL); 616}