Apakah lebih baik menggunakan std :: memcpy () atau std :: copy () dalam hal kinerja?

163

Apakah lebih baik digunakan memcpyseperti yang ditunjukkan di bawah ini atau lebih baik digunakan std::copy()dalam hal kinerja? Mengapa?

char *bits = NULL;
...

bits = new (std::nothrow) char[((int *) copyMe->bits)[0]];
if (bits == NULL)
{
    cout << "ERROR Not enough memory.\n";
    exit(1);
}

memcpy (bits, copyMe->bits, ((int *) copyMe->bits)[0]);
pengguna576670
sumber
Catatan yang chardapat ditandatangani atau tidak ditandatangani, tergantung pada implementasinya. Jika jumlah byte bisa> = 128, maka gunakan unsigned charuntuk array byte Anda. (Para (int *)pemain juga akan lebih aman (unsigned int *).)
Dan Breslau
13
Kenapa kamu tidak menggunakan std::vector<char>? Atau karena Anda mengatakan bits, std::bitset?
GManNickG
2
Sebenarnya, bisakah Anda menjelaskan kepada saya apa yang (int*) copyMe->bits[0]terjadi?
user3728501
4
tidak yakin mengapa sesuatu yang tampak seperti kekacauan dengan konteks vital yang disediakan sangat sedikit di +81, tapi hei. @ user3728501 tebakan saya adalah bahwa mulai dari buffer memegang intmenentukan ukurannya, tapi itu sepertinya resep untuk implementasi bencana yang ditentukan, seperti banyak hal lain di sini.
underscore_d
2
Faktanya, (int *)pemeran itu hanyalah perilaku murni yang tidak terdefinisi, bukan implementasi-didefinisikan. Mencoba melakukan jenis-hukuman melalui para pemain melanggar aturan alias yang ketat dan karenanya benar-benar tidak ditentukan oleh Standar. (Juga, dalam C ++ walaupun bukan C, Anda tidak dapat mengetik-pun melalui unionsalah satu dari keduanya.) Satu-satunya pengecualian adalah jika Anda mengonversi ke varian char*, tetapi kelonggarannya tidak simetris.
underscore_d

Jawaban:

207

Saya akan menentang kebijaksanaan umum di sini yang std::copyakan memiliki sedikit kehilangan kinerja, hampir tak terlihat. Saya hanya melakukan tes dan menemukan bahwa itu tidak benar: Saya memang melihat perbedaan kinerja. Namun, pemenangnya adalah std::copy.

Saya menulis implementasi C ++ SHA-2. Dalam pengujian saya, saya hash 5 string menggunakan keempat versi SHA-2 (224, 256, 384, 512), dan saya loop 300 kali. Saya mengukur waktu menggunakan Boost.timer. 300 loop counter itu cukup untuk sepenuhnya menstabilkan hasil saya. Saya menjalankan tes masing-masing 5 kali, bergantian antara memcpyversi dan std::copyversi. Kode saya mengambil keuntungan dari mengambil data dalam potongan sebanyak mungkin (banyak implementasi lain beroperasi dengan char/ char *, sedangkan saya beroperasi dengan T/ T *(di mana Tadalah tipe terbesar dalam implementasi pengguna yang memiliki perilaku overflow yang benar), sehingga akses memori cepat pada tipe terbesar yang saya dapat adalah pusat kinerja algoritma saya. Ini adalah hasil saya:

Waktu (dalam detik) untuk menyelesaikan uji SHA-2

std::copy   memcpy  % increase
6.11        6.29    2.86%
6.09        6.28    3.03%
6.10        6.29    3.02%
6.08        6.27    3.03%
6.08        6.27    3.03%

Total peningkatan rata-rata kecepatan std :: copy over memcpy: 2.99%

Kompiler saya adalah gcc 4.6.3 pada Fedora 16 x86_64. Bendera pengoptimalan saya adalah -Ofast -march=native -funsafe-loop-optimizations.

Kode untuk implementasi SHA-2 saya.

Saya memutuskan untuk menjalankan tes pada implementasi MD5 saya juga. Hasilnya jauh lebih tidak stabil, jadi saya memutuskan untuk melakukan 10 kali. Namun, setelah beberapa upaya pertama saya, saya mendapatkan hasil yang sangat bervariasi dari satu lari ke yang berikutnya, jadi saya menduga ada semacam aktivitas OS yang terjadi. Saya memutuskan untuk memulai dari awal.

Pengaturan dan bendera kompiler yang sama. Hanya ada satu versi MD5, dan ini lebih cepat dari SHA-2, jadi saya melakukan 3000 loop pada set yang sama dari 5 string tes.

Ini adalah 10 hasil akhir saya:

Waktu (dalam detik) untuk menyelesaikan tes MD5

std::copy   memcpy      % difference
5.52        5.56        +0.72%
5.56        5.55        -0.18%
5.57        5.53        -0.72%
5.57        5.52        -0.91%
5.56        5.57        +0.18%
5.56        5.57        +0.18%
5.56        5.53        -0.54%
5.53        5.57        +0.72%
5.59        5.57        -0.36%
5.57        5.56        -0.18%

Total penurunan rata-rata kecepatan std :: copy over memcpy: 0.11%

Kode untuk implementasi MD5 saya

Hasil ini menunjukkan bahwa ada beberapa optimasi yang std :: copy digunakan dalam tes SHA-2 saya yang std::copytidak dapat digunakan dalam tes MD5 saya. Dalam tes SHA-2, kedua array diciptakan dalam fungsi yang sama yang disebut std::copy/ memcpy. Dalam tes MD5 saya, salah satu array diteruskan ke fungsi sebagai parameter fungsi.

Saya melakukan sedikit pengujian lagi untuk melihat apa yang bisa saya lakukan untuk membuat std::copylebih cepat lagi. Jawabannya ternyata sederhana: aktifkan optimasi waktu tautan. Ini adalah hasil saya dengan LTO dihidupkan (opsi -flto di gcc):

Waktu (dalam detik) untuk menyelesaikan uji MD5 dengan -flto

std::copy   memcpy      % difference
5.54        5.57        +0.54%
5.50        5.53        +0.54%
5.54        5.58        +0.72%
5.50        5.57        +1.26%
5.54        5.58        +0.72%
5.54        5.57        +0.54%
5.54        5.56        +0.36%
5.54        5.58        +0.72%
5.51        5.58        +1.25%
5.54        5.57        +0.54%

Total peningkatan rata-rata kecepatan std :: copy over memcpy: 0.72%

Singkatnya, tampaknya tidak ada penalti kinerja untuk menggunakan std::copy. Bahkan, tampaknya ada peningkatan kinerja.

Penjelasan hasil

Jadi mengapa mungkin std::copymemberikan peningkatan kinerja?

Pertama, saya tidak berharap itu lebih lambat untuk implementasi apa pun, selama optimasi inlining dihidupkan. Semua penyusun inline secara agresif; itu mungkin optimasi yang paling penting karena memungkinkan banyak optimasi lainnya. std::copydapat (dan saya menduga semua implementasi dunia nyata lakukan) mendeteksi bahwa argumen sepele disalin dan bahwa memori diletakkan secara berurutan. Ini berarti bahwa dalam kasus terburuk, ketika memcpylegal, std::copyharus melakukan tidak lebih buruk. Implementasi sepele dari std::copyyang memcpyharus memenuhi kriteria kompiler Anda "selalu sebaris ini ketika mengoptimalkan untuk kecepatan atau ukuran".

Namun, std::copyjuga menyimpan lebih banyak informasinya. Saat Anda menelepon std::copy, fungsi tersebut menjaga jenisnya tetap utuh. memcpyberoperasi pada void *, yang membuang hampir semua informasi yang berguna. Sebagai contoh, jika saya memasukkan array std::uint64_t, kompiler atau pelaksana perpustakaan mungkin dapat memanfaatkan keselarasan 64-bit dengan std::copy, tetapi mungkin lebih sulit untuk melakukannya dengan memcpy. Banyak implementasi algoritma seperti ini bekerja dengan terlebih dahulu mengerjakan bagian yang tidak selaras di awal rentang, kemudian bagian yang disejajarkan, kemudian bagian yang tidak selaras di bagian akhir. Jika semuanya dijamin akan disejajarkan, maka kode menjadi lebih sederhana dan lebih cepat, dan lebih mudah bagi prediktor cabang dalam prosesor Anda untuk mendapatkan yang benar.

Optimalisasi prematur?

std::copyberada dalam posisi yang menarik. Saya berharap itu tidak pernah lebih lambat dari memcpydan kadang-kadang lebih cepat dengan kompiler optimisasi modern. Apalagi apa pun yang Anda bisa memcpy, Anda bisa std::copy. memcpytidak memungkinkan tumpang tindih dalam buffer, sedangkan std::copydukungan tumpang tindih dalam satu arah (dengan std::copy_backwarduntuk arah lain tumpang tindih). memcpyhanya bekerja pada pointer, std::copybekerja pada setiap iterator ( std::map, std::vector, std::deque, atau sendiri jenis kustom saya). Dengan kata lain, Anda hanya perlu menggunakan std::copysaat Anda perlu menyalin potongan data di sekitar.

David Stone
sumber
35
Saya ingin menekankan bahwa ini tidak berarti bahwa std::copy2,99% atau 0,72% atau -0,11% lebih cepat daripada memcpy, kali ini adalah untuk seluruh program untuk dijalankan. Namun, saya biasanya merasa bahwa tolok ukur dalam kode nyata lebih berguna daripada tolok ukur dalam kode palsu. Seluruh program saya mendapat perubahan kecepatan eksekusi. Efek nyata dari hanya dua skema penyalinan akan memiliki perbedaan yang lebih besar daripada yang ditunjukkan di sini ketika diambil secara terpisah, tetapi ini menunjukkan bahwa mereka dapat memiliki perbedaan yang terukur dalam kode aktual.
David Stone
2
Saya ingin tidak setuju dengan temuan Anda, tetapi hasilnya adalah hasil: /. Namun satu pertanyaan (saya tahu itu sudah lama sekali dan Anda tidak ingat penelitian, jadi cukup komentar cara Anda berpikir), Anda mungkin tidak melihat ke kode perakitan;
ST3
2
Menurut pendapat saya memcpydan std::copymemiliki implementasi yang berbeda, jadi dalam beberapa kasus kompiler mengoptimalkan kode sekitar dan kode salinan memori yang sebenarnya sebagai bagian integral dari kode. Dengan kata lain kadang-kadang satu lebih baik daripada yang lain dan bahkan dengan kata lain, memutuskan mana yang akan digunakan adalah optimasi prematur atau bahkan bodoh, karena dalam setiap situasi Anda harus melakukan penelitian baru dan, terlebih lagi, program biasanya sedang dikembangkan, jadi setelah beberapa perubahan kecil keuntungan dari fungsi di atas yang lain mungkin hilang.
ST3
3
@ ST3: Saya akan membayangkan bahwa dalam kasus terburuk, std::copyadalah fungsi inline sepele yang hanya memanggil memcpyketika itu legal. Inlining dasar akan menghilangkan perbedaan kinerja negatif. Saya akan memperbarui posting dengan sedikit penjelasan tentang mengapa std :: copy mungkin lebih cepat.
David Stone
7
Analisis yang sangat informatif. Re Total penurunan rata-rata dalam kecepatan std :: copy over memcpy: 0,11% , sementara jumlahnya benar, hasilnya tidak signifikan secara statistik. Interval kepercayaan 95% untuk perbedaan rata-rata adalah (-0,013s, 0,025), yang termasuk nol. Saat Anda menunjukkan ada variasi dari sumber lain dan dengan data Anda, Anda mungkin akan mengatakan kinerjanya sama. Sebagai referensi, dua hasil lainnya adalah signifikan secara statistik - peluang Anda akan melihat perbedaan dalam waktu yang ekstrim ini secara kebetulan adalah sekitar 1 banding 100 juta (pertama) dan 1 dari 20.000 (terakhir).
TooTone
78

Semua kompiler yang saya tahu akan mengganti yang sederhana std::copydengan yang memcpytepat, atau bahkan lebih baik, membuat salinan vektor sehingga akan lebih cepat dari a memcpy.

Dalam kasus apa pun: profil dan cari tahu sendiri. Kompiler yang berbeda akan melakukan hal yang berbeda, dan sangat mungkin itu tidak akan melakukan persis apa yang Anda minta.

Lihat presentasi ini tentang optimisasi kompiler (pdf).

Inilah yang dilakukan GCC untuk std::copytipe POD sederhana .

#include <algorithm>

struct foo
{
  int x, y;    
};

void bar(foo* a, foo* b, size_t n)
{
  std::copy(a, a + n, b);
}

Inilah pembongkaran (dengan hanya -Ooptimasi), menunjukkan panggilan ke memmove:

bar(foo*, foo*, unsigned long):
    salq    $3, %rdx
    sarq    $3, %rdx
    testq   %rdx, %rdx
    je  .L5
    subq    $8, %rsp
    movq    %rsi, %rax
    salq    $3, %rdx
    movq    %rdi, %rsi
    movq    %rax, %rdi
    call    memmove
    addq    $8, %rsp
.L5:
    rep
    ret

Jika Anda mengubah fungsi tanda tangan ke

void bar(foo* __restrict a, foo* __restrict b, size_t n)

kemudian memmovemenjadi memcpyuntuk sedikit peningkatan kinerja. Perhatikan bahwa memcpyitu sendiri akan sangat vektor.

Peter Alexander
sumber
1
Bagaimana saya bisa membuat profil. Alat apa yang digunakan (di windows dan linux)?
user576670
5
@ Konrad, Anda benar. Tetapi memmoveseharusnya tidak lebih cepat - melainkan harus lebih lambat karena harus memperhitungkan kemungkinan bahwa kedua rentang data tumpang tindih. Saya pikir std::copymemungkinkan data yang tumpang tindih, dan karenanya harus menelepon memmove.
Charles Salvia
2
@ Konrad: Jika memmove selalu lebih cepat dari memcpy, maka memcpy akan memanggil memmove. Apa std :: copy benar-benar mungkin dikirim ke (jika ada) adalah implementasi-didefinisikan, sehingga tidak berguna untuk menyebutkan secara spesifik tanpa menyebutkan implementasi.
Fred Nurk
1
Meskipun, program sederhana untuk mereproduksi perilaku ini, dikompilasi dengan -O3 di bawah GCC menunjukkan kepada saya a memcpy. Ini membuat saya percaya bahwa GCC memeriksa apakah ada memori yang tumpang tindih.
jweyrich
1
@ Konrad: standar std::copymemungkinkan tumpang tindih dalam satu arah tetapi tidak yang lain. Awal dari output tidak dapat terletak di dalam rentang input, tetapi awal dari input diizinkan untuk berada di dalam rentang output. Ini agak aneh, karena urutan tugas ditentukan, dan panggilan mungkin UB meskipun efek dari tugas-tugas itu, dalam urutan itu, didefinisikan. Tapi saya kira pembatasan memungkinkan optimasi vektorisasi.
Steve Jessop
24

Selalu gunakan std::copykarena memcpyterbatas hanya pada struktur POD gaya C, dan kompiler kemungkinan akan mengganti panggilan std::copydengan memcpyjika target sebenarnya adalah POD.

Plus, std::copydapat digunakan dengan banyak jenis iterator, bukan hanya pointer. std::copylebih fleksibel tanpa kehilangan kinerja dan merupakan pemenang yang jelas.

Anak anjing
sumber
Mengapa Anda ingin menyalin di sekitar iterator?
Atmocreations
3
Anda tidak menyalin iterator, melainkan rentang yang ditentukan oleh dua iterator. Misalnya, std::copy(container.begin(), container.end(), destination);akan menyalin konten container(semuanya antara begindan end) ke buffer yang ditunjukkan oleh destination. std::copytidak memerlukan shenanigans seperti &*container.begin()atau &container.back() + 1.
David Stone
16

Secara teori, memcpymungkin memiliki keunggulan kinerja yang sedikit , tidak terlihat , sangat kecil , hanya karena tidak memiliki persyaratan yang sama std::copy. Dari halaman manual dari memcpy:

Untuk menghindari overflow, ukuran array yang ditunjuk oleh parameter tujuan dan sumber, harus setidaknya num byte, dan tidak boleh tumpang tindih (untuk tumpang tindih blok memori, memmove adalah pendekatan yang lebih aman).

Dengan kata lain, memcpybisa mengabaikan kemungkinan data yang tumpang tindih. (Melewati array yang tumpang tindih memcpyadalah perilaku yang tidak terdefinisi.) Jadi memcpytidak perlu memeriksa kondisi ini secara eksplisit, sedangkan std::copydapat digunakan selama OutputIteratorparameter tidak dalam kisaran sumber. Perhatikan ini tidak sama dengan mengatakan bahwa jangkauan sumber dan jangkauan tujuan tidak dapat tumpang tindih.

Jadi karena std::copymemiliki persyaratan yang agak berbeda, secara teori seharusnya sedikit (dengan penekanan ekstrem pada sedikit ) lebih lambat, karena mungkin akan memeriksa tumpang tindih array-C, atau mendelegasikan penyalinan array-C ke memmove, yang perlu melakukan memeriksa. Namun dalam praktiknya, Anda (dan sebagian besar profiler) mungkin bahkan tidak akan mendeteksi perbedaan apa pun.

Tentu saja, jika Anda tidak bekerja dengan POD , Anda tidak dapat menggunakannya memcpy.

Charles Salvia
sumber
7
Ini berlaku untuk std::copy<char>. Tetapi std::copy<int>dapat berasumsi bahwa inputnya selaras. Itu akan membuat perbedaan yang jauh lebih besar, karena itu mempengaruhi setiap elemen. Tumpang tindih adalah pemeriksaan satu kali.
MSalters
2
@MSalters, benar, tetapi sebagian besar implementasi yang memcpysaya lihat memeriksa penyelarasan dan mencoba untuk menyalin kata-kata daripada byte demi byte.
Charles Salvia
1
std :: copy () juga dapat mengabaikan memori yang tumpang tindih. Jika Anda ingin mendukung memori yang tumpang tindih, Anda harus menulis sendiri logikanya untuk memanggil std :: reverse_copy () dalam situasi yang sesuai.
Cygon
2
Ada argumen yang berlawanan yang dapat dibuat: ketika melalui memcpyantarmuka itu kehilangan informasi penyelarasan. Oleh karena itu, memcpyharus melakukan pemeriksaan pelurusan pada saat run-time untuk menangani awal dan akhir yang tidak selaras. Cek itu mungkin murah tetapi tidak gratis. Sedangkan std::copydapat menghindari pemeriksaan ini dan membuat vektor. Juga, kompiler dapat membuktikan bahwa array sumber dan tujuan tidak tumpang tindih dan vektorisasi lagi tanpa pengguna harus memilih antara memcpydan memmove.
Maxim Egorushkin
11

Aturan saya sederhana. Jika Anda menggunakan C ++ lebih suka perpustakaan C ++ dan bukan C :)

