পারফরম্যান্সের বিচারে std :: memcpy () বা std :: copy () ব্যবহার করা কি ভাল?


163

memcpyনীচের চিত্রের মতো ব্যবহার করা কি ভাল বা std::copy()পারফরম্যান্সের ক্ষেত্রে ব্যবহার করা ভাল ? কেন?

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]);

লক্ষ করুন যে charপ্রয়োগের উপর নির্ভর করে স্বাক্ষরিত বা স্বাক্ষরযুক্ত হতে পারে। যদি বাইটের সংখ্যা> = 128 হতে পারে তবে unsigned charআপনার বাইট অ্যারে ব্যবহার করুন । ( (int *)কাস্টটিও এর মতো নিরাপদ হবে (unsigned int *)))
ড্যান ব্রেস্লাউ

13
আপনি ব্যবহার করছেন না কেন std::vector<char>? অথবা যেহেতু আপনি বলতে bits, std::bitset?
GManNickG

2
আসলে, আপনি কি আমাকে দয়া করে ব্যাখ্যা করতে (int*) copyMe->bits[0]পারেন?
ব্যবহারকারী 3728501

4
নিশ্চিত নয় যে এত ছোট গুরুত্বপূর্ণ প্রসঙ্গ সহ এমন কোনও গোলমালের মতো মনে হচ্ছে এমন কেন +81 এ ছিল তবে ওহে। @ ব্যবহারকারী 37৩৮৮৫০১ আমার অনুমান যে বাফার শুরুটি intতার আকার নির্ধারণ করে তবে এটি এখানে অন্যান্য অনেক কিছুর মতো বাস্তবায়ন-সংজ্ঞায়িত বিপর্যয়ের একটি রেসিপি বলে মনে হয়।
আন্ডারস্কোর_২

2
আসলে, that (int *)ালাই কেবল খাঁটি অপরিজ্ঞাত আচরণ, বাস্তবায়ন-সংজ্ঞায়িত নয়। কোনও কাস্টের মাধ্যমে টাইপ-পানিং করার চেষ্টা করা কঠোরভাবে নিয়মিত নিয়ম লঙ্ঘন করে এবং তাই স্ট্যান্ডার্ড দ্বারা একেবারে অপরিজ্ঞাত। (এছাড়াও, সি ++ তে যদিও সি নয়, আপনি কোনওটির মাধ্যমেই টাইপ-পুং করতে পারবেন না union)) আপনি খুব বেশি ব্যতিক্রম হ'ল তবে আপনি যদি কোনও রূপান্তরিত হনchar* তবে ভাতাটি প্রতিসম নয় is
আন্ডারস্কোর_১

উত্তর:


207

আমি এখানে সাধারণ জ্ঞানের বিরুদ্ধে যাচ্ছি যে এতে std::copyসামান্য, প্রায় দুর্ভেদ্য পারফরম্যান্স ক্ষতি হবে। আমি কেবল একটি পরীক্ষা করেছি এবং এটি অসত্য বলে মনে করেছি: আমি একটি পারফরম্যান্সের পার্থক্য লক্ষ্য করেছি। তবে, বিজয়ী ছিল std::copy

আমি একটি সি ++ এসএইচএ -2 বাস্তবায়ন লিখেছি। আমার পরীক্ষায়, আমি চারটি SHA-2 সংস্করণ (224, 256, 384, 512) ব্যবহার করে 5 টি স্ট্রিং করেছি এবং আমি 300 বার লুপ করেছি। আমি বুস্ট.টিমার ব্যবহারের সময়গুলি পরিমাপ করি। 300 টি লুপের কাউন্টারটি আমার ফলাফলগুলি পুরোপুরি স্থিতিশীল করতে যথেষ্ট। আমি প্রতিবার 5 বার পরীক্ষা চালিয়েছি, memcpyসংস্করণ এবং std::copyসংস্করণে একসাথে ঘুরছি। আমার কোড সম্ভব (অন্যান্য অনেক বাস্তবায়নের যেমন খন্ডে বৃহৎ যেমন ডাটা দখল সুবিধা নেয় চালিত char/ char *, আমি সঙ্গে কাজ যেহেতু T/ T *(যেখানে Tব্যবহারকারীর বাস্তবায়ন সর্ববৃহৎ টাইপ সঠিক ওভারফ্লো আচরণ নেই) যে, উপর এত দ্রুত মেমরি অ্যাক্সেস সবচেয়ে বড় ধরণের যা আমি করতে পারি তা আমার অ্যালগোরিদমের পারফরম্যান্সের কেন্দ্রীয় is এগুলি আমার ফলাফল:

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%

স্টাডির গতিতে মোট গড় বৃদ্ধি: মেমকপির উপর অনুলিপি: ২.৯৯%

আমার সংকলক ফেডোরা 16 x86_64 এ জিসিসি 4.6.3। আমার অপটিমাইজেশন পতাকাগুলি -Ofast -march=native -funsafe-loop-optimizations

আমার SHA-2 বাস্তবায়নের জন্য কোড।

আমি আমার এমডি 5 বাস্তবায়ন সম্পর্কেও একটি পরীক্ষা চালানোর সিদ্ধান্ত নিয়েছি। ফলাফলগুলি খুব কম স্থিতিশীল ছিল, তাই আমি 10 রান করার সিদ্ধান্ত নিয়েছিলাম। যাইহোক, আমার প্রথম কয়েকটি চেষ্টার পরে, আমি এমন ফলাফল পেয়েছি যা এক রান থেকে শুরু করে পরের দফায় দুরকমভাবে পরিবর্তিত হয়েছিল, তাই আমি অনুমান করছি যে সেখানে কোনও ধরণের ওএস ক্রিয়াকলাপ চলছে। আমি আবার শুরু করার সিদ্ধান্ত নিয়েছে।

একই সংকলক সেটিংস এবং পতাকা। এমডি 5 এর কেবল একটি সংস্করণ রয়েছে এবং এটি SHA-2 এর চেয়েও দ্রুত, সুতরাং আমি 5 টি পরীক্ষার স্ট্রিংয়ের অনুরূপ সেটটিতে 3000 লুপ করেছি।

এগুলি আমার চূড়ান্ত 10 ফলাফল:

এমডি 5 পরীক্ষা চালানোর জন্য সময় (সেকেন্ডে)

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%

স্টাডির গতিতে মোট গড় হ্রাস :: মেমকপির উপর অনুলিপি: 0.11%

আমার এমডি 5 বাস্তবায়নের জন্য কোড

এই ফলাফলগুলির মধ্যে এমন কিছু অপ্টিমাইজেশন রয়েছে যা আমার এসএডিএ -২ টেস্টে স্ট্যান্ডার্ড :: অনুলিপি ব্যবহার করা হয়েছে যা std::copyআমার এমডি 5 পরীক্ষায় ব্যবহার করতে পারেনি। রয়েছে SHA-2 পরীক্ষা এ উভয় অ্যারে যে বলা একই ফাংশন এ তৈরি হওয়া std::copy/ memcpy। আমার এমডি 5 পরীক্ষায়, অ্যারেগুলির মধ্যে একটি ফাংশন প্যারামিটার হিসাবে ফাংশনে স্থানান্তরিত হয়েছিল।

আমি std::copyআবার দ্রুত তৈরি করতে কী করতে পারি তা দেখার জন্য আমি আরও কিছুটা পরীক্ষা করেছি । উত্তরটি সরল হয়ে উঠল: লিঙ্ক টাইম অপ্টিমাইজেশন চালু করুন। এলটিও চালু হওয়ার সাথে সাথে আমার ফলাফলগুলি (বিকল্পটি জিসিসি-তে ফ্লোটে):

-ফ্ল্টো সহ এমডি 5 পরীক্ষা চালানোর জন্য সময় (সেকেন্ডে)

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%

স্টাডির গতিতে মোট গড় বৃদ্ধি: মেমকপির উপর অনুলিপি: 0.72%

সংক্ষেপে, ব্যবহারের জন্য পারফরম্যান্স জরিমানা বলে মনে হয় না std::copy। আসলে, সেখানে একটি পারফরম্যান্স লাভ বলে মনে হচ্ছে।

ফলাফল ব্যাখ্যা

সুতরাং কেন std::copyএকটি পারফরম্যান্স উত্সাহ দিতে পারে ?

প্রথমত, আমি যতক্ষণ ইনলাইনিংয়ের অপ্টিমাইজেশন চালু না করা হয় এটি কোনও বাস্তবায়নের জন্য ধীর হয়ে যাওয়ার আশা করব না। সমস্ত সংকলক আগ্রাসীভাবে ইনলাইন করুন; এটি সম্ভবত সর্বাধিক গুরুত্বপূর্ণ অপ্টিমাইজেশন কারণ এটি অন্যান্য অনেকগুলি অনুকূলিতকরণ সক্ষম করে। std::copy(এবং আমি সমস্ত বাস্তব বিশ্বের বাস্তবায়নগুলি সন্দেহ করি) সনাক্ত করতে পারে যে আর্গুমেন্টগুলি তুচ্ছভাবে অনুলিপিযোগ্য এবং সেই মেমরিটি ক্রমান্বয়ে ছড়িয়ে দেওয়া হয়েছে। এর অর্থ হ'ল সবচেয়ে খারাপ ক্ষেত্রে যখন memcpyআইনী হয় তখন খারাপ আচরণ করা std::copyউচিত নয়। এই সংলাপগুলির তুচ্ছ বাস্তবায়নটি "গতি বা আকারের জন্য অনুকূলকরণ করার সময় সর্বদা এটির সাথে ইনলাইন করুন" এর std::copyসংকলনের memcpyমানদণ্ডটি পূরণ করা উচিত।

তবে এর std::copyআরও তথ্য রাখে। আপনি যখন কল করবেন তখন std::copyফাংশনটি ধরণের অক্ষত রাখে। memcpyপরিচালিত হয় void *, যা প্রায় সমস্ত দরকারী তথ্য বাতিল করে দেয়। উদাহরণস্বরূপ, আমি যদি একটি অ্যারে পাস করি std::uint64_tতবে সংকলক বা লাইব্রেরি প্রয়োগকারী তার সাথে -৪-বিট প্রান্তিককরণের সুবিধা নিতে সক্ষম হতে পারে std::copyতবে এটি করা আরও কঠিন হতে পারে memcpy। প্রথমে সীমার শুরুতে স্বাক্ষরবিহীন অংশে, তারপরে প্রান্তিককরণ অংশ, তারপরে শেষে স্বাক্ষরবিহীন অংশটিতে কাজ করে এই কাজের মতো অ্যালগরিদমের অনেকগুলি বাস্তবায়ন। যদি এটি সমস্ত প্রান্তিককরণের গ্যারান্টিযুক্ত হয়, তবে কোডটি আপনার প্রসেসরে থাকা শাখার ভবিষ্যদ্বাণীকের সঠিক হওয়ার পক্ষে কোডটি আরও সহজ এবং দ্রুততর হয়।

অকাল অপটিমাইজেশন?

std::copyএকটি আকর্ষণীয় অবস্থানে আছে। আমি প্রত্যাশা করি যে এটি memcpyকোনও আধুনিক অপ্টিমাইজ করা সংকলকটির চেয়ে কখনও ধীর এবং কখনও কখনও দ্রুত হবে না । তদুপরি, আপনি যা কিছু করতে পারেন memcpy, আপনি পারেন std::copymemcpyবাফারগুলিতে কোনও ওভারল্যাপের অনুমতি দেয় না, যেখানে std::copyএকদিকে ওভারল্যাপ সমর্থন করে ( std::copy_backwardওভারল্যাপের অন্য দিকের সাথে)। memcpyশুধুমাত্র পয়েন্টার উপর কাজ করে std::copyকোনো iterators উপর কাজ করে ( std::map, std::vector, std::deque, অথবা আমার নিজস্ব টাইপ)। অন্য কথায়, std::copyযখন আপনার চারপাশের উপাত্তগুলি অনুলিপি করার প্রয়োজন হয় তখনই আপনার ব্যবহার করা উচিত ।


35
আমি জোর দিয়ে বলতে চাই যে এর অর্থ এই নয় যে std::copyএটি 2.99% বা 0.72% বা -0.11% এর চেয়ে দ্রুত memcpy, পুরো সময়টি পুরো প্রোগ্রামটি কার্যকর করার জন্য। তবে আমি সাধারণত অনুভব করি যে জাল কোডের মানদণ্ডের চেয়ে বাস্তব কোডে থাকা মানদণ্ডগুলি বেশি কার্যকর। আমার পুরো প্রোগ্রামটি কার্যকর হয়েছে গতিতে change কেবল দুটি অনুলিপি স্কিমের প্রকৃত প্রভাবগুলি এখানে বিচ্ছিন্নতার সাথে দেখানোর চেয়ে বেশি পার্থক্য থাকতে পারে, তবে এটি দেখায় যে তাদের প্রকৃত কোডে পরিমাপযোগ্য পার্থক্য থাকতে পারে।
ডেভিড স্টোন

2
আমি আপনার অনুসন্ধানগুলির সাথে একমত হতে চাই, তবে ফলাফলগুলি ফলাফল: /। তবে একটি প্রশ্ন (আমি জানি এটি অনেক দিন আগে ছিল এবং আপনি গবেষণাটি মনে রাখেন না, সুতরাং আপনার ভাবনার মত করে মন্তব্য করুন), আপনি সম্ভবত সমাবেশ কোডটি সন্ধান করেন নি;
এসটি 3

2
আমার মতে memcpyএবং std::copyবিভিন্ন বাস্তবায়ন রয়েছে, তাই কিছু ক্ষেত্রে সংকলক আশেপাশের কোড এবং প্রকৃত মেমরির অনুলিপি কোডটিকে কোডের এক এক অবিচ্ছেদ্য অংশ হিসাবে অনুকূল করে তোলে। এটি অন্য কথায় কখনও কখনও একের পরে অন্যটি এমনকি অন্য কথায়, কোনটি ব্যবহার করা উচিত তা অকাল বা এমনকি নির্বোধ অপ্টিমাইজেশনের সিদ্ধান্ত নেওয়া কারণ প্রতিটি পরিস্থিতিতে আপনাকে নতুন গবেষণা করতে হবে এবং আরও বেশি কী, প্রোগ্রামগুলি সাধারণত বিকাশমান হয়, তাই পরে অন্যের তুলনায় কিছু সামান্য পরিবর্তনগুলির কার্যকারিতা হারাতে পারে।
এসটি 3

3
@ এসটি 3: আমি কল্পনা করব যে সবচেয়ে খারাপ ক্ষেত্রে, std::copyএটি একটি তুচ্ছ ইনলাইন ফাংশন যা memcpyআইনী হলে কেবল কল করে । বেসিক ইনলাইনিং যে কোনও নেতিবাচক পারফরম্যান্সের পার্থক্য দূর করবে। আমি কেন std :: অনুলিপি দ্রুত হতে পারে তার কিছুটা ব্যাখ্যা দিয়ে পোস্টটি আপডেট করব।
ডেভিড স্টোন 2

7
খুব তথ্যপূর্ণ বিশ্লেষণ। পুনরায় এসটিডি গতি মোট গড় হ্রাস :: আমার মনে সময় অনুলিপি: 0.11% , যখন নম্বরটি সঠিক, ফলাফল পরিসংখ্যানগত ভাবে উল্লেখযোগ্য নয়। পার্থক্যের জন্য 95% আত্মবিশ্বাসের ব্যবধানটি হল (-0.013s, 0.025), যার মধ্যে শূন্য রয়েছে। আপনি যেমন উল্লেখ করেছেন যে অন্যান্য উত্স থেকে এবং আপনার ডেটার সাথে তারতম্য রয়েছে, আপনি সম্ভবত বলবেন যে পারফরম্যান্সটি একই। রেফারেন্সের জন্য, অন্য দুটি ফলাফল পরিসংখ্যানগতভাবে তাৎপর্যপূর্ণ - আপনি এই চরম সময়ের মধ্যে যে সম্ভাবনাগুলি খুব কম সময়ে দেখতে পেলেন তা হ'ল 100 মিলিয়ন (প্রথম) এবং 1 হাজার 20,000 (শেষ) 1
টুটোনে

78

আমার জানা সমস্ত সংকলক একটি সরলটিকে যখন এটি উপযুক্ত, বা আরও ভাল, এর std::copyসাথে প্রতিস্থাপন করবে তবে memcpyএটি অনুলিপিটির চেয়ে আরও দ্রুততর হবে memcpy

যে কোনও ক্ষেত্রে: প্রোফাইল এবং নিজেকে খুঁজে বার করুন। বিভিন্ন সংকলক বিভিন্ন কাজ করবে এবং এটি বেশ সম্ভব যা আপনি যা চান ঠিক তা করেন না।

সংকলক অপটিমাইজেশন (পিডিএফ) এ এই উপস্থাপনাটি দেখুন ।

একটি জিওডিসিপি একটি সাধারণ পিওডি ধরণের জন্য কী করে তা এখানে std::copy

#include <algorithm>

struct foo
{
  int x, y;    
};

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

এখানে বিচ্ছিন্নতা (কেবলমাত্র -Oঅনুকূলকরণের সাথে) এখানে কলটি দেখানো হয়েছে 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

আপনি যদি ফাংশনের স্বাক্ষরটিতে পরিবর্তন করেন

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

তারপরে সামান্য পারফরম্যান্সের উন্নতির জন্য এটি memmoveহয়ে ওঠে memcpy। নোট করুন যে memcpyনিজেই ভারী ভেক্টরাইজড হবে।


1
আমি কীভাবে প্রোফাইলিং করতে পারি। কোন সরঞ্জামটি ব্যবহার করতে হবে (উইন্ডোজ এবং লিনাক্সে)?
user576670

5
@ কনরাড, আপনি ঠিক বলেছেন। তবে memmoveদ্রুত হওয়া উচিত নয় - বরং এটি হালকা ধীর হওয়া উচিত কারণ এটি দুটি ডেটার রেঞ্জের ওভারল্যাপ হওয়ার সম্ভাবনাটি বিবেচনায় নিতে হবে। আমি মনে করি যে std::copyওভারল্যাপিং ডেটা অনুমতি দেয় এবং তাই এটি কল করতে হবে memmove
চার্লস সালভিয়া

2
@ কনরাড: যদি মেমোমোভ সবসময় মেমকপির চেয়ে দ্রুত ছিল তবে মেমকি মেমোমোভকে কল করবে। কী স্ট্যান্ড :: কপি আসলে প্রেরণ-সংজ্ঞায়িত (যদি কিছু থাকে) প্রেরণ করতে পারে, তাই প্রয়োগের উল্লেখ না করে সুনির্দিষ্ট উল্লেখ করা কার্যকর নয়।
ফ্রেড নূরক

1
যদিও, এই আচরণ পুনরুত্পাদন করার একটি সহজ প্রোগ্রাম, জিসিসির আওতায় -O3 দিয়ে সংকলিত আমাকে একটি দেখায় memcpy। এটি আমাকে বিশ্বাস করতে পরিচালিত করে জিসিসি চেক করে মেমরির ওভারল্যাপ রয়েছে কিনা।
jweyrich

1
@ কনরাড: স্ট্যান্ডার্ডটি একদিকে std::copyওভারল্যাপ করতে দেয় তবে অন্যদিকে নয়। আউটপুটের শুরুটি ইনপুট সীমার মধ্যে থাকা যায় না, তবে ইনপুটটির শুরুটি আউটপুট সীমার মধ্যে থাকা যায়। এটি কিছুটা অদ্ভুত, কারণ অ্যাসাইনমেন্টের ক্রম সংজ্ঞায়িত করা হয়েছে এবং সেই আদেশগুলির ক্রম অনুযায়ী এই কার্যগুলির কার্যকারিতা সংজ্ঞায়িত হলেও কল একটি ইউবি হতে পারে। তবে আমি মনে করি এই সীমাবদ্ধতা ভেক্টরাইজেশন অপ্টিমাইজেশনের অনুমতি দেয় allows
স্টিভ জেসোপ

24

সর্বদা ব্যবহার std::copyকারণ memcpyশুধুমাত্র সি-শৈলী POD কাঠামো সীমাবদ্ধ করা হয়, এবং কম্পাইলার সম্ভবত কল প্রতিস্থাপন করবে std::copyসঙ্গে memcpyযদি লক্ষ্যমাত্রা আসলে শুঁটি হয়।

প্লাস, std::copyকেবলমাত্র পয়েন্টার নয়, বহু পুনরাবৃত্তকারী প্রকারের সাথে ব্যবহার করা যেতে পারে। std::copyকোনও পারফরম্যান্স ক্ষতির জন্য আরও নমনীয় এবং স্পষ্ট বিজয়ী।


আপনার পুনরাবৃত্তকারীদের কেন অনুলিপি করা উচিত?
Atmocreations

3
আপনি পুনরাবৃত্তিকারীদের অনুলিপি করছেন না, বরং দুটি পুনরুক্তি দ্বারা সংজ্ঞায়িত পরিসীমা। উদাহরণস্বরূপ, (এর মধ্যকার সবকিছু) এর std::copy(container.begin(), container.end(), destination);সামগ্রীগুলি অনুলিপি করবেcontainerbeginend নির্দেশিত বাফারে এবং এর )destinationstd::copyশেনানিগানদের মতো &*container.begin()বা দরকার নেই &container.back() + 1
ডেভিড স্টোন

