[英]C++: assignment operator: pass-by-value (copy-and-swap) vs pass-by-reference
[英]c++ pass value by reference vs by copy of POD
我聽說按引用傳遞變量並不總是比按值傳遞快。 對於大變量,通過引用傳遞速度更快,但是對於小變量,此問題可能很棘手。
通過值傳遞需要花費時間來創建副本,但是采用局部變量的值應該更快。 通過引用傳遞並不會浪費時間來創建變量副本,而是先查看指針,然后查看所需的數據。
我知道這個細節在優化問題中並不那么重要,但是對我來說衡量它很有趣(我知道-O0是為了優化而通過的,但是這段代碼很簡單,在優化之后我不確定自己在測量什么)
g ++ -std = c ++ 14 -O0 -g3 -DSIZE_OF_DATA_ARRAY = 16 main.cpp && ./a.out
g ++(Ubuntu 6.3.0-12ubuntu2)6.3.0 20170406
我的問題:
為什么執行時間對於復制vs結構大小來說是相當恆定的?
為什么復制的門檻在16到17之間?
猜猜:它與緩存連接
我的代碼:
#include <iostream>
#include <vector>
#include <limits>
#include <chrono>
#include <iomanip>
#include <vector>
#include <algorithm>
struct Data {
double x[SIZE_OF_DATA_ARRAY];
};
double workOnData(Data &data) {
for (auto i = 0; i < 10; ++i) {
data.x[0] -= 0.5 * (data.x[0] - 1);
}
return data.x[0];
}
void runTestSuite() {
auto queries = 1000000;
Data data;
for (auto i = 0; i < queries; ++i) {
data.x[0] = i;
auto val = workOnData(data);
if (val == -357)
data.x[0] = 1;
}
}
int main() {
std::cout << "sizeof(Data) = " << sizeof(Data) << "\n";
size_t numberOfTests = 99;
std::vector<std::chrono::duration<double>> timeMeasurements{numberOfTests};
std::chrono::time_point<std::chrono::system_clock> startTime, endTime;
for (auto i = 0; i < numberOfTests; ++i) {
startTime = std::chrono::system_clock::now();
runTestSuite();
endTime = std::chrono::system_clock::now();
timeMeasurements[i] = endTime - startTime;
}
std::sort(timeMeasurements.begin(), timeMeasurements.end());
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::cout << std::put_time(std::localtime(&now_c), "%F %T")
<< ": median time = " << timeMeasurements[numberOfTests * 0.5].count() << "s\n";
return 0;
}
為什么執行時間對於復制vs結構大小來說是相當恆定的?
最好的理解是從查看匯編語言到查看編譯器發出的指令。 此處的優化將取決於編譯器的優化設置,以及您是處於發布配置還是調試配置。
還取決於處理器。 例如,某些處理器可能具有用於復制大塊內存的專門指令。 其他處理器可能會根據結構的大小以並行塊的形式復制數據。 同樣,某些平台可能具有硬件幫助,例如DMA控制器。
,有時候展開操作可能比使用特殊說明或硬件幫助更快(取決於數據大小)。
為什么復制的門檻在16到17之間?
閾值可以在對准邊界和非對准之間。
讓我們以32位處理器為例。 它喜歡一次訪問(獲取)4個字節。 訪問24個字節需要進行6次訪存。 訪問16個字節需要4次提取。
但是,訪問17、18或19個字節需要5次提取。 它可能會再獲取4個字節來獲取其余字節。
另一種情況是復制功能的實現。 某些復制功能可能將32位副本用於第一個4字節數量的集合,然后切換到字節比較其余部分。 它可以根據數據大小切換為所有字節的字節復制。 許多可能性。
您系統的真相在於調試匯編語言或復制數據的功能。
緩存命中和未命中
您的性能指標可能會因處理器緩存操作而有所偏差。 如果處理器將您的數據保存在緩存中,則循環會快很多。 通常,首次訪問數據會對性能造成影響。 如果您的數據對於高速緩存而言太大或位於數據高速緩存大小的范圍之外,則可能會浪費更多的時間來重新加載數據高速緩存。
指令緩存問題
許多處理器具有用於數據指令的大型管線和高速緩存。 當它們遇到分支時(例如for
循環的結尾),處理器可能必須重置指令緩存並從程序中的另一個位置重新加載。 這需要時間。 您可以通過展開不同大小的塊並測量性能來演示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.