将一个函数转移到Intel Xeon Phi需要多长时间?

3

是否有预定义的时间需要进行离载调用,将函数的数据(参数)从主机传输到Intel MIC(Xeon Phi协处理器3120系列)?

具体而言,我使用了离载调用("#pragma offload target(mic)")来执行我希望在MIC上执行的函数。该函数有15个参数(指针和变量),我已经确认了参数在MIC上正确传递。然而,我简化了代码,目的是检查传递参数的时间,因此它只包含一个简单的"printf()"函数。我使用"sys/time.h"头文件中的"gettimeofday()"来测量时间,如下面的代码所示:

主机的一些硬件信息: Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz / CentOS release 6.8 / PCI Express Revision 2.0

main.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>

__attribute__ (( target (mic))) unsigned long long ForSolution = 0;
__attribute__ (( target (mic))) unsigned long long sufficientSol = 1;
__attribute__ (( target (mic))) float timer = 0.0;

__attribute__ (( target (mic))) void function(float *grid, float *displ, unsigned long long *li, unsigned long long *repet, float *solution, unsigned long long dim, unsigned long long numOfa, unsigned long long numLoops, unsigned long long numBlock, unsigned long long thread, unsigned long long blockGrid, unsigned long long station, unsigned long long bytesSol, unsigned long long totalSol, volatile unsigned long long *prog);

   float    *grid, *displ, *solution;
   unsigned long long   *li,repet;
   volatile unsigned long long  *prog;
   unsigned long long dim = 10, grid_a = 3, numLoops = 2, numBlock = 0;
   unsigned long long thread = 220, blockGrid = 0, station = 12;
   unsigned long long station_at = 8, bytesSol, totalSol;

   bytesSol = dim*sizeof(float);
   totalSol = ((1024 * 1024 * 1024) / bytesSol) * bytesSol;



   /******** Some memcpy() functions here for the pointers*********/                   



gettimeofday(&start, NULL);

   #pragma offload target(mic) \
        in(grid:length(dim * grid_a * sizeof(float))) \
        in(displ:length(station * station_at * sizeof(float))) \
        in(li:length(dim * sizeof(unsigned long long))) \
        in(repet:length(dim * sizeof(unsigned long long))) \
        out(solution:length(totalSol/sizeof(float))) \
        in(dim,grid_a,numLoops,numBlock,thread,blockGrid,station,bytesSol,totalSol) \
        in(prog:length(sizeof(volatile unsigned long long))) \
        inout(ForSolution,sufficientSol,timer)
   {
        function(grid, displ, li, repet, solution, dim, grid_a, numLoops, numBlock, thread, blockGrid, station, bytesSol, totalSol, prog);
   }

    gettimeofday(&end, NULL);  

    printf("Time to tranfer data on Intel Xeon Phi: %f sec\n", (((end.tv_sec - start.tv_sec) * 1000000.0 + (end.tv_usec - start.tv_usec)) / 1000000.0) - timer);
    printf("Time for calculations: %f sec\n", timer);

function.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <omp.h>

void function(float *grid, float *displ, unsigned long long *li, unsigned long long *repet, float *solution, unsigned long long dim, unsigned long long numOfa, unsigned long long numLoops, unsigned long long numBlock, unsigned long long thread, unsigned long long blockGrid, unsigned long long station, unsigned long long bytesSol, unsigned long long totalSol, volatile unsigned long long *prog)
{
    struct timeval      timer_start, timer_end;

    gettimeofday(&timer_start, NULL);

printf("Hello World!!!\n");


    gettimeofday(&timer_end, NULL);

    timer = ((timer_end.tv_sec - timer_start.tv_sec) * 1000000.0 + (timer_end.tv_usec - timer_start.tv_usec)) / 1000000.0 ;  
}

终端的结果:

Time to tranfer data on Intel Xeon Phi: 3.512706 sec
Time for calculations: 0.000002 sec
Hello World!!!

这段代码需要3.5秒才能完成"卸载目标"。上述结果是否正常?有没有什么方法可以减少此次卸载调用的显著时间延迟?


一段字符串重3.5公斤是正常的吗? - Brendan
更具体地说,从未知的主机操作系统通过未知的PCI Express接口上传未知数量的数据到未知版本的Xeon Phi协处理器所需的时间是无法确定的。 - Brendan
@Brendan 我已经编辑了我的问题。 - wasilis
1个回答

4

接下来看一下步骤:

a) 对于第一个#pragma offload,MIC会被初始化;这可能包括重置它,引导一个精简的Linux(等待其启动所有CPU,初始化其内存管理,启动一个伪NIC驱动程序等),并将您的代码上传到设备上。这可能单独需要几秒钟。

b) 所有输入数据都会被上传到MIC。

c) 函数将被执行。

d) 所有输出数据都将从MIC下载。

对于PCI Express Revision 2.0(x16)上的原始数据传输,最大带宽为8 GB/s;但是您不会获得最大带宽。据我所记,与Phi的通信涉及使用共享环缓冲区,以及在两侧(在主机和协处理器的操作系统上)使用“伪NIC”驱动程序的“门铃”IRQ;由于所有握手和开销,如果您能获得最大带宽的一半,我会感到惊讶。

我认为上传的总代码量、上传的数据和下载的数据远远超过1 GiB (例如,out(solution:length(totalSol/sizeof(float))) 本身就有1 GiB)。如果我们假设“大约4 GiB/s”,那么这至少需要另外约250毫秒。

我的建议是把所有步骤都做两遍;并测量第一次(包括初始化所有内容)和第二次(当所有内容已经初始化时)之间的差异,以确定初始化协处理器需要多长时间。第二个测量(减去执行函数所需的时间)将告诉您数据传输需要多长时间。


我进行了两次卸载调用(以相同的方式),事实上第一次卸载调用似乎需要消耗大量时间来进行初始化和数据传输。具体而言:“第一次卸载调用:在Intel Xeon Phi上传输数据的时间为3.490060秒” “第二次卸载调用:在Intel Xeon Phi上传输数据的时间为0.246883秒” 因此,我们得出结论:初始化的第一次延迟无法减少或避免。 - wasilis
1
@wasilis:初始化的延迟无法减少;但如果英特尔没有提供一种方式来(部分或完全)避免它,我会感到惊讶。可以通过异步地开始初始化,然后执行其他工作(例如从磁盘加载数据),然后等待初始化完成,这样在您实际需要使用它时,它已经(部分或完全)初始化完成。 - Brendan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接