我在内核中运行排序算法,排序部分使用了大约 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 方法。
float tmp;
tmp = in_data [ j ].x;
in_data [ j ].x = in_data [ (j + 1) ].x;
in_data [ (j + 1) ].x = tmp ;
tmp = in_data [ j ].y;
in_data [ j ].y = in_data [ (j + 1) ].y;
in_data [ (j + 1) ].y = tmp ;
tmp = in_data [ j ].z;
in_data [ j ].z = in_data [ (j + 1) ].z;
in_data [ (j + 1) ].z = tmp ;
应该使用原始代码的 1/3 寄存器,因为它一次只需要 1/3 空间。
你也可以做一个全局--->本地------>全局
代替 global -----> private -----> global 来减少私有寄存器的使用。
现在我记得了,AMD 因在使用循环展开时使用大量寄存器而闻名。如果您的
num_record
是编译器已知的固定值,它可能会进行一些展开,并创建 tmp
的副本。
您可以尝试设置 pragma unroll 或在循环内声明
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 ;
}
}
根据你的描述,你的
node
结构看起来或多或少像这样(我假设dis
是一个int
,但无论是真的int
还是float
并不重要):
struct node
{
int dis;
float f1;
...
float f9;
};
如果简单的更改没有帮助...如何在
index
中再添加一个字段 node
,这样可以唯一地标识节点(除非可以使用现有字段之一来完成)并引入 node2
结构仅包含 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;
};
然后使用
node2
进行排序,然后在另一个内核或主机上使用已排序的 node
的 index
进行排序 node2
。
这应该会减少排序内核中的寄存器压力,但需要更多更改,例如已经说过的引入新的
node2
以及可能的内核分裂。