.. _data_transfer: 数据传输 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _data_transfer_principle_introduction: 原理介绍 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 数据传输是通过内存拷贝的方式实现的,LXHPL提供了同步拷贝和异步拷贝接口: - 同步拷贝:调用lynMemcpy接口,接口返回后代表数据已经完成了C2S、S2C或S2S传输。 - 异步拷贝:调用lynMemcpyAsync接口,在特定Stream中执行异步拷贝,确定拷贝完成需要调用lynSynchronizeStream接口同步等待,该接口返回后代表数据已经完成拷贝。 - 需要向Server端拷贝数据时,需要提前调用lynMalloc接口分配Server侧内存。 - Client端的内存分配,用户可自行调用标准库提供的new或malloc接口申请内存,并在内存生命周期结束后调用delete或free接口进行释放,LXHPL未提供额外接口。 - 当同一个应用的可执行文件既可以在Client上执行,也支持在Server上执行时,需要根据软件栈运行模式来判断后续的内存申请接口调用逻辑。 如果应用的可执行文件在Client侧执行,则可能涉及Client和Server的数据传输,需要调用lynMemcpy(同步接口)或lynMemcpyAsync接口(异步接口)通过内存拷贝的方式实现数据传输。 - S2S(ServerToServer)的拷贝分为两种情况,一种是在同一个Device上的两个内存地址之间的拷贝;另一种是一个Device拷贝到另一个Device上的拷贝;在SDK层会自动根据传进接口的src和dst两个地址参数来判断拷贝方式,当src和dst是在同一个Device上lynMalloc出来的,就会在同一个Device上拷贝,当src和dst是不同Device上lynMalloc出来的就会进行跨Device进行拷贝。跨Device的直接拷贝在很多场景可以提升很大的效率,相比于原来的Device1→Host,Host→Device2的这种跨设备拷贝,减少了Host侧临时内存开销,以及多一步拷贝的耗时。 .. attention:: 不能跨进程拷贝。 - MultiProcessP2P的拷贝,可以实现多进程之间的不同Device之间的P2P拷贝。 .. _c2s_data_transfer: C2S数据传输 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 用户可以从LynSDK提供的示例代码中查看完整样例,在示例代码中,调用各接口后都添加了异常判断和处理,以下是关键步骤代码示例,仅供参考,不可以直接拷贝编译。 .. code-block:: c //创建解码器发送Stream lynCreateStream(&vdec_send_stream); //分配Server侧内存 lynMalloc(&buf, 1024 * 1024); //执行异步内存拷贝 lynMemcpyAsync(stream, buf, packet->data, packet->size, ClientToServer); //同步等待拷贝完成并释放Server侧内存 lynSynchronizeStream(vdec_send_stream); lynFree(buf); //销毁Stream lynDestroyStream(vdec_send_stream); .. _s2c_data_transfer: S2C数据传输 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 用户可以从LynSDK提供的示例代码中查看完整样例,在示例代码中,调用各接口后都添加了异常判断和处理,以下是关键步骤代码示例,仅供参考,不可以直接拷贝编译。 .. code-block:: c //创建Stream lynStream_t stream; lynCreateStream(&stream); //初始化Server侧内存,同步接口 lynMemset(m_buffer1, 5, 1024*1024); //将数据拷贝回Client侧,检查Server内存是否初始化成功,同步接口 lynMemcpy(hostMem1, m_buffer1, 1024*1024, ServerToClient); //初始化Server侧内存,异步接口 lynMemsetAsync(m_buffer1, 6, 1024*1024, stream); //同步等待直至异步初始化完成 lynSynchronizeStream(stream); //将数据拷贝回Client侧,检查Server内存是否初始化成功,异步接口 lynMemcpyAsync(stream, hostMem1, m_buffer1, 1024*1024, ServerToClient); //同步等待直至异步拷贝完成 lynSynchronizeStream(stream); //销毁Stream lynDestroyStream(stream); .. _s2s_data_transfer: S2S数据传输 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 如下示例用于说明在不同Device上申请的地址,通过调用lynMemcpy接口进行跨Device的P2P拷贝。 .. code-block:: c lynContext_t ctx0; lynContext_t ctx1; void *devPtr0; void *devPtr1; lynCreateContext(&ctx0, 0); lynMalloc(&devPtr0, 1024); lynCreateContext(&ctx1, 1); lynMalloc(&devPtr1, 1024); lynMemcpy(devPtr0, devPtr1, 1024, ServerToServer); //两个地址分别在device0和device1上会进行跨设备P2P的拷贝 lynSetCurrentContext(ctx0); lynFree(devPtr0); lynDestroyContext(ctx0); lynSetCurrentContext(ctx1); lynFree(devPtr1); lynDestroyContext(ctx1); .. _multi_process_p2p_data_transfer: MultiProcessP2P数据传输 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MultiProcessP2P的拷贝,可以实现多进程之间的不同Device之间的P2P拷贝。 read.cpp示例: .. code-block:: c typedef struct{ uint64_t pid = 0; uint64_t devPtr = 0; }MEM_DATA; int fd = open("./sharemem", O_RDWR|O_CREAT,0666); ftruncate(fd, sizeof(MEM_DATA)); // 申请共享内存 MEM_DATA* mem = (MEM_DATA)mmap(NULL, sizeof(MEM_DATA), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); lynContext_t ctx; void *devPtr; lynCreateContext(&ctx, 0); lynMalloc(&devPtr, 1024); // 从共享内存中得到mem->devPtr,将write进程中的这个devPtr内存拷贝到该进程中的devPtr中 lynMemcpy(devPtr, reinterpret_cast(mem->devPtr), 1024, MultiProcessP2P); lynFree(devPtr); lynDestroyContext(ctx); write.cpp示例: .. code-block:: c typedef struct{ uint64_t pid = 0; uint64_t devPtr = 0; }MEM_DATA; int fd = open("./sharemem", O_RDWR|O_CREAT,0666); ftruncate(fd, sizeof(MEM_DATA)); // 申请共享内存 MEM_DATA* mem = (MEM_DATA)mmap(NULL, sizeof(MEM_DATA), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); lynContext_t ctx; void *devPtr; lynCreateContext(&ctx, 0); lynMalloc(&devPtr, 1024); lynMemSet(devPtr, 1, 1024); // 将该进程申请的devPtr放到共享内存 mem->devPtr = reinterpret_cast(devPtr); sleep(1); lynFree(devPtr); lynDestroyContext(ctx);