Skip to content

Commit 5c66fc8

Browse files
authored
[feat] Add support for Ascend device memory transfers (#382)
PR adds support for transferring data between device and host memory using Ascend native APIs. Currently, only Ascend-specific native APIs have been integrated, with core computing kernels to be added soon. - `ascend_stream.cc`: Provides wrappers for ACLRT copy operations, including synchronous, asynchronous, and batched operations. - `ascend_buffer.cc`: Offers wrappers for ACLRT memory management APIs, including device memory allocation/deallocation, host memory allocation/deallocation, and host memory mapping/unmapping.
1 parent 3127481 commit 5c66fc8

File tree

7 files changed

+441
-0
lines changed

7 files changed

+441
-0
lines changed

ucm/shared/test/case/trans/trans_test.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ TEST_F(UCTransUnitTest, CopyDataWithSM)
6868
ASSERT_EQ(device.Setup(deviceId), ok);
6969
auto buffer = device.MakeBuffer();
7070
auto stream = device.MakeSMStream();
71+
if (!stream) { return; }
7172
auto hPtr1 = buffer->MakeHostBuffer(size * number);
7273
ASSERT_NE(hPtr1, nullptr);
7374
ASSERT_EQ(buffer->MakeDeviceBuffers(size, number), ok);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
set(ASCEND_ROOT "/usr/local/Ascend/ascend-toolkit/latest" CACHE PATH "Path to Ascend root directory")
2+
add_library(Ascend::ascendcl UNKNOWN IMPORTED)
3+
set_target_properties(Ascend::ascendcl PROPERTIES
4+
INTERFACE_INCLUDE_DIRECTORIES "${ASCEND_ROOT}/include"
5+
IMPORTED_LOCATION "${ASCEND_ROOT}/lib64/libascendcl.so"
6+
)
7+
add_library(trans STATIC
8+
ascend_device.cc
9+
ascend_buffer.cc
10+
ascend_stream.cc
11+
)
12+
target_link_libraries(trans PUBLIC
13+
fmt
14+
Ascend::ascendcl
15+
)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
* */
24+
#include "ascend_buffer.h"
25+
#include <acl/acl.h>
26+
27+
namespace UC::Trans {
28+
29+
std::shared_ptr<void> Trans::AscendBuffer::MakeDeviceBuffer(size_t size)
30+
{
31+
void* device = nullptr;
32+
auto ret = aclrtMalloc(&device, size, ACL_MEM_TYPE_HIGH_BAND_WIDTH);
33+
if (ret == ACL_SUCCESS) { return std::shared_ptr<void>(device, aclrtFree); }
34+
return nullptr;
35+
}
36+
37+
std::shared_ptr<void> Trans::AscendBuffer::MakeHostBuffer(size_t size)
38+
{
39+
void* host = nullptr;
40+
auto ret = aclrtMallocHost(&host, size);
41+
if (ret == ACL_SUCCESS) { return std::shared_ptr<void>(host, aclrtFreeHost); }
42+
return nullptr;
43+
}
44+
45+
Status Trans::AscendBuffer::RegisterHostBuffer(void* ptr, size_t size)
46+
{
47+
if (registerOnHost_) {
48+
aclrtHostUnregister(registerOnHost_);
49+
registerOnHost_ = nullptr;
50+
registerOnDevice_ = nullptr;
51+
}
52+
auto ret = aclrtHostRegister(ptr, size, ACL_HOST_REGISTER_MAPPED, &registerOnDevice_);
53+
if (ret == ACL_SUCCESS) {
54+
registerOnHost_ = ptr;
55+
return Status::OK();
56+
}
57+
registerOnDevice_ = nullptr;
58+
return Status{ret, std::to_string(ret)};
59+
}
60+
61+
void Trans::AscendBuffer::UnregisterHostBuffer(void* ptr)
62+
{
63+
aclrtHostUnregister(ptr);
64+
if (registerOnHost_ == ptr) {
65+
registerOnHost_ = nullptr;
66+
registerOnDevice_ = nullptr;
67+
}
68+
}
69+
70+
void* Trans::AscendBuffer::GetHostPtrOnDevice(void* ptr)
71+
{
72+
if (registerOnHost_ == ptr) { return registerOnDevice_; }
73+
return nullptr;
74+
}
75+
76+
} // namespace UC::Trans
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
* */
24+
#ifndef UNIFIEDCACHE_TRANS_ASCEND_BUFFER_H
25+
#define UNIFIEDCACHE_TRANS_ASCEND_BUFFER_H
26+
27+
#include "trans/detail/reserved_buffer.h"
28+
29+
namespace UC::Trans {
30+
31+
class AscendBuffer : public ReservedBuffer {
32+
void* registerOnHost_{nullptr};
33+
void* registerOnDevice_{nullptr};
34+
35+
public:
36+
std::shared_ptr<void> MakeDeviceBuffer(size_t size) override;
37+
std::shared_ptr<void> MakeHostBuffer(size_t size) override;
38+
39+
Status RegisterHostBuffer(void* ptr, size_t size) override;
40+
void UnregisterHostBuffer(void* ptr) override;
41+
void* GetHostPtrOnDevice(void* ptr) override;
42+
};
43+
44+
} // namespace UC::Trans
45+
46+
#endif
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
* */
24+
#include <acl/acl.h>
25+
#include "ascend_buffer.h"
26+
#include "ascend_stream.h"
27+
#include "trans/device.h"
28+
29+
namespace UC::Trans {
30+
31+
Status Device::Setup(int32_t deviceId)
32+
{
33+
if (deviceId < 0) { return Status::Error(fmt::format("invalid device id({})", deviceId)); }
34+
auto ret = aclrtSetDevice(deviceId);
35+
if (ret == ACL_SUCCESS) { return Status::OK(); }
36+
return Status{ret, std::to_string(ret)};
37+
}
38+
39+
std::unique_ptr<Stream> Device::MakeStream()
40+
{
41+
std::unique_ptr<Stream> stream = nullptr;
42+
try {
43+
stream = std::make_unique<AscendStream>();
44+
} catch (...) {
45+
return nullptr;
46+
}
47+
if (stream->Setup().Success()) { return stream; }
48+
return nullptr;
49+
}
50+
51+
std::unique_ptr<Stream> Device::MakeSMStream() { return nullptr; }
52+
53+
std::unique_ptr<Buffer> Device::MakeBuffer()
54+
{
55+
try {
56+
return std::make_unique<AscendBuffer>();
57+
} catch (...) {
58+
return nullptr;
59+
}
60+
}
61+
62+
} // namespace UC::Trans
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/**
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
* */
24+
#include "ascend_stream.h"
25+
26+
namespace UC::Trans {
27+
28+
AscendStream::~AscendStream()
29+
{
30+
if (cbThread_.joinable()) {
31+
auto tid = cbThread_.native_handle();
32+
(void)aclrtUnSubscribeReport(tid, stream_);
33+
stop_ = true;
34+
cbThread_.join();
35+
}
36+
if (stream_) {
37+
(void)aclrtDestroyStream(stream_);
38+
stream_ = nullptr;
39+
}
40+
}
41+
42+
Status AscendStream::Setup()
43+
{
44+
auto ret = aclrtCreateStream(&stream_);
45+
if (ret != ACL_SUCCESS) [[unlikely]] { return Status{ret, std::to_string(ret)}; }
46+
cbThread_ = std::thread([this] {
47+
while (!this->stop_) { (void)aclrtProcessReport(10); }
48+
});
49+
auto tid = cbThread_.native_handle();
50+
ret = aclrtSubscribeReport(tid, stream_);
51+
if (ret != ACL_SUCCESS) [[unlikely]] { return Status{ret, std::to_string(ret)}; }
52+
return Status::OK();
53+
}
54+
55+
Status AscendStream::DeviceToHost(void* device, void* host, size_t size)
56+
{
57+
auto ret = aclrtMemcpy(host, size, device, size, ACL_MEMCPY_DEVICE_TO_HOST);
58+
if (ret == ACL_SUCCESS) { return Status::OK(); }
59+
return Status{ret, std::to_string(ret)};
60+
}
61+
62+
Status AscendStream::DeviceToHost(void* device[], void* host[], size_t size, size_t number)
63+
{
64+
auto s = DeviceToHostAsync(device, host, size, number);
65+
if (s.Failure()) [[unlikely]] { return s; }
66+
return Synchronized();
67+
}
68+
69+
Status AscendStream::DeviceToHost(void* device[], void* host, size_t size, size_t number)
70+
{
71+
auto s = DeviceToHostAsync(device, host, size, number);
72+
if (s.Failure()) [[unlikely]] { return s; }
73+
return Synchronized();
74+
}
75+
76+
Status AscendStream::DeviceToHostAsync(void* device, void* host, size_t size)
77+
{
78+
auto ret = aclrtMemcpyAsync(host, size, device, size, ACL_MEMCPY_DEVICE_TO_HOST, stream_);
79+
if (ret == ACL_SUCCESS) { return Status::OK(); }
80+
return Status{ret, std::to_string(ret)};
81+
}
82+
83+
Status AscendStream::DeviceToHostAsync(void* device[], void* host[], size_t size, size_t number)
84+
{
85+
for (size_t i = 0; i < number; i++) {
86+
auto s = DeviceToHostAsync(device[i], host[i], size);
87+
if (s.Failure()) [[unlikely]] { return s; }
88+
}
89+
return Status::OK();
90+
}
91+
92+
Status AscendStream::DeviceToHostAsync(void* device[], void* host, size_t size, size_t number)
93+
{
94+
for (size_t i = 0; i < number; i++) {
95+
auto pHost = (void*)(((int8_t*)host) + size * i);
96+
auto s = DeviceToHostAsync(device[i], pHost, size);
97+
if (s.Failure()) [[unlikely]] { return s; }
98+
}
99+
return Status::OK();
100+
}
101+
102+
Status AscendStream::HostToDevice(void* host, void* device, size_t size)
103+
{
104+
auto ret = aclrtMemcpy(device, size, host, size, ACL_MEMCPY_HOST_TO_DEVICE);
105+
if (ret == ACL_SUCCESS) { return Status::OK(); }
106+
return Status{ret, std::to_string(ret)};
107+
}
108+
109+
Status AscendStream::HostToDevice(void* host[], void* device[], size_t size, size_t number)
110+
{
111+
auto s = HostToDeviceAsync(host, device, size, number);
112+
if (s.Failure()) [[unlikely]] { return s; }
113+
return Synchronized();
114+
}
115+
116+
Status AscendStream::HostToDevice(void* host, void* device[], size_t size, size_t number)
117+
{
118+
auto s = HostToDeviceAsync(host, device, size, number);
119+
if (s.Failure()) [[unlikely]] { return s; }
120+
return Synchronized();
121+
}
122+
123+
Status AscendStream::HostToDeviceAsync(void* host, void* device, size_t size)
124+
{
125+
auto ret = aclrtMemcpyAsync(device, size, host, size, ACL_MEMCPY_HOST_TO_DEVICE, stream_);
126+
if (ret == ACL_SUCCESS) { return Status::OK(); }
127+
return Status{ret, std::to_string(ret)};
128+
}
129+
130+
Status AscendStream::HostToDeviceAsync(void* host[], void* device[], size_t size, size_t number)
131+
{
132+
for (size_t i = 0; i < number; i++) {
133+
auto s = HostToDeviceAsync(host[i], device[i], size);
134+
if (s.Failure()) [[unlikely]] { return s; }
135+
}
136+
return Status::OK();
137+
}
138+
139+
Status AscendStream::HostToDeviceAsync(void* host, void* device[], size_t size, size_t number)
140+
{
141+
for (size_t i = 0; i < number; i++) {
142+
auto pHost = (void*)(((int8_t*)host) + size * i);
143+
auto s = HostToDeviceAsync(pHost, device[i], size);
144+
if (s.Failure()) [[unlikely]] { return s; }
145+
}
146+
return Status::OK();
147+
}
148+
149+
using Closure = std::function<void(bool)>;
150+
151+
static void Trampoline(void* data)
152+
{
153+
auto c = static_cast<Closure*>(data);
154+
(*c)(true);
155+
delete c;
156+
}
157+
158+
Status Trans::AscendStream::AppendCallback(std::function<void(bool)> cb)
159+
{
160+
auto c = new (std::nothrow) Closure{std::move(cb)};
161+
if (!c) [[unlikely]] { return Status::Error("out of memory for appending callback"); }
162+
auto ret = aclrtLaunchCallback(Trampoline, (void*)c, ACL_CALLBACK_NO_BLOCK, stream_);
163+
if (ret != ACL_SUCCESS) [[unlikely]] {
164+
delete c;
165+
return Status{ret, std::to_string(ret)};
166+
}
167+
return Status::OK();
168+
}
169+
170+
Status AscendStream::Synchronized()
171+
{
172+
auto ret = aclrtSynchronizeStream(stream_);
173+
if (ret == ACL_SUCCESS) { return Status::OK(); }
174+
return Status{ret, std::to_string(ret)};
175+
}
176+
177+
} // namespace UC::Trans

0 commit comments

Comments
 (0)