16

ধারণায়, memcpyএকটি থাকতে পারে অসম্মান , অপ্রত্যক্ষ , ইনফিনিটসিমাল কর্মক্ষমতা সুবিধা, শুধুমাত্র কারণ এটি হিসাবে একই প্রয়োজনীয়তা নেই std::copy। ম্যান পৃষ্ঠা থেকে memcpy:

ওভারফ্লো এড়াতে, গন্তব্য এবং উত্স পরামিতি উভয় দ্বারা নির্দেশিত অ্যারেগুলির আকার কমপক্ষে নম্বরের বাইট হতে হবে এবং ওভারল্যাপ করা উচিত নয় (মেমরি ব্লককে ওভারল্যাপ করার জন্য, মেমোমোভ একটি নিরাপদ পদ্ধতির)।

অন্য কথায়, memcpyওভারল্যাপিং ডেটার সম্ভাবনা উপেক্ষা করতে পারে। (ওভারল্যাপিং অ্যারে এতে পাস করা অপরিজ্ঞাত memcpyআচরণ।) সুতরাং memcpyস্পষ্টভাবে এই শর্তটি পরীক্ষা করার দরকার নেই, যেখানে প্যারামিটার উত্সের সীমাতে না থাকলে std::copyততক্ষণ ব্যবহার করা যেতে পারে OutputIterator। দ্রষ্টব্য এটি বলার মতো নয় যে উত্সের সীমা এবং গন্তব্য সীমার ওভারল্যাপ করতে পারে না।

