模板参数作为函数说明符和编译器优化

Posted

技术标签:

【中文标题】模板参数作为函数说明符和编译器优化【英文标题】:Template parameter as function specifier and compiler optimization 【发布时间】:2013-02-28 14:54:53 【问题描述】:

我发现this 的帖子非常有用,我想澄清一下关于编译器优化的一些事情。假设我们有这个功能(和原来的帖子一样):

template<int action>
__global__ void kernel()

    switch(action) 
       case 1:
       // First code
       break;

       case 2:
       // Second code
       break;
    

即使我在编译时调用模板变量未知的函数,编译器是否会在消除无法访问的代码的意义上进行优化——比如创建两个单独的函数?例如:

kernel<argv[1][0]>();

【问题讨论】:

那是行不通的。根据定义,模板参数值必须在编译时知道。 【参考方案1】:

简短回答:不。

模板是在编译时实例化和生成的,因此您不能使用 argv 中的值,因为它们在编译时是未知的。

让我想知道为什么您不只是尝试一下并将该代码扔给编译器 - 它会告诉您模板参数必须是编译时常量。

更新: 由于您在 cmets 中告诉我们,这主要不是关于性能,而是关于可读性,我建议使用 switch/case:

template <char c> void kernel() 
  //...
  switch(c)  /* ... */ 


switch (argv[1][0]) 
  case 'a': 
    kernel<'a'>();
    break;
  case 'b': 
    kernel<'b'>();
    break;
  //...

由于您必须做出决定的值(即argv[1][0])仅在运行时才知道,因此您必须使用运行时决定机制。其中,switch/case 是最快的,特别是如果没有太多不同的情况(但超过两个),特别是如果情况之间没有间隙(即'a','b','c',而不是 1、55、2048)。然后编译器可以生成非常快的跳转表。

【讨论】:

我正在考虑重新组织我的代码,我想知道这种方式是否会导致性能下降。但感谢您对虚拟问题的回答。 在大多数情况下,只有一个能够可靠地告诉您代码更改对性能的实际影响:分析器。【参考方案2】:

作为模板的新手,我不得不研究一些基本问题。最后我想出了解决我的问题的方法。如果我想根据命令行参数调用带有模板参数的函数,我应该这样做:

if(argv[1][0] == '1')
    kernel<1><<< ... >>>();

if(argv[1][0] == '2')
    kernel<2><<< ... >>>();

我还检查了此类程序的 ptx 文件,发现编译器在这种情况下进行了优化,生成了两个不同的内核函数,而没有 switch 语句。

【讨论】:

为了避免重复的 if 语句,您可以将指向各种模板实例化的函数指针放入一个数组中,然后通过数组中相应的函数指针调用所需的内核,由适当的 argv[] 索引. @njuffa:是的,这看起来很聪明。这只是一个例子,switch 也是另一种方式,但我喜欢你的方式。 使用 switch/case 的可读性要高得多,将函数指针存储在数组中,afaik 不太可能产生更多开销 - 但同样,我将决定留给分析器,即实现两个版本和看看哪个更快。当然,前提是性能在程序的那个角落确实很重要。如果没有,请为您节省一些时间和精力,并以您认为最易读和可维护的方式实现它。 @ArneMertz 使我的代码更具可读性和可维护性正是我想做的事情,我很好奇这种改进是否会导致性能下降。 nvcc 的 PTX 输出告诉我“不”。 好的,从这个问题我认为性能是你最关心的问题 - 我更新了我的答案。

以上是关于模板参数作为函数说明符和编译器优化的主要内容,如果未能解决你的问题,请参考以下文章

C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?

MinGW(GCC)编译时的优化参数是啥?

未使用函数参数的编译器优化

《编译 - 编译杂记》GCC优化等级说明

[C++11]对模板右尖括号的优化

(Linux)gcc进行优化编译的参数是啥?