簡體   English   中英

atomic fetch_add vs添加性能

[英]atomic fetch_add vs add performance

下面的代碼演示了多線程編程的好奇心。 特別是在單個線程中std::memory_order_relaxed增量與常規增量的性能。 我不明白為什么fetch_add(寬松)單線程比常規增量慢兩倍。

static void BM_IncrementCounterLocal(benchmark::State& state) {
  volatile std::atomic_int val2;

  while (state.KeepRunning()) {
    for (int i = 0; i < 10; ++i) {
      DoNotOptimize(val2.fetch_add(1, std::memory_order_relaxed));
    }
  }
}
BENCHMARK(BM_IncrementCounterLocal)->ThreadRange(1, 8);

static void BM_IncrementCounterLocalInt(benchmark::State& state) {
  volatile int val3 = 0;

  while (state.KeepRunning()) {
    for (int i = 0; i < 10; ++i) {
      DoNotOptimize(++val3);
    }
  }
}
BENCHMARK(BM_IncrementCounterLocalInt)->ThreadRange(1, 8);

輸出:

Benchmark                               Time(ns)    CPU(ns) Iterations
      ----------------------------------------------------------------------
      BM_IncrementCounterLocal/threads:1            59         60   11402509                                 
      BM_IncrementCounterLocal/threads:2            30         61   11284498                                 
      BM_IncrementCounterLocal/threads:4            19         62   11373100                                 
      BM_IncrementCounterLocal/threads:8            17         62   10491608

      BM_IncrementCounterLocalInt/threads:1         31         31   22592452                                 
      BM_IncrementCounterLocalInt/threads:2         15         31   22170842                                 
      BM_IncrementCounterLocalInt/threads:4          8         31   22214640                                 
      BM_IncrementCounterLocalInt/threads:8          9         31   21889704

對於volatile int ,編譯器必須確保它不會優化和/或重新排序變量的任何讀/寫。

使用fetch_addCPU必須采取fetch_add讀取 - 修改 - 寫入操作是原子的。

這兩個完全不同的要求:原子性要求意味着CPU必須與機器上的其他CPU通信,確保它們不會在自己的讀寫之間讀/寫給定的內存位置。 如果編譯器使用比較和交換指令編譯fetch_add ,它實際上會發出一個短循環來捕獲其他CPU修改其中的值的情況。

對於volatile int不需要這樣的通信。 相反, volatile要求編譯器不發明任何讀取: volatile設計用於與硬件寄存器的單線程通信,其中僅僅讀取值的行為可能具有副作用。

本地版本不使用原子。 (它使用volatile的事實是一個紅色的鯡魚 - volatile在多線程代碼中基本沒有意義)。

原子版本使用原子能公司(!)。 事實上,只有一個線程實際上將用於訪問變量,這對CPU來說是不可見的,我也不會驚訝於編譯器也沒有發現它。 (沒有必要浪費開發人員的努力來確定將std::atomic_int轉換為int是否安全,當它幾乎永遠不會出現時。如果不需要從多個線程訪問它,則不會編寫atomic_int 。)

因此,原子版本將難以確保增量實際上是原子的,坦率地說,我感到驚訝的是它只慢了2倍 - 我本來期望更像是10倍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM