【ESWIN编程大赛】五、2020年11月12日陈工直播笔记

举报
ReCclay 发表于 2022/02/21 23:33:26 2022/02/21
【摘要】 文章目录 一、pint api功能说明1.1、背景1.2、需求1.3、功能模块以及说明1.3.1、组成模块层次1.3.2、Memory Management1.3.3、1D/2D/3D 内存分配与...

一、pint api功能说明

1.1、背景

  • 充分展示公司芯片的编程模式的灵活性和高效性。
  • 为用户开发人员提供简单高效的编程方式,降低用户编程的入门门槛,提高用户使用粘性。
  • 编程模型易维护、易扩展。

1.2、需求

  • 编程流程简单高效,API风格与CUDA保持一致,每个API都会返回运行状态值。其功能可以根据使用场景稍作修改。
  • 扩展性强,对CUDA的API有针对性的模拟,比如与GPU功能相似的API。
  • pint API包含通用的basic API(memory malloc、copy和memset,program launch, stream operation, event等)。
  • 提供支持C/C++、python 语言的api功能

1.3、功能模块以及说明

Module Name Description
Memory Management (Single device) Memory malloc, copy, memset in 1D,2D,3D
Memory Management (Multi devices) Memory copy peer (1 device to other device)
Execution Control Create and launch program with source type is code file, binary, code string.
Device Management Init device running mode, get device count and detail info, set and change computing device.
Stream Management A task queue to control device tasks and realize asynchronous operation
Error handling Show the error return as string type or string description.
Version management Show the pint api and other dependency libraries version.
other new function deep learnning etc…

1.3.1、组成模块层次

在这里插入图片描述
默认使用的是default stream

