Pertanyaan ini, meskipun agak tua, membutuhkan beberapa tolok ukur, karena menanyakan cara yang tidak paling idiomatis, atau cara yang dapat ditulis dalam jumlah baris paling sedikit, tetapi cara tercepat . Dan konyol untuk menjawab pertanyaan itu tanpa pengujian yang sebenarnya. Jadi saya membandingkan empat solusi, memset vs. std :: fill vs. ZERO dari jawaban AnT vs solusi yang saya buat dengan menggunakan AVX intrinsics.
Perhatikan bahwa solusi ini tidak umum, ini hanya berfungsi pada data 32 atau 64 bit. Beri komentar jika kode ini melakukan kesalahan.
#include<immintrin.h>
#define intrin_ZERO(a,n){\
size_t x = 0;\
const size_t inc = 32 / sizeof(*(a));/*size of 256 bit register over size of variable*/\
for (;x < n-inc;x+=inc)\
_mm256_storeu_ps((float *)((a)+x),_mm256_setzero_ps());\
if(4 == sizeof(*(a))){\
switch(n-x){\
case 3:\
(a)[x] = 0;x++;\
case 2:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
else if(8 == sizeof(*(a))){\
switch(n-x){\
case 7:\
(a)[x] = 0;x++;\
case 6:\
(a)[x] = 0;x++;\
case 5:\
(a)[x] = 0;x++;\
case 4:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 3:\
(a)[x] = 0;x++;\
case 2:\
((long long *)(a))[x] = 0;break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
}
Saya tidak akan mengklaim bahwa ini adalah metode tercepat, karena saya bukan ahli pengoptimalan tingkat rendah. Melainkan merupakan contoh implementasi dependen arsitektur yang benar yang lebih cepat daripada memset.
Sekarang, ke hasilnya. Saya menghitung kinerja untuk array ukuran 100 int dan panjang, baik secara statis maupun dinamis, tetapi dengan pengecualian D3D, yang melakukan penghapusan kode mati pada array statis, hasilnya sangat sebanding, jadi saya hanya akan menampilkan kinerja array dinamis. Penandaan waktu adalah ms untuk 1 juta iterasi, menggunakan fungsi jam presisi rendah time.h.
clang 3.8 (Menggunakan frontend clang-cl, flag pengoptimalan = / OX / arch: AVX / Oi / Ot)
int:
memset: 99
fill: 97
ZERO: 98
intrin_ZERO: 90
long long:
memset: 285
fill: 286
ZERO: 285
intrin_ZERO: 188
gcc 5.1.0 (tanda pengoptimalan: -O3 -march = native -mtune = native -mavx):
int:
memset: 268
fill: 268
ZERO: 268
intrin_ZERO: 91
long long:
memset: 402
fill: 399
ZERO: 400
intrin_ZERO: 185
msvc 2015 (tanda pengoptimalan: / OX / arch: AVX / Oi / Ot):
int
memset: 196
fill: 613
ZERO: 221
intrin_ZERO: 95
long long:
memset: 273
fill: 559
ZERO: 376
intrin_ZERO: 188
Ada banyak hal menarik yang terjadi di sini: llvm kill gcc, optimasi jerawatan khas MSVC (ia melakukan penghapusan kode mati yang mengesankan pada array statis dan kemudian memiliki kinerja yang buruk untuk diisi). Meskipun implementasi saya jauh lebih cepat, ini mungkin hanya karena ia mengenali bahwa pembersihan bit memiliki overhead yang jauh lebih sedikit daripada operasi pengaturan lainnya.
Penerapan Clang patut dilihat, karena jauh lebih cepat. Beberapa pengujian tambahan menunjukkan bahwa memset-nya sebenarnya dikhususkan untuk memset nol - bukan nol untuk 400 byte array jauh lebih lambat (~ 220ms) dan sebanding dengan gcc. Namun, memset bukan nol dengan array 800 byte tidak membuat perbedaan kecepatan, yang mungkin mengapa dalam kasus itu, memset mereka memiliki kinerja yang lebih buruk daripada implementasi saya - spesialisasi hanya untuk array kecil, dan cuttoff tepat sekitar 800 byte. Perhatikan juga bahwa gcc 'fill' dan 'ZERO' tidak dioptimalkan untuk memset (melihat kode yang dihasilkan), gcc hanya menghasilkan kode dengan karakteristik performa yang identik.
Kesimpulan: memset tidak benar-benar dioptimalkan untuk tugas ini sebagaimana orang akan berpura-pura (jika tidak, memset gcc dan msvc dan llvm akan memiliki kinerja yang sama). Jika kinerja penting, maka memset tidak boleh menjadi solusi akhir, terutama untuk larik berukuran sedang yang canggung ini, karena tidak dikhususkan untuk pembersihan bit, dan tidak dioptimalkan secara manual lebih baik daripada yang dapat dilakukan oleh kompiler sendiri.
new
adalah C ++ ...