เพื่อตอบเพียงแค่นี้:
คำถามของฉันคือเนื่องจากฉันไม่ได้วนซ้ำแถวลำดับที่ต่อเนื่องกันในแต่ละครั้งในกรณีเหล่านี้ฉันจะเสียสละประสิทธิภาพที่เพิ่มขึ้นทันทีจากการจัดสรรส่วนประกอบด้วยวิธีนี้หรือไม่? เป็นปัญหาหรือไม่เมื่อฉันทำซ้ำใน C ++ อาร์เรย์ที่ต่อเนื่องกันสองชุดและใช้ข้อมูลจากทั้งสองในแต่ละรอบ
ไม่ (อย่างน้อยก็ไม่จำเป็น) ในกรณีส่วนใหญ่แคชคอนโทรลเลอร์สามารถจัดการกับการอ่านจากอาร์เรย์ที่ต่อเนื่องกันได้มากกว่าหนึ่งชุดได้อย่างมีประสิทธิภาพ ส่วนที่สำคัญคือการพยายามเข้าถึงอาเรย์แต่ละรายการอย่างเป็นเส้นตรง
เพื่อแสดงสิ่งนี้ฉันได้เขียนเกณฑ์มาตรฐานขนาดเล็ก (ใช้เกณฑ์มาตรฐานทั่วไป)
เริ่มต้นด้วยโครงสร้างเวกเตอร์อย่างง่าย:
struct float3 { float x, y, z; };
ฉันพบว่าการวนซ้ำการรวมองค์ประกอบของสองอาร์เรย์ที่แยกกันและการจัดเก็บผลลัพธ์ในลำดับที่สามดำเนินการเหมือนกับรุ่นที่ข้อมูลต้นฉบับถูกอินเตอร์ลีฟในอาร์เรย์เดียวและผลลัพธ์ที่เก็บไว้ในลำดับที่สาม อย่างไรก็ตามฉันพบว่าถ้าฉันแทรกผลลัพธ์กับแหล่งที่มาประสิทธิภาพก็ลดลง (ประมาณ 2 เท่า)
ถ้าฉันเข้าถึงข้อมูลแบบสุ่มประสิทธิภาพการทำงานที่ได้รับจากปัจจัยระหว่าง 10 ถึง 20
การจับเวลา (10,000,000 องค์ประกอบ)
การเข้าถึงเชิงเส้น
- อาร์เรย์แยกต่างหาก 0.21 วินาที
- 0.21s interleaved แหล่ง
- interleaved source และผลลัพธ์ 0.48s
การเข้าถึงแบบสุ่ม (ไม่ใส่ข้อคิดเห็นสุ่ม_shuffle)
- อาร์เรย์ที่แยกต่างหาก 2.42 วินาที
- แหล่ง interleaved 4.43s
- interleaved source และผลลัพธ์ 4.00s
แหล่งที่มา (รวบรวมด้วย Visual Studio 2013):
#include <Windows.h>
#include <vector>
#include <algorithm>
#include <iostream>
struct float3 { float x, y, z; };
float3 operator+( float3 const &a, float3 const &b )
{
return float3{ a.x + b.x, a.y + b.y, a.z + b.z };
}
struct Both { float3 a, b; };
struct All { float3 a, b, res; };
// A version without any indirection
void sum( float3 *a, float3 *b, float3 *res, int n )
{
for( int i = 0; i < n; ++i )
*res++ = *a++ + *b++;
}
void sum( float3 *a, float3 *b, float3 *res, int *index, int n )
{
for( int i = 0; i < n; ++i, ++index )
res[*index] = a[*index] + b[*index];
}
void sum( Both *both, float3 *res, int *index, int n )
{
for( int i = 0; i < n; ++i, ++index )
res[*index] = both[*index].a + both[*index].b;
}
void sum( All *all, int *index, int n )
{
for( int i = 0; i < n; ++i, ++index )
all[*index].res = all[*index].a + all[*index].b;
}
class PerformanceTimer
{
public:
PerformanceTimer() { QueryPerformanceCounter( &start ); }
double time()
{
LARGE_INTEGER now, freq;
QueryPerformanceCounter( &now );
QueryPerformanceFrequency( &freq );
return double( now.QuadPart - start.QuadPart ) / double( freq.QuadPart );
}
private:
LARGE_INTEGER start;
};
int main( int argc, char* argv[] )
{
const int count = 10000000;
std::vector< float3 > a( count, float3{ 1.f, 2.f, 3.f } );
std::vector< float3 > b( count, float3{ 1.f, 2.f, 3.f } );
std::vector< float3 > res( count );
std::vector< All > all( count, All{ { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f } } );
std::vector< Both > both( count, Both{ { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f } } );
std::vector< int > index( count );
int n = 0;
std::generate( index.begin(), index.end(), [&]{ return n++; } );
//std::random_shuffle( index.begin(), index.end() );
PerformanceTimer timer;
// uncomment version to test
//sum( &a[0], &b[0], &res[0], &index[0], count );
//sum( &both[0], &res[0], &index[0], count );
//sum( &all[0], &index[0], count );
std::cout << timer.time();
return 0;
}