UmmaGumma
sumber
40
C ++ secara eksplisit dirancang untuk memungkinkan menggunakan perpustakaan C. Ini bukan kecelakaan. Seringkali lebih baik menggunakan std :: copy daripada memcpy di C ++, tetapi ini tidak ada hubungannya dengan yang mana adalah C, dan argumen semacam itu biasanya merupakan pendekatan yang salah.
Fred Nurk
2
@ FredNurk Biasanya Anda ingin menghindari area C yang lemah di mana C ++ memberikan alternatif yang lebih aman.
Phil1970
@ Phil1970 Saya tidak yakin bahwa C ++ jauh lebih aman dalam hal ini. Kita masih harus melewati iterator yang valid yang tidak dibanjiri, dll. Saya kira bisa menggunakan std::end(c_arr)alih-alih c_arr + i_hope_this_is_the_right_number_of elementslebih aman? dan mungkin yang lebih penting, lebih jelas. Dan itu akan menjadi poin yang saya tekankan dalam kasus khusus ini: std::copy()lebih idiomatis, lebih dapat dipelihara jika jenis iterator berubah nanti, mengarah pada sintaks yang lebih jelas, dll.
underscore_d
1
@underscore_d std::copylebih aman karena dengan benar menyalin data yang dikirimkan jika mereka bukan tipe POD. memcpyakan dengan senang hati menyalin std::stringobjek ke representasi byte baru demi byte.
Jens
3

