230 lines
6.1 KiB
Python
230 lines
6.1 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
# ruff: noqa: F401
|
|
|
|
import ctypes
|
|
|
|
import numpy as np
|
|
import pytest
|
|
import tvm_ffi
|
|
|
|
import tvm.testing
|
|
from tvm import relax
|
|
from tvm.ir import Op
|
|
from tvm.script import ir as I
|
|
from tvm.script import relax as R
|
|
|
|
# Parameterization for reading dtype of DLTensor. Chosen to have
|
|
# multiple distinct type codes, number of lanes, and widths.
|
|
dtype = tvm.testing.parameter(
|
|
"int32",
|
|
"int64",
|
|
"float32",
|
|
"float32x4",
|
|
"bfloat",
|
|
"float8_e4m3fn",
|
|
)
|
|
shape = tvm.testing.parameter(
|
|
[],
|
|
[16],
|
|
[128, 256],
|
|
[1] * 64,
|
|
)
|
|
|
|
elem_offset = tvm.testing.parameter(0, 64, 128)
|
|
|
|
|
|
def inspect_tensor_field(op_name, *args):
|
|
return relax.Call(Op.get(f"relax.inspect.{op_name}"), args)
|
|
|
|
|
|
def test_tensor_dtype_code(dtype):
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor):
|
|
return inspect_tensor_field("tensor_dtype_code", A)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
arg = tvm.runtime.empty([16], dtype)
|
|
res = vm["main"](arg)
|
|
|
|
expected_type_code = tvm.runtime.DataType(dtype).type_code
|
|
assert res == expected_type_code
|
|
|
|
|
|
def test_tensor_dtype_bits(dtype):
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor):
|
|
return inspect_tensor_field("tensor_dtype_bits", A)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
arg = tvm.runtime.empty([16], dtype)
|
|
res = vm["main"](arg)
|
|
|
|
expected_type_bits = tvm.runtime.DataType(dtype).bits
|
|
assert res == expected_type_bits
|
|
|
|
|
|
def test_tensor_dtype_lanes(dtype):
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor):
|
|
return inspect_tensor_field("tensor_dtype_lanes", A)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
arg = tvm.runtime.empty([16], dtype)
|
|
res = vm["main"](arg)
|
|
|
|
expected_type_lanes = tvm.runtime.DataType(dtype).lanes
|
|
assert res == expected_type_lanes
|
|
|
|
|
|
def test_tensor_ndim(shape):
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor):
|
|
return inspect_tensor_field("tensor_ndim", A)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
arg = tvm.runtime.empty(shape, "int32")
|
|
res = vm["main"](arg)
|
|
|
|
assert res == len(shape)
|
|
|
|
|
|
def test_tensor_shape(shape):
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor, axis: R.Prim("int64")):
|
|
return inspect_tensor_field("tensor_shape_i", A, axis)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
arg = tvm.runtime.empty(shape, "int32")
|
|
|
|
res = [vm["main"](arg, i) for i, _ in enumerate(shape)]
|
|
|
|
tvm.ir.assert_structural_equal(res, shape)
|
|
|
|
|
|
def _get_compact_striding(shape):
|
|
strides = []
|
|
product = 1
|
|
for dim in reversed(shape):
|
|
strides.append(product)
|
|
product *= dim
|
|
return list(reversed(strides))
|
|
|
|
|
|
def test_strides_of_compact_tensor(shape):
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor, axis: R.Prim("int64")):
|
|
return inspect_tensor_field("tensor_stride_i", A, axis)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
arg = tvm.runtime.empty(shape, "int32")
|
|
|
|
res = [vm["main"](arg, i) for i, _ in enumerate(shape)]
|
|
expected = _get_compact_striding(shape)
|
|
|
|
tvm.ir.assert_structural_equal(res, expected)
|
|
|
|
|
|
def test_strides_of_non_compact_tensor():
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor, axis: R.Prim("int64")):
|
|
return inspect_tensor_field("tensor_stride_i", A, axis)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
view_shape = [4, 4]
|
|
expected_strides = [1, 4]
|
|
# use transpose to make strides non-compact
|
|
x = np.zeros([4, 4], "int32").T
|
|
y = tvm_ffi.from_dlpack(x, require_alignment=4, require_contiguous=False)
|
|
res = [vm["main"](y, i) for i, _ in enumerate(view_shape)]
|
|
tvm.ir.assert_structural_equal(res, expected_strides)
|
|
|
|
|
|
def test_byte_offset(elem_offset):
|
|
backing_shape = [64, 64]
|
|
view_shape = [16, 16]
|
|
byte_offset = elem_offset * 4
|
|
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor):
|
|
return inspect_tensor_field("tensor_byte_offset", A)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
dtype = "int32"
|
|
backing_tensor = tvm.runtime.empty(backing_shape, dtype)
|
|
view = backing_tensor._create_view(view_shape, dtype, relative_byte_offset=byte_offset)
|
|
res = vm["main"](view)
|
|
assert res == byte_offset
|
|
|
|
|
|
def test_elem_offset(elem_offset, dtype):
|
|
tvm_dtype = tvm.runtime.DataType(dtype)
|
|
|
|
backing_shape = [64, 64]
|
|
view_shape = [16, 16]
|
|
element_bytes = (tvm_dtype.bits * tvm_dtype.lanes) // 8
|
|
byte_offset = elem_offset * element_bytes
|
|
|
|
@I.ir_module
|
|
class mod:
|
|
@R.function
|
|
def main(A: R.Tensor):
|
|
return inspect_tensor_field("tensor_elem_offset", A)
|
|
|
|
built = tvm.compile(mod)
|
|
vm = relax.VirtualMachine(built, tvm.cpu())
|
|
|
|
backing_tensor = tvm.runtime.empty(backing_shape, dtype)
|
|
view = backing_tensor._create_view(view_shape, dtype, relative_byte_offset=byte_offset)
|
|
res = vm["main"](view)
|
|
|
|
assert res == elem_offset
|
|
|
|
|
|
if __name__ == "__main__":
|
|
tvm.testing.main()
|