Krótka odpowiedź
Pod Windows kompilacji z Visual Studio 2010 w trybie uwalniania kierowania platformy x64, przechodząc rozpakowanego argumentów jest znacznie wolniejszy niż przekazując jeden struct przez odniesienie lub nawet przez wartość.
Wyniki śledzić:
Multi result = 0; multi iterations = 10000
Ref result = 0; ref iterations = 10000
Value result = 0; value iterations = 10000
---------------------------------------------------
Timer "multi args":
Total time = 0.387886
------------------------------------------
Timer "struct by reference":
Total time = 0.0679177
------------------------------------------
Timer "struct by value":
Total time = 0.143382
Obserwacja
Bardziej czynność wykonuje obliczenia w swoim ciele, tym mniej napowietrznych kopia będzie bolało wydajność. W rzeczywistości przetestowałem funkcję, która wykonuje tylko kilka dodatków i jeden podział.
Niektóre dane teraz
Mam zdefiniowane struct zawierający wszystkie parametry
struct Args{
int leftchild;
int rightchild;
int ly_index;
int uy_index;
int bit;
int nodepos;
int amount;
int level;
Args(int l, int r, int ly, int uy, int b, int n, int a, int lev)
: leftchild(l)
, rightchild(r)
, ly_index(ly)
, uy_index(uy)
, bit(b)
, nodepos(n)
, amount(a)
, level(lev)
{}
};
i 3 funkcje.
static size_t counter1 = 0;
static size_t counter2 = 0;
static size_t counter3 = 0;
int FindPoints(int leftchild, int rightchild, int ly_index, int uy_index, int bit, int nodepos, int amount, int level)
{
++counter1;
leftchild = leftchild + (rightchild + ly_index + uy_index + bit + nodepos + amount + level)/100 - 1;
return leftchild ? FindPoints(leftchild, rightchild, ly_index, uy_index, bit, nodepos, amount, level) : 0;
}
int FindPointsRef(Args& a)
{
++counter2;
a.leftchild = a.leftchild + (a.rightchild + a.ly_index + a.uy_index + a.bit + a.nodepos + a.amount + a.level)/100 - 1;
return a.leftchild ? FindPointsRef(a) : 0;
}
int FindPointsValue(Args a)
{
++counter3;
a.leftchild = a.leftchild + (a.rightchild + a.ly_index + a.uy_index + a.bit + a.nodepos + a.amount + a.level)/100 - 1;
return a.leftchild ? FindPointsValue(a) : 0;
}
Wszyscy wykonują tę samą pracę, ale pierwszy bierze argumenty jak w swoim pytaniu, drugi bierze struct argumentów przez odniesienie a trzeci bierze struct przez wartość.
Zbudowałem program przy użyciu Visual Studio 2010, wypuszczono konfigurację x64 i zmierzyłem przy użyciu domowej klasy, która otacza funkcję Windows QueryPerformanceCounter
i zapewnia wygodny operator wyjścia.
Główną funkcją wygląda następująco:
int main()
{
// define my timers
PersistentTimer timer_multi("multi args");
PersistentTimer timer_ref("struct by reference");
PersistentTimer timer_value("struct by value");
int leftchild = 10000; // number of iterations; 10000 to prevent stack overflow
int rightchild = 1; // sum of other values is < 100 (look to FindPoints* implementations)
int ly_index = 2;
int uy_index = 3;
int bit = 4;
int nodepos = 5;
int amount = 6;
int level = 7;
// define structs of arguments for second and third function
Args args_ref(leftchild, rightchild, ly_index, uy_index, bit, nodepos, amount, level);
Args args_copy(leftchild, rightchild, ly_index, uy_index, bit, nodepos, amount, level);
// return values initialized to a non zero value just to be sure that functions have done thir job
int a1 = 5;
timer_multi.measure([&]{
a1 = FindPoints(leftchild, rightchild, ly_index, uy_index, bit, nodepos, amount, level);
});
std::cout << "Multi result = " << a1 << "; multi iterations = " << counter1 << '\n';
int a2 = 5;
timer_ref.measure([&]{
a2 = FindPointsRef(args_ref);
});
std::cout << "Ref result = " << a2 << "; ref iterations = " << counter2 << '\n';
int a3 = 5;
timer_value.measure([&]{
a3 = FindPointsValue(args_copy);
});
std::cout << "Value result = " << a3 << "; value iterations = " << counter3 << '\n';
// print timer results
std::cout << timer_multi << timer_ref << timer_value;
getchar();
}
Cóż, to będzie oczywiście trwać dłużej niż gdybyś miał mniej - o ile parametry zdarzyć mapować tych samych rejestrów rozmówcy i odbierającym (mało prawdopodobne). Ale czy te parametry nie są niezbędne do prawidłowego działania twojej funkcji? –
A co z definicją struktury i przekazaniem jej przez odniesienie? –
@PaoloM Jaki wpływ będzie miało na wydajność?Jestem bardzo zainteresowany :) – Mads