সুতরাং যেহেতু std::copyকিছুটা আলাদা প্রয়োজনীয়তা আছে, তত্ত্ব এটি হওয়া উচিত সামান্য (চালু একটি চরম জোর দিয়ে সামান্য ধীর), যেহেতু এটি সম্ভবত ওভারল্যাপিং সি-অ্যারে জন্য চেক করবে, বা অন্য করতে সি-অ্যারে অনুলিপি প্রতিনিধি memmove, যা সঞ্চালন প্রয়োজন চেক করুন। তবে অনুশীলনে, আপনি (এবং বেশিরভাগ প্রোফাইলার) সম্ভবত কোনও পার্থক্য সনাক্ত করতে পারবেন না।

অবশ্যই, যদি আপনি পিওডিদের সাথে কাজ না করে থাকেন যেভাবেই ব্যবহার করতে পারবেন নাmemcpy


7
এই জন্য সত্য std::copy<char>। তবে std::copy<int>ধরে নিতে পারে যে এর ইনপুটগুলি আন্তঃসংযুক্ত রয়েছে। এটি একটি আরও বড় পার্থক্য তৈরি করবে, কারণ এটি প্রতিটি উপাদানকে প্রভাবিত করে। ওভারল্যাপ হ'ল এককালীন চেক।
এমসাল্টারস 17:38

