Page 80 - 《软件学报》2024年第6期
P. 80

2656                                                       软件学报  2024  年第  35  卷第  6  期


                    4) 连续访问数组的元素宽度定义: 优化维以下的所有更低维的数据总长量.
                    5) 局部离散访问数组的元素宽度定义: 优化维及以下的所有更低维的数据总长量.
                    6) 编译指示使用合法性定义: 编译指示所作用的循环中, 若存在指针, 被优化指示的数组与指针访问不存在读
                 写相关或者写写相关.

                                          表 3 多级存储层次访问融合优化编译指示说明

                       字句                                          含义
                       sbuf                                指示使用单缓冲区进行优化
                       dbuf                                指示使用双缓冲区进行优化
                     mem2ldm         指示变量列表中是循环中可以使用DMA缓冲优化的连续访问或局部离散访问的主存变量
                     sdm2ldm        指示变量列表中是循环中可以使用RMA缓冲优化的连续访问或局部离散访问的ldm共享变量
                     mem2sdm         指示变量列表中是循环中可以使用DMA缓冲优化的连续访问或局部离散访问的主存变量
                     ldm_addr                                  指示缓冲区地址
                     sdm_addr                              指示共享数据缓冲区地址
                     ldm_size                    指示用于访存优化的ldm缓冲空间的大小 (以字节为单位)
                                  #pragma ccc sbuf mem2ldm(source)
                     sdm_size                   指示用于访存优化的sdm缓冲空间的大小 (以字节为单位)

                    程序员在使用制导语句优化一个数组时, 该数组在循环中的所有访问必须是满足以上定义的局部离散访问数
                 组或者连续访问数组, 才允许被编译指示. 而且在编译器优化时, 如果新定义的数组元素宽度超过用户给出的缓冲
                 区容量, 直接放弃对该数组的优化. 其他代码变换合法性由编译系统保证.

                 3.3   编译指示使用示例
                    多级存储层次访存通信融合编译优化的编译指示的设计思路是在用户指导下, 编译器将多次对局部离散的主
                 存或  SDM  访问集中为一次或者几次高效的批量数据传输, 利用                DMA  和  RMA  机制的高带宽提升访存性能. 程序
                 设计人员只需要将可以优化的变量以及可用的缓冲区信息写入编译指示, 编译器自动完成                              DMA  和  RMA  操作的
                 生成和相应的程序变换. 图        9  展示了使用编译指示对第        3.1  节中的示例代码进行优化指示的编程示例. 编译器将
                 根据指示信息, 对相应循环中的数组访问             source、data 和  sdm_sum  进行缓冲优化.

                            #include <parallel.h>
                            #define N 1L<<30
                            #define M 1<<20                         //连续读访问主存数组data
                            //data和source为主存数组
                                                                       for(k=0;k<N;k++)
                            int data[N] [M];
                                                                       {
                            int source[N] [N];                      #pragma ccc sbuf mem2ldm (data)
                            __thread_sdm intsum[64];//sum为SDM数组
                                                                    ldm_addr(ldm_buf) ldm_size (4096)
                            __thread_ldm int ldm_buf[1024];
                                                                          for(l=0;l<M;l++)
                            __thread_sdm int sdm_buf[M];                  {
                            #pragma ccc th_func                             mysum=data[k][l]+...;
                            void kernel()
                                                                          }
                            {
                                                                       }
                                  …                                    sum[myid] = mysum;
                               //每个线程不同任务块                             m_sync(CCC_ARRAY);//核组同步
                               for(i=mybs;i<mybe;i++)
                                                                       if(myid==0)
                               {
                                                                       {
                                                                       // 连续读访问SDM数组sum
                            ldm_addr(ldm_buf) ldm_size(4096)
                                                                    #pragma ccc sbuf sdm2ldm(sum)
                                 #pragma ccc sbuf mem2sdm(data)
                                                                    ldm_addr(ldm_buf) ldm_size(256)
                            sdm_addr (sdm_buf) sdm_size (1<<24)
                                                                          for(n=1;n<64;n++)
                                  for(j=0;j<N;j++)
                                                                            sum[0]+=sum[n];
                                  {
                                                                        }
                                    pose = func(source[i][j]);            …
                                    data[i][pose] =  ...;           }
                                  }//循环j
                                  m_sync(CCC_ARRAY);//核组同步
                               }//循环i
                                                   图 9 编译指示优化示例
   75   76   77   78   79   80   81   82   83   84   85