Vector Addition

This tutorial demonstrates vector addition operator and its launch on Ascend simulator.

16 import asc2
17 import torch
18
19
20 # The functions which are executed on Ascend NPU must be marked with `@asc2.jit` decorator.
21 # Available parameters for @asc2.jit decorator can be seen in the documentation:
22 # https://compiler-team-ru.github.io/pyasc/python-api/rst/runtime/index.html
23 @asc2.jit
24 def vector_add(
25         # Pointers to input and output tensors should have `asc2.GlobalAddress` type.
26         x_ptr: asc2.GlobalAddress, y_ptr: asc2.GlobalAddress, out_ptr: asc2.GlobalAddress,
27         # Scalar parameters are passed as Python types (e.g. `int`, `float`).
28         # For optimization purposes it is recommended to pass scalar parameter as constants (e.g. `asc2.ConstExpr[int]`).
29         size: int,
30         # tile_size is used in asc2.copy_in must be asc2.ConstExpr
31         tile_size: asc2.ConstExpr):
32
33     # Tensor descriptor is created from `asc2.GlobalAddress` to represent entire tensor.
34     x_gm = asc2.global_tensor(x_ptr, [size])
35     y_gm = asc2.global_tensor(y_ptr, [size])
36     out_gm = asc2.global_tensor(out_ptr, [size])
37
38     # Python expressions are used to calculate offset and define the loop iterating over tiles:
39     # `asc2.block_num()` function provides number of AICOREs launched.
40     block_loop_num = asc2.ceildiv(asc2.ceildiv(size, asc2.block_num()), tile_size)
41     # `asc2.block_idx()` function is used to get current AICORE index.
42     block_offset = asc2.block_idx() * tile_size * block_loop_num
43
44     # `unroll_factor` parameter of `asc2.range` in `for` loop can be used to manage software pipelining. Set it to `2` to enable double buffering.
45     # `parallel` parameter of `asc2.range` in `for` loop enable overlapping of store operation of `i`-th iteration and load of `i+1`-th iteration.
46     # It is user responsibility to ensure that there are no data dependencies between overlapped iterations.
47     for i in asc2.range(block_loop_num, unroll_factor=2, parallel=True):
48         tile_offset = block_offset + i * tile_size
49         # `asc2.copy_in` is used to create a local tensor object which is used for further calculations. Data movement from GM to UB happens in this operation.
50         x = asc2.copy_in(x_gm, [tile_offset], [tile_size])
51         y = asc2.copy_in(y_gm, [tile_offset], [tile_size])
52         # One or more operations can be applied for tensors. It is compiler responsibility to allocate required number of memory blocks in UB.
53         out = x + y
54         # `asc2.copy_out` is used to move data from UB back to GM.
55         asc2.copy_out(out, out_gm, [tile_offset])
56
57
58 if __name__ == "__main__":
59     backend = asc2.Backend.Model  # can be "Model" for simulator or "NPU" for device
60     soc_version = asc2.Platform.Ascend950PR_9599  # Device version
61     device_id = 0  # might be necessary to provide if more than one NPU device is present in the system
62     asc2.set_platform(backend, soc_version, device_id)
63
64     size = 8192
65     block_num = 16
66     tile_size = 128
67     dtype = torch.float32
68     # Allocate tensors
69     x = torch.randn(size, dtype=dtype)
70     y = torch.randn(size, dtype=dtype)
71     out = torch.empty_like(x)
72
73     # For the kernel invocation, number of AICOREs should be provided in brackets:
74     vector_add[block_num](x, y, out, size, tile_size)
75     torch.testing.assert_close(out, x + y)

Gallery generated by Sphinx-Gallery