2
@ এসএমএল্টারস, সত্য, তবে বেশিরভাগ বাস্তবায়ন memcpyআমি বাইট বাই না করে সারিবদ্ধকরণ এবং শব্দগুলি অনুলিপি করার চেষ্টা দেখেছি।
চার্লস সালভিয়া

1
std :: copy () ওভারল্যাপিং মেমরিটিকেও এড়িয়ে যেতে পারে। আপনি যদি ওভারল্যাপিং মেমোরিটিকে সমর্থন করতে চান, তবে উপযুক্ত পরিস্থিতিতে স্ট্যান্ড :: রিভার্স_কপি () কল করতে নিজেকে যুক্তিটি লিখতে হবে।
সাইগন

2
একটি বিপরীত যুক্তি রয়েছে যা তৈরি করা যায়: memcpyইন্টারফেসের মধ্য দিয়ে যাওয়ার সময় এটি প্রান্তিককরণের তথ্য হারাতে থাকে। অতএব, memcpyস্বাক্ষরবিহীন সূচনা এবং শেষগুলি পরিচালনা করতে রান-টাইমে প্রান্তিককরণের পরীক্ষা করতে হবে। এই চেকগুলি সস্তা হতে পারে তবে তারা নিখরচায় নয়। যেখানে std::copyএই চেকগুলি এড়াতে এবং ভেক্টরাইজ করতে পারে। এছাড়াও, সংকলক প্রমাণ করতে পারে যে উত্স এবং গন্তব্য অ্যারেগুলি ওভারল্যাপ হয় না এবং আবার ব্যবহারকারীকে memcpyএবং এর মধ্যে নির্বাচন না করে ভেক্টরাইজ করে না memmove
ম্যাক্সিম এগারুশকিন

