这是错过的优化机会吗 [英] Is this a missed optimization opportunity or not

查看:69
本文介绍了这是错过的优化机会吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发布了答案。代码:

#include <atomic>
#include <utility>
void printImpl(...);

std::atomic<bool> printLog = false;

class Log {
 public:
  template <typename T>
  const auto& operator<<(T&& t) {
    if (printLog) {
      ulog.active = true;
      return ulog << std::forward<T>(t);
    } else {
      ulog.active = false;
      return ulog;
    }
  }

 private:
  struct unchecked_log {
    template <typename T>
    const auto& operator<<(T&& t) const {
      if (active) {
        printImpl(std::forward<T>(t));
      }
      return *this;
    }
    bool active{false};
  };
  unchecked_log ulog{};
};

// Instead of the macro. Doesn't break backward compatibility
Log LOG;

void test(bool) { LOG << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10; }

本质上,代码将忽略或记录所有数据。想法是将 atomic< bool> 记录在常规的 bool 中,可以更轻松地对其进行优化。我认为大多数编译器都可以轻松地优化 if(处于活动状态)部分,因为无法在调用之间进行更改。尽管结果,但大多数编译器的确将函数调用内联到 unchecked_log :: operator< ;< ,但不优化分支。有什么阻碍这种优化的吗?这是非法的。

In essence, the code either ignores or logs all the data. The idea was to record the atomic<bool> in a regular bool which can be optimized out more easily. I thought most compilers could easily optimize out the if (active) part since there is no way it can change between calls. Turns out though, most compilers do inline the function call to unchecked_log::operator<< but do not optimize out the branching. Is there something preventing this optimization? Would it be illegal.

推荐答案

LOG 是具有外部链接的全局变量。因此,在另一个翻译单元中的 printImpl 的定义可以达到它,并且可以在两次调用之间修改 LOG.ulog.active

LOG is a global variable with external linkage. Therefore printImpl's definition in another translation unit can reach it and can potentially modify LOG.ulog.active between calls.

test 中使 LOG 为局部变量,然后重复的检查将在 test 的条目中合并为一个,或将 LOG 保留在原来的位置并将其设为静态,因此包含 printImpl 定义的其他编译单元无法到达此翻译单元的实例。

Make LOG a local variable in test and the repeated checks will be consolidated into one at the entry of test or leave LOG where it is and make it static, so a different compilation unit containing printImpl's definition cannot reach this translation unit's instance.

如下面的评论中所述,或者让 operator <<拷贝返回,这样它返回的实例(现在是临时实例)是不可达的对于 printImpl

As mentioned in a comment below, alternatively let operator<< return by copy, so that the instance it returns (now a temporary) is unreachable for printImpl.

请注意,可访问性(私人等),而不是 ulog ulog.active 。一旦 printImpl 能够获得指向相关实例的指针或引用, private 就无法保护其免受修改无论。以下是一些如何实现(非详尽无遗)的示例:

Note that the accessibility (private, etc.) of ulog and ulog.active does not matter. As soon as printImpl is able to obtain a pointer or reference to the instance of relevance, private does not protect from modification no matter what. Here are few examples of how that is possible (non-exhaustive):


  1. 呼叫 operator<< LOG 上的code>可能会根据<$的中间修改而更改 LOG.ulog.active c $ c> printLog 或通过 const_cast 获得结果

  2. 调用默认的复制/移动赋值运算符

  3. (因为这是标准布局类) reinterpret_cast LOG 到对其 ulog 成员
  4. 的引用
  5. (因为这些类可以轻松复制) memcpy 将其他状态放入 LOG

  6. 放置-新建 Log 放入 LOG ,这将使先前的引用自动引用新对象,因为 Log 满足该条件

  7. 等。

  1. Calling operator<< on LOG which may now change LOG.ulog.active based on an intervening modification of printLog or by const_casting the result
  2. Calling the defaulted copy/move assignment operators
  3. (since this is a standard-layout class) reinterpret_cast LOG to a reference to its ulog member
  4. (since the classes are trivially copyable) memcpy a different state into LOG
  5. placement-new a new instance of Log into LOG, which will make previous references reference the new object automatically, because Log satisfies the conditions for that
  6. etc.

这篇关于这是错过的优化机会吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