Hanya tambahan kecil: Perbedaan kecepatan antara memcpy()dan std::copy()dapat sedikit bervariasi tergantung pada apakah optimasi diaktifkan atau dinonaktifkan. Dengan g ++ 6.2.0 dan tanpa optimasi memcpy()jelas menang:

Benchmark             Time           CPU Iterations
---------------------------------------------------
bm_memcpy            17 ns         17 ns   40867738
bm_stdcopy           62 ns         62 ns   11176219
bm_stdcopy_n         72 ns         72 ns    9481749

Ketika optimisasi diaktifkan ( -O3), semuanya terlihat hampir sama lagi:

Benchmark             Time           CPU Iterations
---------------------------------------------------
bm_memcpy             3 ns          3 ns  274527617
bm_stdcopy            3 ns          3 ns  272663990
bm_stdcopy_n          3 ns          3 ns  274732792

Semakin besar array, semakin sedikit efek yang didapatnya, tetapi bahkan pada N=1000 memcpy() sekitar dua kali lebih cepat ketika optimasi tidak diaktifkan.

Kode sumber (memerlukan Google Benchmark):

#include <string.h>
#include <algorithm>
#include <vector>
#include <benchmark/benchmark.h>

constexpr int N = 10;

void bm_memcpy(benchmark::State& state)
{
  std::vector<int> a(N);
  std::vector<int> r(N);

  while (state.KeepRunning())
  {
    memcpy(r.data(), a.data(), N * sizeof(int));
  }
}