11

আমার নিয়ম সহজ। আপনি যদি সি ++ ব্যবহার করেন তবে সি ++ লাইব্রেরি পছন্দ করবেন এবং সি নয় :)


40
সি লাইব্রেরি ব্যবহারের অনুমতি দেওয়ার জন্য সি ++ স্পষ্টভাবে তৈরি করা হয়েছিল। এটি কোনও দুর্ঘটনা ছিল না। সি ++ তে মেম্পপির চেয়ে স্ট্যান্ড :: কপি ব্যবহার করা প্রায়শই ভাল, তবে এটি কোন সি, এর সাথে কোনও সম্পর্ক নেই এবং এই ধরণের যুক্তি সাধারণত ভুল পদ্ধতির হয়।
ফ্রেড নূরক

2
@ ফ্রেডনার্ক সাধারণত আপনি সি এর দুর্বল অঞ্চল এড়াতে চান যেখানে সি ++ একটি নিরাপদ বিকল্প সরবরাহ করে।
ফিল 1970

@ ফিল 1970 আমি নিশ্চিত না যে সি ++ এই ক্ষেত্রে অনেক বেশি নিরাপদ is আমাদের এখনও বৈধ পুনরাবৃত্তকারীগুলি পাস করতে হবে যা ওভাররন হয় না, ইত্যাদি I আমি অনুমান করি যে এটির std::end(c_arr)পরিবর্তে আপনি ব্যবহার করতে সক্ষম হবেন c_arr + i_hope_this_is_the_right_number_of elementsকি? এবং সম্ভবত আরও গুরুত্বপূর্ণ, পরিষ্কার। এবং এই নির্দিষ্ট ক্ষেত্রে আমি যে বিষয়টিটির উপরে জোর দিয়েছি std::copy()তা হ'ল : যদি পুনরাবৃত্তির ধরণগুলি পরে পরিবর্তন হয়, পরিষ্কার বাক্য গঠন ইত্যাদির দিকে পরিচালিত করে তবে আরও বুদ্ধিমান, আরও রক্ষণাবেক্ষণযোগ্য
আন্ডারস্কোর_১