1.3.2、Memory Management

  • 1、支持1D,2D,3D的memory 分配,多维的memory malloc会产生pitch。
  • 2、pitch是设备cache line的整数倍,pitch的存在有利于memory的对齐操作,比如跨行访问、对齐拷贝,提高效率。
  • 3、pintMemcpy, pintMemcpy2D, pintMemcpy3D,pintMemset, pintMemsetPatern都是设备全局同步函数。
  • 4、Memory copy支持同步异步模式,共5种类型:
    • a、Host to Host (H2H, 多一种host端的异步的选择,如果不想用这个功能,可用系统函数memcpy替代)
    • b、Host to Device(H2D)
    • c、Device to Host (D2H)
    • d、Device to Device (D2D)
    • e、Default (通过判断输入参数的类型(Host ptr or Device ptr),自动去选择拷贝类型。

1.3.3、1D/2D/3D 内存分配与拷贝

内存分配

1D/2D内存分配

1D     pintMalloc(void **devPtr, size_t size)    
2D     pintMallocPitch(void **devPtr, size_t *pitch, size_width, size_t height)

  
 
  • 1
  • 2

在这里插入图片描述
3D内存分配

3D 	   pintMalloc3D(void **devPtr, struct pintPitch *pitch, const struct pintRegion region) 

  
 
  • 1

在这里插入图片描述

内存拷贝

1D内存拷贝

1D copy  pintMemcpy(void *dst, const size_t dstOffset, const void *src,
                               const size_t srcOffset, size_t count, 
                               enum pintMemcpyKind kind);                              


  
 
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

2D内存拷贝

在这里插入图片描述
在这里插入图片描述

3D内存拷贝

在这里插入图片描述

在这里插入图片描述

1.3.4、Pattern

在这里插入图片描述
支持 pattern_size 1,2,4,8,16,32,64,128.

在这里插入图片描述
按1Byte做memory set.

1.3.5、Execution Control

  • 编译源码、源码文件或者解析可执行文件,并生成一个携带可在设备上运行的信息的program结构体。
  • 由于设备代码中需要传参,参数是global变量,且编译后的参数在设备上的地址顺序不确定,所以传参的方式需要指定global变量,以与字符串映射的方式传入,比如 {“iA”, d_iA}。

1.3.6、Program

在这里插入图片描述

  • src: 源代码文件、源代码字符串、编译的可执行二进制.pin文件
  • options:额外的编译选项。
  • kind: 指定src的类型。

在这里插入图片描述

  • 该函数主要功能是更新参数并将该kernel的可执行信息提交给设备。该函数为异步函数如果想要获取准确的结果,需要加上同步函数
  • pint_args:类似于字典的结构体,存入kernel 代码中的global变量和host端初始化的指针,比如{“iA”, d_iA} 。如果不想传参或者更新参数,该参数可设置为NULL。
  • info:program 运行时候的一些信息,比如设备上的耗时 cycle数。该结构体也可以作为今后的一个扩展用。如果不想获取这些信息,该参数可设置为NULL。

1.3.7、Device Management

  • 初始化设备。如果没有显示初始化,pint api会在设备运行时初始化设备。
  • 获取设备的基本信息,包括数量、id等其它基本信息。
  • 切换设备。可以快速切换设备id的方式,让对应的设备能里面运行。
  • 设备id从0开始,止于设备数量 - 1。
  • 如果未指定设备,默认使用设备id 0。【现在比赛用的就是默认设备0】
pintError_t pintSetDevice(int device)

  
 
  • 1
  • 通过设置设备id来快速切换到对应的设备。
  • 如果不调用该函数,则使用default device 0.
Code example:
forint i = 0; i < device_count; ++i){
       pintSetDevice(i);
       pintMalloc();
       pintMemcpy();
       pintLaunch();
       pintDeviceSynchronize();
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • pintError_t pintDeviceSynchronize() 同步设备上的所有操作,直到当前时刻设备上所有的操作执行完。
  • pintError_t pintDeviceRest(void) 销毁当前进程的所有分配的资源并对其重置。

1.3.8、Stream Management

  • 一个host上运行的异步的任务队列,用于管理在设备上运行的任务集。
  • 一个设备上可拥有多个stream。
  • Streams之间的任务集相互独立。设备上支持多种类型的操作同时运行,通过多个stream协作,可以overlap掉部分操作,提高效率。
  • 如果没有创建stream,每个设备都会有一个对应的default stream,来管理任务集。
  • 所有支持stream的api尾部都带有Async(除了pintLaunchProgram),并在参数列表中需要指定stream。
  • 所有支持stream api都是异步函数,想要保证结果的正确性,最好加上同步函数。

在这里插入图片描述

常见的3种stream的写法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3.9、Error handling

返回错误码对应的字符串或者错误信息,方便调试。

  • const char* pintGetErrorName(pintError_t error)
  • const char* pintGetErrorString(pintError_t error)

二、pint kernel优化讲解

2.1、pintMemset 和pintMemsetPattern 用于初始化memory

int *d_buffer = pintMalloc((void**)&d_buffer, size_inbytes);
pintMemset(d_buffer, 0, 0, size_inbytes);
  d_buffer[i] = 0;  //on device

  
 
  • 1
  • 2
  • 3
int pattern = 1234;
pintMemsetpattern(d_buffer, &pattern, sizeof(int), 0, size_inbytes);
d_buffer[i] = 1234;  //on device

  
 
  • 1
  • 2
  • 3

2.2、pint kernel运行模式(支持串行并行)

在这里插入图片描述

2.3、read only + cache line

在这里插入图片描述

  • 1、without read only
    • 每次数据从Share Cache读取到D cache只有一个Word(4Bytes)。
  • 2、with read only
    • 每次数据从Share Cache读取到D cache有一个cache line(64Bytes)。

有效利用硬件的read only,可以大大提高UAP的带宽。

①、函数调用

/**
 * \brief set dcache read-only range
 *
 * \param begin - read-only start addr
 * \param end - read-only end addr
 *
 * \return
 * void
 *
 */
inline void pint_ro_seg_set(const void* begin, const void* end){
  uap_ro_seg_set(
    (addr_t)(begin) , 
    (addr_t)(end) );
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

②、结束

pint_dcache_discard();

  
 
  • 1

2.4、write only

  • 数据写入share cache并不会马上写入DDR,而是会保留在share cache上。等cache line被踢后,被踢的cache line会写到DDR上。减少数据与DDR的通信次数。
  • 目前write only功能支持的数据量较小,大约8MB左右。

①、设置只写区域函数:

/**
 * \brief initialize write only region with begin address and length
 *
 * \param begin_addr - write only region begin address
 * \param length - write only region length in byte
 *
 * \return
 * void
 */
inline void pint_mcore_wo_region_init(const void* begin_addr, uint32_t length)
{
  cache_line_t start_cache = (addr_t)begin_addr >> 6;
  cache_line_t end_cache = ((addr_t)begin_addr + length + 63) >> 6;
  uap_mcore_wo_enable(start_cache, end_cache);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

需要注意的是,length为只写区域的字节数!

②、只写区域结束调用:

pint_mcore_wo_region_release();

  
 
  • 1

2.5、ncore 同步sync功能(全局,部分同步)

  • 全局同步 sync (所有core)
  • 32 core同步 (0~31,32~63,..为一组)
  • 16 core同步 (0~15,16~31,..为一组)
  • 8 core同步 (0~7,8~15,..为一组)
  • sync.retire 不同步 (调用该函数的core都可以不强制被同步

这里以累加操作做说明。UAP目前由256个core,512个int数据:

在这里插入图片描述

第一次累加,将后半段的数据累加到前半段,同时增加一个全局同步。

在这里插入图片描述

第一次累加,将后半段的数据累加到前半段,考虑到后128个core不需要保存数据,不参与下一次累加计算,所以不用做同步,调用sync.retire后不会被强制同步。

在这里插入图片描述

在这里插入图片描述
①、汇编写法:

asm volatile("uap.sync");

  
 
  • 1

②、C语言写法:

pint_sync_all_cores();

  
 
  • 1

2.6、原子操作

①、 汇编写法:

asm volatile("uap.faa\t%1, %0":"+m" (x), "+r" (b));

  
 
  • 1

执行:

tmp = x;
x = x + b;
b = tmp;

  
 
  • 1
  • 2
  • 3

②、C语言写法

b = pint_atomic_add(&x, 1);

  
 
  • 1

执行:

b = x;
x = x + 1;

  
 
  • 1
  • 2

2.7、Dcache discard 和 Dcache flush

Dcache discard

/**
 * \brief discard data of dcache
 *
 * \return
 * void
 *
 */
inline void pint_dcache_discard(){
  uap_dcac_discard();
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Dcache flush

/**
 * \brief flush dcache dirty data to shared-cache excluding stack data.
 *  将dcache脏数据清除到shared-cache中,不清除栈数据。
 * \return
 *  void
 */
inline void pint_dcache_flush_excluding_stack(){
  uap_dcac_flush_excluding_stack();
}

/**
 * \brief flush all dcache dirty data to shared-cache.
 *  将所有dcache脏数据刷新到shared-cache中。
 * \return
 *  void
 */
inline void pint_dcache_flush(){
  uap_dcac_flush();
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.8、nonblocking

文章来源: recclay.blog.csdn.net,作者:ReCclay,版权归原作者所有,如需转载,请联系作者。

原文链接:recclay.blog.csdn.net/article/details/109692272

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。