我在内核中运行排序算法,排序部分使用大约36个VGPR,从而导致12.5%的占用率和糟糕的性能。
代码段如下:
typedef struct {
float record[8];
float dis;
int t_class;
}node;
for ( int i = 0 ; i < num_record ; i ++ ){
in_data [ i]. dis = Dist ( in_data [i]. record , new_point , num_feature );
}
node tmp ;
int i;
int j;
#pragma unroll 1
for ( i = 0 ; i < num_record - 1 ; i ++ )
for ( j = 0 ; j < num_record - i - 1 ; j ++ )
{
if ( in_data [ j]. dis > in_data [ (j + 1) ]. dis )
{
tmp = in_data [ j ];
in_data [ j ] = in_data [ (j + 1) ];
in_data [ (j + 1) ] = tmp ;
}
}
有没有办法减少寄存器的使用而不对算法本身进行大的修改?我想最好将寄存器减少到16以下。
更新
基本上内核正试图实现详尽的knn方法。
答案 0 :(得分:0)
{{1}}
应该使用原始代码的1/3寄存器,因为它一次只需要1/3的空间。
您还可以进行全局---&gt;本地------&gt;全球
而不是全球-----&gt;私人-----&gt;全球减少私人登记使用。
答案 1 :(得分:0)
现在我记得,在使用循环展开时,AMD以使用大量寄存器而闻名。如果您的num_record
是编译器已知的固定值,它可以进行一些展开,并创建tmp
的副本。
您可以尝试设置pragma展开,或在循环中声明tmp
参数吗?
可能性1:
node tmp;
#pragma unroll
for ( int i = 0 ; i < num_record - 1 ; i ++ )
#pragma unroll
for ( int j = 0 ; j < num_record - i - 1 ; j ++ )
{
if ( in_data [ j]. dis > in_data [ (j + 1) ]. dis )
{
tmp = in_data [ j ];
in_data [ j ] = in_data [ (j + 1) ];
in_data [ (j + 1) ] = tmp ;
}
}
可能性2:
for ( int i = 0 ; i < num_record - 1 ; i ++ )
for ( int j = 0 ; j < num_record - i - 1 ; j ++ )
{
if ( in_data [ j]. dis > in_data [ (j + 1) ]. dis )
{
node tmp = in_data [ j ];
in_data [ j ] = in_data [ (j + 1) ];
in_data [ (j + 1) ] = tmp ;
}
}
答案 2 :(得分:0)
根据您的说明,您的node
结构或多或少看起来像这样(我假设dis
是int
,但是否真的{{1}无关紧要}或int
):
float
如果简单的更改无法帮助...如何添加一个字段struct node
{
int dis;
float f1;
...
float f9;
};
到index
,这样可以唯一地标识节点(除非可以使用其中一个现有字段)并引入仅包含node
和node2
的{{1}}结构?
像这样:
index
然后使用dis
进行排序,然后使用已排序struct node
{
int index; // add index for uniqueness unless one of f1 ... f1 could do
int dis;
float f1;
...
float f9;
};
struct node2
{
int index; // add index for uniqueness unless one of f1 ... f1 could do
int dis;
};
的{{1}}在另一个内核或主机排序node2
上进行排序。
这应该减少排序内核中的寄存器压力,但是需要更多的更改,比如已经说过引入新的node
和可能的内核分裂。