void bm_stdcopy(benchmark::State& state)
{
  std::vector<int> a(N);
  std::vector<int> r(N);

  while (state.KeepRunning())
  {
    std::copy(a.begin(), a.end(), r.begin());
  }
}

void bm_stdcopy_n(benchmark::State& state)
{
  std::vector<int> a(N);
  std::vector<int> r(N);

  while (state.KeepRunning())
  {
    std::copy_n(a.begin(), N, r.begin());
  }
}

BENCHMARK(bm_memcpy);
BENCHMARK(bm_stdcopy);
BENCHMARK(bm_stdcopy_n);

BENCHMARK_MAIN()

/* EOF */
Grumbel
sumber
18
Mengukur kinerja dengan pengoptimalan yang dinonaktifkan adalah ... well ... hampir tidak ada gunanya ... Jika Anda tertarik dengan kinerja, Anda tidak akan dapat dikompilasi tanpa optimasi.
bolov
3
@bolov Tidak selalu. Dalam beberapa kasus, program yang relatif cepat dalam debug penting untuk dimiliki.
Acorn
2

Jika Anda benar-benar membutuhkan kinerja penyalinan maksimum (yang mungkin tidak Anda), gunakan keduanya .

Ada banyak yang dapat dilakukan untuk mengoptimalkan penyalinan memori - bahkan lebih jika Anda bersedia menggunakan beberapa utas / inti untuk itu. Lihat, misalnya:

Apa yang hilang / kurang optimal dalam implementasi memcpy ini?

baik pertanyaan dan beberapa jawaban telah menyarankan implementasi atau tautan ke implementasi.

einpoklum
sumber
4
mode pedant: dengan peringatan biasa bahwa "jangan gunakan salah satu dari mereka " berarti jika Anda telah membuktikan bahwa Anda memiliki situasi / persyaratan yang sangat spesifik di mana fungsi Standar yang disediakan oleh implementasi Anda tidak cukup cepat ; jika tidak, kekhawatiran saya yang biasa adalah bahwa orang-orang yang belum membuktikan bahwa teralihkan pada optimalisasi kode penyalinan alih-alih bagian yang biasanya lebih berguna dari program mereka.
underscore_d
-2

Profiling menunjukkan pernyataan itu: std::copy()selalu secepat memcpy()atau lebih cepat salah.

Sistem saya:

HP-Compaq-dx7500-Microtower 3.13.0-24-generic # 47-Ubuntu SMP Jumat 2 Mei 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU / Linux.

gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

Kode (bahasa: c ++):

    const uint32_t arr_size = (1080 * 720 * 3); //HD image in rgb24
    const uint32_t iterations = 100000;
    uint8_t arr1[arr_size];
    uint8_t arr2[arr_size];
    std::vector<uint8_t> v;

    main(){
        {
            DPROFILE;
            memcpy(arr1, arr2, sizeof(arr1));
            printf("memcpy()\n");
        }

        v.reserve(sizeof(arr1));
        {
            DPROFILE;
            std::copy(arr1, arr1 + sizeof(arr1), v.begin());
            printf("std::copy()\n");
        }

        {
            time_t t = time(NULL);
            for(uint32_t i = 0; i < iterations; ++i)
                memcpy(arr1, arr2, sizeof(arr1));
            printf("memcpy()    elapsed %d s\n", time(NULL) - t);
        }

        {
            time_t t = time(NULL);
            for(uint32_t i = 0; i < iterations; ++i)
                std::copy(arr1, arr1 + sizeof(arr1), v.begin());
            printf("std::copy() elapsed %d s\n", time(NULL) - t);
        }
    }