1
@ মাংসকো_ডি std::copyনিরাপদ কারণ এটি পাসের ডেটাগুলি পিওডি-প্রকারের না হলে সঠিকভাবে অনুলিপি করে। memcpyআনন্দের সাথে std::stringবাইট দ্বারা একটি নতুন উপস্থাপনা বাইটে কোনও বস্তু অনুলিপি করবে ।
জেনস

3

শুধু একটি ছোটখাট উপরন্তু: মধ্যে গতি পার্থক্য memcpy()এবং std::copy()যদি অপ্টিমাইজেশন সক্ষম অথবা অক্ষম হয় উপর নির্ভর করে বেশ একটু পরিবর্তিত হতে পারে। জি ++ .2.২.০ সহ এবং অপ্টিমাইজেশান ছাড়াই memcpy()স্পষ্টভাবে বিজয়ী হয়:

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

যখন অপ্টিমাইজেশন সক্ষম করা থাকে ( -O3), তখন সমস্ত কিছু আবার একই রকম দেখা যায়:

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

প্রভাবটি যত কম অ্যারে N=1000 memcpy()তত কম লক্ষণীয় হয় তবে অপটিমাইজেশন সক্ষম না করা অবস্থায় প্রায় দ্বিগুণ দ্রুত হয়।

উত্স কোড (গুগল বেনমার্ক প্রয়োজন):

#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 */

18
অপ্টিমাইজেশানগুলি সহ পারফরম্যান্স পরিমাপ করা হ'ল ... ভাল ... বেশ অর্থহীন ... আপনি যদি পারফরম্যান্সে আগ্রহী হন তবে অপটিমাইজেশন ছাড়াই সংকলন করবেন না।
বলভ

3
@ বলভ সবসময় না ডিবাগের অধীনে তুলনামূলক দ্রুত প্রোগ্রাম হ'ল কিছু ক্ষেত্রে গুরুত্বপূর্ণ।
আকোর

2

আপনার যদি সত্যিই সর্বাধিক অনুলিপি সম্পাদনা প্রয়োজন হয় (যা আপনি নাও করতে পারেন) তবে সেগুলির দুটিই ব্যবহার করবেন না

একটা ব্যাপার অনেক এটির জন্য / কোর আপনি একাধিক থ্রেড ব্যবহার করতে চলেছেন ইচ্ছুক যদি আরও বেশি - যে অপ্টিমাইজ মেমরির কপি করার করা যাবে। উদাহরণস্বরূপ দেখুন:

এই মেমকিটি বাস্তবায়নে কী অনুপস্থিত / উপ-অনুকূল?

প্রশ্ন এবং উত্তর দুটিই বাস্তবায়ন বা বাস্তবায়নের লিঙ্কগুলির পরামর্শ দিয়েছে।


4
প্যাডেন্ট মোড: "যথাযথভাবে এগুলির উভয়ই ব্যবহার করবেন না " এর অর্থ হ'ল যদি আপনার যদি প্রমাণ হয়ে যায় যে আপনার একটি অত্যন্ত নির্দিষ্ট পরিস্থিতি / প্রয়োজনীয়তা রয়েছে যার জন্য আপনার বাস্তবায়ন দ্বারা সরবরাহিত স্ট্যান্ডার্ড ফাংশনও যথেষ্ট দ্রুত নয় ; অন্যথায়, আমার স্বাভাবিক উদ্বেগ হ'ল যে ব্যক্তিরা তাদের প্রোগ্রামের সাধারণত আরও দরকারী অংশগুলির পরিবর্তে অকালপূর্বক অনুলিপি কোডটি অনুকূলিতকরণের পক্ষে প্রমাণিত হন নি id
আন্ডারস্কোর_

