AscendCL快速入门——内存管理篇
主要介绍了关于AscendCL运行资源管理相关内容
本篇将介绍内存管理相关操作
一、概述
本文介绍了AscendCL内存管理的相关知识,帮助掌握AscendCL中“host”和”device”的概念与使用方法,能够在两侧分别申请和释放内存,并在两侧之间进行内存拷贝和数据传输。
我们用一般计算机进行举例,CPU+内存所在的一侧,或者说进程启动的一侧,收集数据的一侧,我们称之为”host”侧,GPU+显存所在的一侧,进行专用计算,使用数据,我们称之为”Decive“。
在华为设备中,将GPU换为NPU,将显存换为Device内存,CPU+内存是Host侧,NPU则是Device侧,数据在Host收集,并发送到Device侧供NPU进行推理,并将结果从Device侧发回Host侧进行后处理、使用等操作。但是,有些华为设备,进程就是在NPU上进行,数据也是在Device内存直接加载的,此时没有Host侧,也没有Host->Device的数据传输过程,这种情况下,内存管理简单,无需考虑Host侧的事情。
二、接口API与代码展示
- Host侧内存管理相关接口方式比较简单,其中aclrtMallocHost是内存申请接口,aclrtFreeHost是其对应的释放接口
aclError aclrtMallocHost(void **hostPtr, size_t size);
aclError aclrtFreeHost(void *hostPtr);
这里要注意:aclrtMallocHost申请出来的内存必须由aclrtFreeHost来释 放,而 aclrtFreeHost只能释放由aclrtMallocHost申请出来的内存。起来有点拗口,实际就是说aclrtMallocHost和aclrtFreeHost这两个接口是强对应的,不要用于别的内存。
阅读下段代码,理解内存管理接口的使用。
#pragma add_include_path("/usr/local/Ascend/ascend-toolkit/latest/
x86_64-linux/acllib/include/")
#pragma add_library_path("/usr/local/Ascend/ascend-toolkit/latest/
x86_64-linux/acllib/lib64/")
#pragma cling load("libascendcl.so")
#define INFO_LOG(fmt, args...) fprintf(stdout, "[INFO] " fmt "\n", ##args)
#define WARN_LOG(fmt, args...) fprintf(stdout, "[WARN] " fmt "\n", ##args)
#define ERROR_LOG(fmt, args...) fprintf(stdout, "[ERROR] " fmt "\n", ##args)
#include <iostream>>
#include "acl/acl.h"
#include <stdio.h>
INFO_LOG("AscendCL Hello World.");
// AscendCL init
const char *aclConfigPath = "";
aclError ret = aclInit(aclConfigPath);
if ((ret != ACL_ERROR_NONE) && (ret != ACL_ERROR_REPEAT_INITIALIZE)) {
ERROR_LOG("AscendCL init failed");
}
INFO_LOG("AscendCL init success.");
ret = aclrtSetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return 0;
}
void *hostInput = nullptr;
int64_t size_input = 256;
ret = aclrtMallocHost(&hostInput, size_input);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL HostMem Malloc failed %d .", ret);
}
else {
INFO_LOG("AscendCL HostMem Malloc success .");
}
if (hostInput != nullptr) {
ret = aclrtFreeHost(hostInput);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL HostMem Free failed %d .", ret);
}
else {
INFO_LOG("AscendCL HostMem Free success .");
}
}
ret = aclrtResetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return 0;
}
ret = aclFinalize();
if ((ret != ACL_ERROR_NONE)&& (ret != ACL_ERROR_REPEAT_FINALIZE)) {
ERROR_LOG("Finalize AscendCL failed.");
}
INFO_LOG("End to finalize AscendCL.");
return 0;
- Device侧内存管理
aclError aclrtMalloc(void **devPtr, size_t size, aclrtMemMallocPolicy policy);
aclError aclrtFree(void *devPtr);
申请内存接口又多个参数:policy,指明申请内存的策略,当前一共有三种策略可选ACL_MEM_MALLOC_HUGE_FIRST:当申请的内存小于等于1M时,即使使用该内存分配规则, 也是申请普通页的内存。当申请的内存大于1M时,优先申请大页内存,如果大页内存不够,则使用普通页的内存。
ACL_MEM_MALLOC_HUGE_ONLY:仅申请大页,如果大页内存 不够,则返回错误。
ACL_MEM_MALLOC_NORMAL_ONLY:仅申请普通页。
aclrtMalloc和aclrtFree要成对出现。用aclrtMalloc申请出来的内存也是对齐过的。
阅读如下代码,理解Device侧内存管理使用。
INFO_LOG("AscendCL Hello World.");
// AscendCL init
ret = aclInit(aclConfigPath);
if ((ret != ACL_ERROR_NONE) && (ret != ACL_ERROR_REPEAT_INITIALIZE)) {
ERROR_LOG("AscendCL init failed.");
}
else {
INFO_LOG("AscendCL init success.");
}
ret = aclrtSetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return 0;
}
INFO_LOG("Set device 0 success.");
void *devInput = nullptr;
size_input = 256;
ret = aclrtMalloc(&devInput, size_input, ACL_MEM_MALLOC_HUGE_FIRST);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL DeviceMem Malloc failed %d.", ret);
}
else{
INFO_LOG("AscendCL DeviceMem Malloc success.");
}
if (hostInput != nullptr) {
ret = aclrtFree(devInput);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL DeviceMem Free failed.");
}
else{
INFO_LOG("AscendCL DeviceMem Free success.");
}
}
ret = aclrtResetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return 0;
}
ret = aclFinalize();
if ((ret != ACL_ERROR_NONE)&& (ret != ACL_ERROR_REPEAT_FINALIZE)) {
ERROR_LOG("Finalize AscendCL failed.");
}
INFO_LOG("End to finalize AscendCL.");
return 0;
- 内存拷贝
两侧的内存都申请好了,下面该是对内存的初始化以及在Host与Device之 间拷贝 数据了。刚申请出来的内存,里边的数据是随机的,有时我们想要对其进行一波统一的 初始化,此时可以使用这个接口:
aclError aclrtMemset(void *devPtr, size_t maxCount, int32_t value, size_t count);
devPtr:内存的起始地址
maxCount:内存的最大长度,单位byte
value:设置的值需要设置为指定值的内存长度,单位Byte
接下来是内存拷贝,而拷贝这个动作又分“源地址”和“目的地址”,所以在 AscendCL的内存拷贝动作中,共有4种拷贝方向。内存拷贝的函数原型如下:
aclError aclrtMemcpy(void *dst, size_t destMax, const void *src, size_t count,aclrtMemcpyKind kind);
Dst:目的地址
destMax:目的内存地址的最大内存长度,单位Byte
src:源地址
count:内存复制的长度,单位Byte
kind:指向内存复制方向
阅读下面代码来理解本接口的使用
INFO_LOG("AscendCL Hello World.");
// AscendCL init
ret = aclInit(aclConfigPath);
if ((ret != ACL_ERROR_NONE) && (ret != ACL_ERROR_REPEAT_INITIALIZE)) {
ERROR_LOG("AscendCL init failed.");
}
INFO_LOG("AscendCL init success.");
ret = aclrtSetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return 0;
}
hostInput = nullptr;
devInput = nullptr;
size_input = 256;
ret = aclrtMallocHost(&hostInput, size_input);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL HostMem Malloc failed.");
}
else{
INFO_LOG("AscendCL HostMem Malloc success.");
}
ret = aclrtMalloc(&devInput, size_input, ACL_MEM_MALLOC_HUGE_FIRST);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL DeviceMem Malloc failed %d.",ret );
}
else{
INFO_LOG("AscendCL DeviceMem Malloc success .");
}
ret = aclrtMemset(hostInput, size_input, 1, size_input);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL HostMem Memset failed %d.",ret );
}
else{
INFO_LOG("AscendCL HostMem Memset success.");
}
ret = aclrtMemset(devInput, size_input, 0, size_input);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL DeviceMem Memset failed %d.",ret );
}
else{
INFO_LOG("AscendCL DeviceMem Memset success.");
}
aclrtMemcpy(devInput, size_input, hostInput, size_input, ACL_MEMCPY_HOST_TO_DEVICE);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL Memcopy Host to Device failed %d.",ret );
}
else{
INFO_LOG("AscendCL Memcopy Host to Device success.");
}
if (hostInput != nullptr) {
ret = aclrtFreeHost(hostInput);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL HostMem Free failed %d.",ret );
}
else{
INFO_LOG("AscendCL HostMem Free success.");
}
}
if (devInput != nullptr) {
ret = aclrtFree(devInput);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL DeviceMem Free failed %d.",ret );
}
else{
INFO_LOG("AscendCL DeviceMem Free success.");
}
}
ret = aclrtResetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return 0;
}
ret = aclFinalize();
if ((ret != ACL_ERROR_NONE)&& (ret != ACL_ERROR_REPEAT_FINALIZE)) {
ERROR_LOG("Finalize AscendCL failed.");
}
INFO_LOG("End to finalize AscendCL.");
return 0;
- 如果要获取当前设备有多少内存,以及多少可用内存,可以选用这个接口:
aclError aclrtGetMemInfo(aclrtMemAttr attr, size_t *free, size_t *total)
其中的attr参数指的是内存的类型,主要有以下几种:
ACL_DDR_MEM, //DDR内存,DDR上所有大页内存+普通内存
ACL_DDR_MEM_HUGE, //DDR大页内存
ACL_DDR_MEM_NORMAL, //DDR普通内存
选择内存类型的时候要根据当前使用的设备形态来选择,阅读以下代码
INFO_LOG("AscendCL Hello World.");
// AscendCL init
ret = aclInit(aclConfigPath);
if ((ret != ACL_ERROR_NONE) && (ret != ACL_ERROR_REPEAT_INITIALIZE)) {
ERROR_LOG("AscendCL init failed.");
return ret;
}
INFO_LOG("AscendCL init success.");
ret = aclrtSetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return ret;
}
size_t free_mem = 0;
size_t total_mem = 0;
ret = aclrtGetMemInfo(ACL_DDR_MEM, &free_mem, &total_mem);
if (ret != ACL_SUCCESS) {
ERROR_LOG("AscendCL GetMemInfo failed %d.",ret);
return ret;
}
INFO_LOG("available memory: %zu", free_mem);
INFO_LOG("total memory: %zu", total_mem);
ret = aclrtResetDevice(0);
if (ret != ACL_ERROR_NONE) {
ERROR_LOG("AclrtSetDevice failed %d.",ret);
return ret;
}
ret = aclFinalize();
if ((ret != ACL_ERROR_NONE)&& (ret != ACL_ERROR_REPEAT_FINALIZE)) {
ERROR_LOG("Finalize AscendCL failed.");
return ret;
}
INFO_LOG("End to finalize AscendCL.");
return 0;
- 运行模式判断,部署环境下,为了明确在哪种模式下运行,提供了以下接口
aclError aclrtGetRunMode(aclrtRunMode *runMode);
runMode参数是接口调用后输出的一个枚举值,有两种可能:
ACL_DEVICE, //昇腾AI软件栈运行在Device的Control CPU或板端环境上
ACL_HOST, //昇腾AI软件栈运行在Host CPU上。
下篇将介绍 AscendCL入门 —— 模型推理篇
- 分享
- 举报
-
浏览量:1909次2023-04-12 18:08:59
-
浏览量:1232次2023-04-12 18:41:04
-
浏览量:1676次2023-04-12 19:12:22
-
浏览量:1400次2023-04-12 18:59:36
-
浏览量:1941次2020-08-18 19:54:52
-
浏览量:1021次2023-07-27 10:28:36
-
浏览量:1286次2023-12-13 17:20:20
-
浏览量:733次2024-01-25 15:08:45
-
浏览量:682次2023-09-18 16:40:57
-
浏览量:10129次2022-11-10 18:07:40
-
浏览量:3736次2020-08-18 19:54:58
-
浏览量:3366次2023-04-16 20:29:23
-
浏览量:3554次2020-07-27 15:12:15
-
浏览量:732次2023-12-06 09:40:25
-
浏览量:192次2024-09-29 16:03:37
-
浏览量:3195次2020-07-28 10:38:42
-
浏览量:2640次2020-10-15 15:06:44
-
2023-03-14 17:30:00
-
浏览量:1816次2021-01-27 16:48:37
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
四叶草~
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明