g ++ -O0 -o test_stdcopy test_stdcopy.cpp

memcpy () profil: utama: 21: sekarang: 1422969084: 04859 terlewati: 2650 us
std :: salin () profil: utama: 27: sekarang: 1422969084: 04862 berlalu: 2745 us
memcpy () elapsed 44 s std :: copy ( ) berlalu 45 s

g ++ -O3 -o test_stdcopy test_stdcopy.cpp

memcpy () profil: utama: 21: sekarang: 1422969601: 04939 berlalu: 2385 us
std :: salin () profil: utama: 28: sekarang: 1422969601: 04941 berlalu: 2690 us
memcpy () elaped 27 s std :: copy ( ) berlalu 43 s

Red Alert menunjukkan bahwa kode tersebut menggunakan memcpy dari array ke array dan std :: copy dari array ke vektor. Itu bisa menjadi alasan untuk memcpy lebih cepat.

Karena ada

v.reserve (sizeof (arr1));

tidak akan ada perbedaan dalam salinan ke vektor atau array.

Kode diperbaiki untuk menggunakan array untuk kedua kasus. memcpy masih lebih cepat:

{
    time_t t = time(NULL);
    for(uint32_t i = 0; i < iterations; ++i)
        memcpy(arr1, arr2, sizeof(arr1));
    printf("memcpy()    elapsed %ld s\n", time(NULL) - t);
}

{
    time_t t = time(NULL);
    for(uint32_t i = 0; i < iterations; ++i)
        std::copy(arr1, arr1 + sizeof(arr1), arr2);
    printf("std::copy() elapsed %ld s\n", time(NULL) - t);
}

memcpy()    elapsed 44 s
std::copy() elapsed 48 s 
imatveev13
sumber
1
salah, profil Anda menunjukkan bahwa menyalin ke dalam array lebih cepat daripada menyalin ke dalam vektor. Menyimpang dari topik.
Peringatan Merah
Saya bisa saja salah, tetapi dalam contoh Anda yang dikoreksi, dengan memcpy, bukankah Anda menyalin arr2 ke arr1, sedangkan dengan std :: copy, Anda menyalin arr1 ke arr2? ... Apa yang bisa Anda lakukan adalah membuat banyak, berganti-ganti percobaan (sekali batch memcpy, sekali batch std :: copy, lalu kembali lagi dengan memcopy, dll., beberapa kali.). Kemudian, saya akan menggunakan clock () alih-alih waktu (), karena siapa yang tahu apa yang PC Anda bisa lakukan selain program itu. Hanya dua sen saya, meskipun ... :-)
paercebal
7
Jadi, beralih std::copydari vektor ke array entah bagaimana membuat memcpybutuh waktu hampir dua kali lebih lama? Data ini sangat mencurigakan. Saya mengkompilasi kode Anda menggunakan gcc dengan -O3, dan perakitan yang dihasilkan sama untuk kedua loop. Jadi setiap perbedaan waktu yang Anda amati pada mesin Anda hanya bersifat insidental.
Red Alert