-2

প্রোফাইলিং সেই বিবৃতিটি দেখায়: std::copy()সর্বদা তত দ্রুত memcpy()বা তত দ্রুত মিথ্যা।

আমার সিস্টেম:

এইচপি-কমপ্যাক-ডিএক্স 7500-মাইক্রোটওয়ার 3.13.0-24-জেনেরিক # 47-উবুন্টু এসএমপি শুক্র 2 মে 23:30:00 ইউটিসি 2014 x86_64 x86_64 x86_64 জিএনইউ / লিনাক্স।

জিসিসি (উবুন্টু 4.8.2-19ubuntu1) 4.8.2

কোড (ভাষা: সি ++):

    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 () প্রোফাইল: মূল: 21: এখন: 1422969084: 04859 অতিবাহিত: 2650 usd
std :: copy () প্রোফাইল: মূল: 27: এখন: 1422969084: 04862 বিস্তৃত: 2745 us
memcpy () elapsed 44 s std :: copy (copy) ) 45 পেরিয়ে গেছে

g ++ -O3 -o test_stdcopy test_stdcopy.cpp

memcpy () প্রোফাইল: মূল: 21: এখন: 1422969601: 04939 অতিবাহিত: 2385 us
std :: অনুলিপি () প্রোফাইল: প্রধান: 28: এখন: 1422969601: 04941 অতিবাহিত: 2690 us
memcpy () কেটে গেছে 27 টি স্ট্যান্ড :: কপি ( ) অতিবাহিত হয়েছে 43 টি

রেড সতর্কতা নির্দেশ করে যে কোডটি অ্যারে থেকে অ্যারেতে মেকপি ব্যবহার করে এবং std :: অ্যারে থেকে ভেক্টরে অনুলিপি করে। এটি দ্রুত মেমকপির জন্য কারণ হতে পারে d

যেহেতু আছে

v.reserve (যাও sizeof (arr1));

ভেক্টর বা অ্যারেতে অনুলিপির কোনও পার্থক্য থাকবে না।

কোড উভয় ক্ষেত্রে অ্যারে ব্যবহারের জন্য স্থির করা হয়েছে। ম্যাকপি এখনও দ্রুত:

{
    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 

1
ভুল, আপনার প্রোফাইলটি দেখায় যে একটি অ্যারেতে অনুলিপি করা একটি ভেক্টরে অনুলিপি করার চেয়ে দ্রুত। অন্য প্রসঙ্গ.
রেড সতর্কতা

আমি ভুল হতে পারি, তবে আপনার সংশোধনযোগ্য উদাহরণে, মেমকিপি সহ, আপনি কি আরআর 2 টি আরআর 1 এ অনুলিপি করছেন না, যখন স্টাড :: অনুলিপি সহ, আপনি আর্ট 1 এ আর 2 তে অনুলিপি করছেন? ... আপনি যা করতে পারছেন তা হল একাধিক বিকল্প তৈরি করা, পরীক্ষা-নিরীক্ষা (একবার ম্য্যাম্পির এক ব্যাচ, একবার স্টাড :: কপি, তারপর আবার মেমকোপি ইত্যাদি নিয়ে একাধিকবার ফিরে আসবে)) তারপরে, আমি সময় () এর পরিবর্তে ঘড়ির () ব্যবহার করব, কারণ আপনার প্রোগ্রামটি ছাড়াও আপনার পিসি কী করতে পারে তা কে জানে। কেবল আমার দুটি সেন্ট, যদিও ... :-)
প্যারাসেবল

7
সুতরাং, std::copyকোনও ভেক্টর থেকে কোনও অ্যারেতে স্যুইচ করা কোনওভাবে memcpyপ্রায় দ্বিগুণ সময় নেয়? এই তথ্যটি অত্যন্ত সন্দেহজনক। আমি আপনার কোডটি জিওসি ব্যবহার করে -O3 দিয়ে সংকলন করেছি এবং উত্পন্ন সমাবেশটি উভয় লুপের জন্য একই। সুতরাং আপনি আপনার মেশিনে পর্যবেক্ষণ সময়ে কোনও পার্থক্য কেবল ঘটনাবহুল।
রেড সতর্কতা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.