|
17 | 17 | import collections
|
18 | 18 | import ctypes
|
19 | 19 |
|
| 20 | +import numpy as np |
20 | 21 | import pytest
|
21 |
| -from helper import skip_if_dtype_not_supported |
| 22 | +from helper import get_queue_or_skip, skip_if_dtype_not_supported |
22 | 23 |
|
23 | 24 | import dpctl
|
24 | 25 | import dpctl.tensor as dpt
|
25 | 26 | import dpctl.tensor._dlpack as _dlp
|
26 | 27 | import dpctl.tensor._usmarray as dpt_arr
|
27 | 28 |
|
28 |
| -device_oneAPI = 14 # DLDeviceType.kDLOneAPI |
| 29 | +device_CPU = dpt_arr.DLDeviceType.kDLCPU |
| 30 | +device_oneAPI = dpt_arr.DLDeviceType.kDLOneAPI |
29 | 31 |
|
30 | 32 | _usm_types_list = ["shared", "device", "host"]
|
31 | 33 |
|
@@ -491,17 +493,206 @@ def test_dlpack_dl_device():
|
491 | 493 | cap2 = x.__dlpack__(dl_device=(1, 0), max_version=max_supported_ver)
|
492 | 494 | assert _is_capsule(cap2)
|
493 | 495 | cap3 = x.__dlpack__(
|
494 |
| - dl_device=(dpt_arr.DLDeviceType.kDLCPU, 0), |
| 496 | + dl_device=(device_CPU, 0), |
495 | 497 | max_version=max_supported_ver,
|
496 | 498 | )
|
497 | 499 | assert _is_capsule(cap3)
|
498 | 500 | cap4 = x.__dlpack__(dl_device=("kDLCPU", 0), max_version=max_supported_ver)
|
499 | 501 | assert _is_capsule(cap4)
|
500 |
| - with pytest.raises(NotImplementedError): |
| 502 | + with pytest.raises(TypeError): |
501 | 503 | # pass method instead of return of its __call__ invocation
|
502 | 504 | x.__dlpack__(
|
503 | 505 | dl_device=x.__dlpack_device__, max_version=max_supported_ver
|
504 | 506 | )
|
505 |
| - with pytest.raises(NotImplementedError): |
| 507 | + with pytest.raises(TypeError): |
506 | 508 | # exercise check for length
|
507 | 509 | x.__dlpack__(dl_device=(3,), max_version=max_supported_ver)
|
| 510 | + |
| 511 | + |
| 512 | +def test_from_dlpack_kdlcpu_interop_numpy(): |
| 513 | + """ |
| 514 | + Basic test that usm_ndarray can interoperate with NumPy ndarray |
| 515 | + `__dlpack_device__`. |
| 516 | + """ |
| 517 | + get_queue_or_skip() |
| 518 | + |
| 519 | + sh = 5 |
| 520 | + dt = dpt.int32 |
| 521 | + |
| 522 | + X = dpt.empty(sh, dtype=dt) |
| 523 | + dl_device_np = np.empty(()).__dlpack_device__() |
| 524 | + |
| 525 | + Y = dpt.from_dlpack(X, device=dl_device_np) |
| 526 | + assert isinstance(Y, np.ndarray) |
| 527 | + assert X.shape == Y.shape |
| 528 | + assert X.dtype == Y.dtype |
| 529 | + |
| 530 | + V = dpt.from_dlpack(Y) |
| 531 | + assert isinstance(V, np.ndarray) |
| 532 | + assert Y.shape == V.shape |
| 533 | + assert Y.dtype == V.dtype |
| 534 | + |
| 535 | + |
| 536 | +@pytest.mark.parametrize("shape", [tuple(), (2,), (3, 0, 1), (2, 2, 2)]) |
| 537 | +def test_from_dlpack_to_kdlcpu(shape, typestr): |
| 538 | + q = get_queue_or_skip() |
| 539 | + skip_if_dtype_not_supported(typestr, q.sycl_device) |
| 540 | + |
| 541 | + X = dpt.empty(shape, dtype=typestr, sycl_queue=q) |
| 542 | + Y = dpt.from_dlpack(X, device=(device_CPU, 0)) |
| 543 | + assert isinstance(Y, np.ndarray) |
| 544 | + assert X.shape == Y.shape |
| 545 | + assert X.dtype == Y.dtype |
| 546 | + # NumPy does not treat size 0 arrays consistently |
| 547 | + # w.r.t. strides, so skip these cases |
| 548 | + if X.ndim and X.size != 0: |
| 549 | + V = Y[::-1] |
| 550 | + W = dpt.from_dlpack(V) |
| 551 | + assert V.strides == W.strides |
| 552 | + |
| 553 | + |
| 554 | +@pytest.mark.parametrize("mod", [2, 5]) |
| 555 | +def test_from_dlpack_to_kdlcpu_strides(mod, typestr): |
| 556 | + q = get_queue_or_skip() |
| 557 | + skip_if_dtype_not_supported(typestr, q.sycl_device) |
| 558 | + |
| 559 | + X0 = dpt.empty(3 * mod, dtype=typestr, sycl_queue=q) |
| 560 | + for start in range(mod): |
| 561 | + X = X0[slice(-start - 1, None, -mod)] |
| 562 | + Y = dpt.from_dlpack(X, device=(device_CPU, 0)) |
| 563 | + assert X.shape == Y.shape |
| 564 | + assert X.dtype == Y.dtype |
| 565 | + if Y.ndim: |
| 566 | + V = Y[::-1] |
| 567 | + W = dpt.from_dlpack(V) |
| 568 | + assert V.strides == W.strides |
| 569 | + |
| 570 | + |
| 571 | +def test_dlpack_from_subdevice_to_kdlcpu(): |
| 572 | + """ |
| 573 | + Check that array allocated on a sub-device can be |
| 574 | + imported via DLPack to kDLCPU device (as a NumPy array). |
| 575 | + """ |
| 576 | + n = 64 |
| 577 | + try: |
| 578 | + dev = dpctl.SyclDevice() |
| 579 | + except dpctl.SyclDeviceCreationError: |
| 580 | + pytest.skip("No default device available") |
| 581 | + try: |
| 582 | + sdevs = dev.create_sub_devices(partition="next_partitionable") |
| 583 | + except dpctl.SyclSubDeviceCreationError: |
| 584 | + sdevs = None |
| 585 | + try: |
| 586 | + if sdevs is None: |
| 587 | + sdevs = dev.create_sub_devices(partition=[1, 1]) |
| 588 | + except dpctl.SyclSubDeviceCreationError: |
| 589 | + pytest.skip("Default device can not be partitioned") |
| 590 | + assert isinstance(sdevs, list) and len(sdevs) > 0 |
| 591 | + try: |
| 592 | + ctx = sdevs[0].sycl_platform.default_context |
| 593 | + except dpctl.SyclContextCreationError: |
| 594 | + pytest.skip("Platform's default_context is not available") |
| 595 | + try: |
| 596 | + q = dpctl.SyclQueue(ctx, sdevs[0]) |
| 597 | + except dpctl.SyclQueueCreationError: |
| 598 | + pytest.skip("Queue could not be created") |
| 599 | + |
| 600 | + ar = dpt.arange(n, dtype=dpt.int32, sycl_queue=q) |
| 601 | + ar2 = dpt.from_dlpack(ar, dl_device=(device_CPU, 0)) |
| 602 | + assert isinstance(ar2, np.ndarray) |
| 603 | + |
| 604 | + |
| 605 | +def test_legacy_dlpack_capsule_from_numpy(): |
| 606 | + """ |
| 607 | + Check that NumPy's exported legacy DLPack capsule |
| 608 | + will interoperate with from_dlpack_capsule, |
| 609 | + especially with zero-copy. |
| 610 | + """ |
| 611 | + x = np.arange(100, dtype="i4") |
| 612 | + cap = x.__dlpack__() |
| 613 | + y = _dlp.from_dlpack_capsule(cap) |
| 614 | + del cap |
| 615 | + assert x.ctypes.data == y.ctypes.data |
| 616 | + |
| 617 | + x = np.arange(100, dtype="u4").reshape((10, 10)).T |
| 618 | + cap = x.__dlpack__() |
| 619 | + y = _dlp.from_dlpack_capsule(cap) |
| 620 | + del cap |
| 621 | + assert x.ctypes.data == y.ctypes.data |
| 622 | + del x |
| 623 | + |
| 624 | + x = np.arange(100, dtype="f4").reshape((10, 10), order="F") |
| 625 | + cap = x.__dlpack__() |
| 626 | + y = _dlp.from_dlpack_capsule(cap) |
| 627 | + del cap |
| 628 | + assert x.ctypes.data == y.ctypes.data |
| 629 | + |
| 630 | + x = np.arange(100, dtype="c8") |
| 631 | + x1 = x[::-2] |
| 632 | + cap = x1.__dlpack__() |
| 633 | + y = _dlp.from_dlpack_capsule(cap) |
| 634 | + assert x1.ctypes.data == y.ctypes.data |
| 635 | + del x1, y, x |
| 636 | + del cap |
| 637 | + |
| 638 | + x = np.ones(100, dtype="?") |
| 639 | + x1 = x[::-2] |
| 640 | + cap = x1.__dlpack__() |
| 641 | + y = _dlp.from_dlpack_capsule(cap) |
| 642 | + assert x1.ctypes.data == y.ctypes.data |
| 643 | + del x1, y, x |
| 644 | + del cap |
| 645 | + |
| 646 | + |
| 647 | +def test_dlpack_capsule_readonly_array_to_kdlcpu(): |
| 648 | + try: |
| 649 | + x = dpt.arange(100, dtype="i4") |
| 650 | + except dpctl.SyclDeviceCreationError: |
| 651 | + pytest.skip("No default device available") |
| 652 | + |
| 653 | + max_supported_ver = _dlp.get_build_dlpack_version() |
| 654 | + # read-only array |
| 655 | + x.flags["W"] = False |
| 656 | + cap = x.__dlpack__(max_version=max_supported_ver, dl_device=(device_CPU, 0)) |
| 657 | + y = _dlp.from_dlpack_capsule(cap) |
| 658 | + assert dpt.all(x == dpt.asarray(y)) |
| 659 | + assert not y.flags["W"] |
| 660 | + |
| 661 | + cap1 = _dlp.numpy_to_dlpack_versioned_capsule(y, not y.flags["W"]) |
| 662 | + y1 = _dlp.from_dlpack_capsule(cap1) |
| 663 | + assert not y1.flags["W"] |
| 664 | + |
| 665 | + |
| 666 | +def test_used_dlpack_capsule_from_numpy(): |
| 667 | + get_queue_or_skip() |
| 668 | + |
| 669 | + x_np = np.arange(100, dtype="i4") |
| 670 | + |
| 671 | + cap = x_np.__dlpack__() |
| 672 | + _dlp.from_dlpack_capsule(cap) |
| 673 | + with pytest.raises( |
| 674 | + ValueError, |
| 675 | + match="A DLPack tensor object can not be consumed multiple times", |
| 676 | + ): |
| 677 | + _dlp.from_dlpack_capsule(cap) |
| 678 | + del cap |
| 679 | + |
| 680 | + x = dpt.asarray(x_np) |
| 681 | + max_supported_ver = _dlp.get_build_dlpack_version() |
| 682 | + cap = x.__dlpack__(max_version=max_supported_ver, dl_device=(device_CPU, 0)) |
| 683 | + _dlp.from_dlpack_capsule(cap) |
| 684 | + with pytest.raises( |
| 685 | + ValueError, |
| 686 | + match="A DLPack tensor object can not be consumed multiple times", |
| 687 | + ): |
| 688 | + _dlp.from_dlpack_capsule(cap) |
| 689 | + del cap |
| 690 | + |
| 691 | + |
| 692 | +def test_dlpack_size_0_on_kdlcpu(): |
| 693 | + get_queue_or_skip() |
| 694 | + x_np = np.ones(0, dtype="i4") |
| 695 | + |
| 696 | + cap = x_np.__dlpack__() |
| 697 | + y = _dlp.from_dlpack_capsule(cap) |
| 698 | + assert y.ctypes.data == x_np.ctypes.data |
0 commit comments