মেমকি () এবং মেমমোভ () পয়েন্টার ইনক্রিমেন্টের চেয়ে দ্রুত কেন?


92

আমি কপি করছি N থেকে বাইট pSrcথেকে pDest। এটি একটি একক লুপে করা যেতে পারে:

for (int i = 0; i < N; i++)
    *pDest++ = *pSrc++

কেন এই তুলনায় ধীর হয় memcpyবা memmove? এটির গতি বাড়ানোর জন্য তারা কোন কৌশল ব্যবহার করে?


4
আপনার লুপটি কেবলমাত্র একটি অবস্থান অনুলিপি করে। আমি মনে করি আপনি কোনওভাবে পয়েন্টারগুলিকে বৃদ্ধি করতে চেয়েছিলেন।
রহস্যময়

13
বা, আপনি কেবল তাদের জন্য এটি ঠিক করতে পারেন, যেমন আমি করেছি। এবং, BTW, কোন সত্য সি প্রোগ্রামার কি কখনো থেকে গন্য 1করার N, এটা সবসময় থেকে 0থেকে N-1:-)
paxdiablo

6
@ প্যাক্সিডিয়াবলো: আপনি যদি অ্যারেগুলি লুপ করছেন তবে নিশ্চিত। তবে এমন অনেকগুলি কেস রয়েছে যেখানে 1 থেকে N পর্যন্ত লুপিং করা ঠিক আছে। আপনি ডেটা দিয়ে কী করছেন তার উপর নির্ভর করে - আপনি যদি 1 থেকে শুরু করে একটি সংখ্যাযুক্ত তালিকা প্রদর্শন করেন, উদাহরণস্বরূপ, কোনও ব্যবহারকারীর কাছে, তবে 1 থেকে শুরু করা সম্ভবত আরও অর্থবোধ করে। যাই হোক না কেন, এটি কোনও বড় সমস্যাটিকে উপেক্ষা করে যে intকাউন্টার হিসাবে ব্যবহার করা হয় যখন size_tপরিবর্তে একটি স্বাক্ষরবিহীন ধরণের ব্যবহার করা উচিত।
বিলি ওনিল

4
@ প্যাক্সিডিয়াবলো আপনি এন থেকে শুরু করে 1 পর্যন্তও গণনা করতে পারেন কিছু প্রসেসরের ক্ষেত্রে যে কোনও তুলনামূলক নির্দেশকে হ্রাস করবে কারণ হ্রাস শূন্যের দিকে পৌঁছলে শাখার নির্দেশের জন্য উপযুক্ত বিট সেট করবে।
একমাসে

6
আমি মনে করি প্রশ্নের ভিত্তিটি মিথ্যা। আধুনিক সংকলকরা এটিকে রূপান্তর করবে memcpyবা memmove(পয়েন্টারগুলি উপনাম হতে পারে কিনা তা তারা বলতে পারে কিনা তার উপর নির্ভর করে)
ডেভিড শোয়ার্টজ

উত্তর:


120

যেহেতু মেমকিপি বাইট পয়েন্টারগুলির পরিবর্তে শব্দ পয়েন্টার ব্যবহার করে, এছাড়াও মেমকি অ্যাপ্লিকেশনগুলি প্রায়শই সিমডের নির্দেশাবলী দ্বারা লিখিত হয় যা একসাথে 128 বিট স্থানান্তরিত করে তোলে।

সিমডি নির্দেশাবলী হ'ল সমাবেশ নির্দেশাবলী যা ভেক্টরে প্রতিটি উপাদানগুলিতে 16 বাইট দীর্ঘ দীর্ঘ ক্রিয়াকলাপ করতে পারে। এর মধ্যে লোড এবং স্টোর নির্দেশাবলী অন্তর্ভুক্ত।


15
আপনি যখন জিসিসি চালু করেন -O3, এটি লুপের জন্য সিমডি ব্যবহার করবে, যদি না জানা থাকে pDestএবং তার pSrcনাম না রাখে।
ডায়েটারিচ এপ্পি

আমি বর্তমানে by৪ বাইট (৫১২ বিট) সিমডি সহ একটি জিওন ফি-তে কাজ করছি, সুতরাং "16 বাইট অব" এর এই জিনিসটি আমাকে হাসায় makes এছাড়াও, সিমড সক্ষম করার জন্য আপনি কোন সিপিইউ টার্গেট করছেন তা অবশ্যই উল্লেখ করতে হবে, উদাহরণস্বরূপ -মার্চ = নেটিভ দিয়ে with
ইয়াকুডবজ

হয়তো আমার উত্তরটি সংশোধন করা উচিত। :)
একমাসে

এটি পোস্ট করার সময় এমনকি অত্যন্ত পুরানো। X86 এ অ্যাভিএক্স ভেক্টরগুলি (২০১১ এ প্রেরণ করা হয়েছে) 32 বাইট দীর্ঘ এবং AVX-512 64৪ বাইট দীর্ঘ। 1024-বিট বা 2048-বিট ভেক্টর সহ কিছু আর্কিটেকচার রয়েছে, বা এআরএম
এসভিইয়ের

@ ফুকলভ যখন নির্দেশাবলী তখন উপলব্ধ থাকতে পারে, আপনার কাছে মেমকি ব্যবহারের কোনও প্রমাণ আছে কি? এটা সাধারণত একটি সময় লাগে লাইব্রেরি ধরতে জন্য, এবং সর্বশেষ বেশী আমি ব্যবহারের জানতে পারেন SSSE3 এবং আরো অনেক 2011 চেয়ে আরো সাম্প্রতিক হয়
পিট Kirkham

81

মেমোরি অনুলিপি রুটিনগুলি পয়েন্টারগুলির মাধ্যমে সাধারণ মেমরির অনুলির চেয়ে অনেক জটিল এবং দ্রুত হতে পারে:

void simple_memory_copy(void* dst, void* src, unsigned int bytes)
{
  unsigned char* b_dst = (unsigned char*)dst;
  unsigned char* b_src = (unsigned char*)src;
  for (int i = 0; i < bytes; ++i)
    *b_dst++ = *b_src++;
}

উন্নতি

প্রথমটি যে উন্নতি করতে পারে তা হ'ল একটি শব্দের সীমানায় বিন্দুগুলির বিন্যস্ত করা (শব্দের দ্বারা আমার অর্থ দেশীয় পূর্ণসংখ্যার আকার, সাধারণত 32 বিট / 4 বাইট, তবে নতুন স্থাপত্যগুলিতে 64 বিট / 8 বাইট হতে পারে) এবং শব্দ আকারের পদক্ষেপ ব্যবহার করা যেতে পারে / অনুলিপি নির্দেশাবলী। এটি পয়েন্টার সারিবদ্ধ না হওয়া পর্যন্ত বাইট কপি করতে বাইট ব্যবহার করা প্রয়োজন।

void aligned_memory_copy(void* dst, void* src, unsigned int bytes)
{
  unsigned char* b_dst = (unsigned char*)dst;
  unsigned char* b_src = (unsigned char*)src;

  // Copy bytes to align source pointer
  while ((b_src & 0x3) != 0)
  {
    *b_dst++ = *b_src++;
    bytes--;
  }

  unsigned int* w_dst = (unsigned int*)b_dst;
  unsigned int* w_src = (unsigned int*)b_src;
  while (bytes >= 4)
  {
    *w_dst++ = *w_src++;
    bytes -= 4;
  }

  // Copy trailing bytes
  if (bytes > 0)
  {
    b_dst = (unsigned char*)w_dst;
    b_src = (unsigned char*)w_src;
    while (bytes > 0)
    {
      *b_dst++ = *b_src++;
      bytes--;
    }
  }
}

উত্স বা গন্তব্য পয়েন্টারটি যথাযথভাবে সংযুক্ত করা হয়েছে তার ভিত্তিতে বিভিন্ন আর্কিটেকচার ভিন্নভাবে সম্পাদন করবে। উদাহরণস্বরূপ একটি এক্সস্কেল প্রসেসরের উপর উত্স পয়েন্টারের চেয়ে গন্তব্য পয়েন্টারটিকে সারিবদ্ধ করে আমি আরও ভাল পারফরম্যান্স পেয়েছি।

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

এই পর্যায়ে কোডটি সি (বা সি ++) এর পরিবর্তে অ্যাসেমব্লিতে লেখা হচ্ছে, যেহেতু বিলম্বতা আড়ালকরণ এবং থ্রুপুটটির সর্বাধিক সুবিধা পেতে আপনাকে ম্যানুয়ালি লোড এবং স্টোরের নির্দেশাবলীর প্রয়োজন।

সাধারণত লিখিত অনিয়ন্ত্রিত লুপের এক পুনরাবৃত্তিতে ডেটাগুলির একটি সম্পূর্ণ ক্যাশে লাইন অনুলিপি করা উচিত।

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

এর অর্থ ফাংশনটি শুরু করার সাথে সাথে প্রধান অনুলিপি লুপের ভিতরে প্রিফেচ নির্দেশাবলী রাখা putting কপি লুপের আনার ডেটার মাঝখানে প্রিফেক নির্দেশাবলী সহ যা বেশ কয়েকটি পুনরাবৃত্তির সময়ে অনুলিপি করা হবে।

আমি মনে করতে পারি না তবে গন্তব্যের ঠিকানাগুলির পাশাপাশি উত্সের ঠিকানাগুলি উপস্থাপন করাও উপকারী হতে পারে।

ফ্যাক্টর

দ্রুত মেমোরি কীভাবে অনুলিপি করা যায় তার প্রধান কারণগুলি:

  • প্রসেসর, এর ক্যাশে এবং প্রধান মেমরির মধ্যে বিলম্ব।
  • প্রসেসরের ক্যাশে লাইনের আকার এবং কাঠামো।
  • প্রসেসরের মেমরি মুভ / অনুলিপি নির্দেশাবলী (বিলম্বিতা, থ্রুপুট, নিবন্ধের আকার ইত্যাদি)।

সুতরাং আপনি যদি একটি দক্ষ এবং দ্রুত মেমোরি মোকাবেলার রুটিন লিখতে চান তবে আপনার প্রসেসর এবং আর্কিটেকচারের জন্য আপনি যে লেখার জন্য লিখছেন তা সম্পর্কে আপনাকে অনেক কিছু জানতে হবে। বলা বাহুল্য, আপনি যদি কিছু এম্বেড থাকা প্ল্যাটফর্মটিতে না লিখে থাকেন তবে কেবল বিল্ট ইন মেমরি কপির রুটিনগুলি ব্যবহার করা আরও সহজ।


আধুনিক সিপিইউগুলি একটি রৈখিক মেমরি অ্যাক্সেস প্যাটার্ন সনাক্ত করবে এবং তাদের নিজস্ব প্রিফেচিং শুরু করবে। আমি প্রত্যাশা করি যে প্রিফেচ নির্দেশাবলী যে কারণে খুব বেশি পার্থক্য করতে পারে না।
ম্যাক্সি

@ ম্যাক্সি আমি যে কয়েকটি আর্কিটেকচারে মেমরি কপি রুটিনগুলি প্রয়োগ করেছি সেগুলি প্রিফেচটি পরিমাপযোগ্যভাবে সহায়তা করেছে। যদিও এটি সত্য হতে পারে যে বর্তমান প্রজন্মের ইন্টেল / এএমডি চিপগুলি প্রিফেক্চ অনেক আগেই করে, সেখানে প্রচুর পুরানো চিপস এবং অন্যান্য আর্কিটেকচার নেই।
ডেইমিন

"(b_src & 0x3) কে কি কেউ ব্যাখ্যা করতে পারেন! = 0"? আমি এটি বুঝতে পারি না এবং এটিও - এটি সংকলন করে না (একটি ত্রুটি নিক্ষেপ করে: বাইনারি অবৈধ অপারেটর &: স্বাক্ষরবিহীন চর এবং int);
ম্যাভেরিক মেরক্যাট

"(b_src & 0x3)! = 0" সর্বনিম্ন 2 বিট 0 না কিনা তা যাচাই করছে So আপনার সংকলন ত্রুটিটি ঘটে কারণ এটি 0x3 কে বাইট ইন হিসাবে ব্যবহার করে না, আপনি 0x00000003 বা 0x3i (আমার মনে হয়) ব্যবহার করে এটি ঠিক করতে পারেন।
ডেমিন

b_src & 0x3সংকলন করবে না কারণ আপনাকে পয়েন্টার ধরণের ক্ষেত্রে বিটওয়াইজ গাণিতিক করার অনুমতি নেই। আপনাকে অবশ্যই এটি (u)intptr_tপ্রথমে নিক্ষেপ করতে হবে
ফুক্লিভি

18

memcpyকম্পিউটারের আর্কিটেকচারের উপর নির্ভর করে একবারে একাধিক বাইট অনুলিপি করতে পারে। বেশিরভাগ আধুনিক কম্পিউটার একক প্রসেসরের নির্দেশে 32 বিট বা আরও বেশি দিয়ে কাজ করতে পারে।

থেকে একটা উদাহরণ বাস্তবায়ন :

    00026 * দ্রুত অনুলিপি করার জন্য, উভয় পয়েন্টার হিসাবে সাধারণ ক্ষেত্রে অনুকূলিত করুন
    00027 * এবং দৈর্ঘ্যটি শব্দের সাথে সংযুক্ত থাকে এবং পরিবর্তে শব্দটি একবারে অনুলিপি করে
    বাইট-এ-এ-সময়ে 00028 *। অন্যথায়, বাইট দ্বারা অনুলিপি।

8
একটি 386-তে (একটি উদাহরণ হিসাবে), যার কোনও বোর্ডে ক্যাশে ছিল না, এটি একটি বিশাল পার্থক্য করেছে। বেশিরভাগ আধুনিক প্রসেসরগুলিতে, পড়তে এবং লেখাগুলি একবারে একটি ক্যাশে-লাইন ঘটবে, এবং মেমোরির বাসটি সাধারণত বাধা হয়ে দাঁড়ায়, সুতরাং কয়েক শতাংশের উন্নতি আশা করে, কোথাও চতুর্দিকে কাছাকাছি নয়।
জেরি কফিন

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

@ বিলি ওনিল: +১ একেবারে ঠিক ... বিড়ালের চামড়ার একাধিক উপায় নেই। এটি ছিল মাত্র একটি উদাহরণ। স্থির! গঠনমূলক মন্তব্যের জন্য ধন্যবাদ।
মার্ক Byers

7

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

  1. বৃহত্তর ইউনিটগুলি ব্যবহার করুন, যেমন বাইটের পরিবর্তে 32-বিট শব্দ। আপনি এখানে (এমনকি হতে পারে) প্রান্তিককরণের সাথেও ডিল করতে পারেন। আপনি কিছু প্ল্যাটফর্মে উদাহরণস্বরূপ বিজোড় মেমরির স্থানে 32-বিট শব্দটি পড়তে / লিখতে পারবেন না এবং অন্য প্ল্যাটফর্মে আপনি একটি বিশাল পারফরম্যান্স জরিমানা প্রদান করেন। এটির সমাধানের জন্য, ঠিকানাটি 4 দিয়ে বিভাজনযোগ্য একক হতে হবে আপনি 64 বিট সিপিইউগুলির জন্য এটি 64-বিট পর্যন্ত নিতে পারেন বা সিমডি (একক নির্দেশনা, একাধিক ডেটা) নির্দেশাবলী ( এমএমএক্স , এসএসই , ইত্যাদি) ব্যবহার করেও উচ্চতর করতে পারেন )

  2. আপনি বিশেষ সিপিইউ নির্দেশাবলী ব্যবহার করতে পারেন যা আপনার সংকলক সি থেকে অপ্টিমাইজ করতে নাও পারে উদাহরণস্বরূপ, 80386-এ, আপনি "রেপ" উপসর্গ নির্দেশ + "মুভস্ব" নির্দেশ ব্যবহার করতে পারেন এন বাইটগুলি গণনাতে নির্ধারিত করার জন্য নিবন্ধন. ভাল সংকলক আপনার জন্য কেবল এটি করবে, তবে আপনি এমন প্ল্যাটফর্মে থাকতে পারেন যাতে ভাল সংকলক নেই। দ্রষ্টব্য, সেই উদাহরণটি গতির একটি খারাপ প্রদর্শন হতে পারে, তবে প্রান্তিককরণ + বৃহত্তর ইউনিট নির্দেশাবলীর সাথে মিলিত হয়ে এটি নির্দিষ্ট সিপিইউতে থাকা সমস্ত কিছুর চেয়ে দ্রুততর হতে পারে।

  3. লুপ আনরোলিং - কয়েকটি সিপিইউগুলিতে শাখাগুলি বেশ ব্যয়বহুল হতে পারে, তাই লুপগুলি আনআরোলিং করা শাখার সংখ্যা কমিয়ে আনতে পারে। এটি সিমডি নির্দেশাবলী এবং খুব বড় আকারের ইউনিটগুলির সাথে একত্রিত করার জন্য একটি ভাল কৌশল।

উদাহরণস্বরূপ, http://www.agner.org/optimize/#asMLib এর একটি memcpyবাস্তবায়ন রয়েছে যা সেখানে সবচেয়ে মারধর করে (খুব অল্প পরিমাণে)। আপনি যদি সোর্স কোডটি পড়েন তবে এটি এমন প্রচুর পরিমাণে ইনলাইনড অ্যাসেমব্লিং কোড হবে যা উপরের তিনটি কৌশলকে টানবে এবং আপনি কোন সিপিইউ চালাচ্ছেন তার উপর নির্ভর করে সেই কৌশলগুলির মধ্যে কোনটি বেছে নেবে।

দ্রষ্টব্য, এখানে অনুরূপ অপ্টিমাইজেশন রয়েছে যা বাফারেও বাইটগুলি সন্ধানের জন্য তৈরি করা যেতে পারে। strchr()এবং বন্ধুরা প্রায়শই দ্রুত আপনার হাত ঘূর্ণিত সমতুল্যের চেয়ে দ্রুত হয়ে যায়। এটি নেট এবং জাভার ক্ষেত্রে বিশেষভাবে সত্য । উদাহরণস্বরূপ,। নেট, অন্তর্নির্মিত String.IndexOf()এমনকি বায়ার – মুর স্ট্রিং অনুসন্ধানের চেয়ে অনেক দ্রুত , কারণ এটি উপরোক্ত অপ্টিমাইজেশান কৌশলগুলি ব্যবহার করে।


4
আপনি যে একই আগ্নার কুয়াশার সাথে সংযুক্ত রয়েছেন তাও তাত্ত্বিকভাবে বোঝায় যে লুপ আনআরোলিং করা আধুনিক সিপিইউগুলিতে প্রতিবিজাতীয় ।

বর্তমানে বেশিরভাগ সিপিইউগুলির শাখার পূর্বাভাস ভাল রয়েছে, যা সাধারণ ক্ষেত্রে লুপ এনরোলিংয়ের সুবিধাটিকে অস্বীকার করা উচিত। একটি ভাল অনুকূলকরণ সংকলক এখনও মাঝে মাঝে এটি ব্যবহার করতে পারে।
থোমাসরুটটার

5

সংক্ষিপ্ত উত্তর:

  • ক্যাশে ভরাট
  • যেখানে সম্ভব বাইটের পরিবর্তে শব্দ পরিবর্তনের স্থানান্তর করুন
  • সিমডি ম্যাজিক

4

এটি বাস্তবের কোনও বাস্তব-বাস্তবায়নে বাস্তবে ব্যবহৃত হয়েছে কিনা তা আমি জানি না memcpy, তবে আমি মনে করি যে ডাফের ডিভাইসটি এখানে উল্লেখ করার যোগ্য।

উইকিপিডিয়া থেকে :

send(to, from, count)
register short *to, *from;
register count;
{
        register n = (count + 7) / 8;
        switch(count % 8) {
        case 0:      do {     *to = *from++;
        case 7:              *to = *from++;
        case 6:              *to = *from++;
        case 5:              *to = *from++;
        case 4:              *to = *from++;
        case 3:              *to = *from++;
        case 2:              *to = *from++;
        case 1:              *to = *from++;
                } while(--n > 0);
        }
}

মনে রাখবেন যে memcpyউপরেরটি ইচ্ছাকৃতভাবে toপয়েন্টারটিকে বাড়িয়ে তোলে না । এটি কিছুটা আলাদা অপারেশন প্রয়োগ করে: মেমরি-ম্যাপযুক্ত রেজিস্টারটিতে লেখা। বিস্তারিত জানার জন্য উইকিপিডিয়া নিবন্ধটি দেখুন।


ডাফের ডিভাইস, বা কেবলমাত্র প্রাথমিক জাম্প মেকানিজম, প্রথম 1..3 (বা 1..7) বাইটগুলি অনুলিপি করার জন্য একটি ভাল ব্যবহার যাতে পয়েন্টারগুলি একটি সুন্দর সীমানায় সংযুক্ত থাকে যেখানে বড় মেমরি সরানোর নির্দেশাবলী ব্যবহার করা যেতে পারে।
ডেইমিন

@ মার্কবায়ার্স: কোডটি কিছুটা আলাদা অপারেশন চিত্রিত করে ( *toমেমরি- ম্যাপযুক্ত নিবন্ধকে বোঝায় এবং ইচ্ছাকৃতভাবে বৃদ্ধি করা হয় না - লিঙ্ক-টু নিবন্ধটি দেখুন)। আমি যেমন ভেবেছিলাম যে আমি পরিষ্কার করে দিয়েছি, আমার উত্তর কোনও দক্ষ সরবরাহ করার চেষ্টা করে না memcpy, এটি কেবল একটি কৌতূহলযুক্ত কৌশলটির উল্লেখ করে।
এনপিই

@ ডেইমিন সম্মত হয়েছেন, যেমন আপনি বলেছিলেন যে আপনি এই কাজটি এড়াতে পারবেন (যখন) () এবং স্যুইচটি অনুবাদক দ্বারা একটি জাম্প টেবিলটিতে অনুবাদ করা হবে। যখন আপনি বাকী ডেটা যত্ন নিতে চান তখন খুব দরকারী। ডফের ডিভাইস সম্পর্কে একটি সতর্কতা উল্লেখ করা উচিত, দৃশ্যত নতুন আর্কিটেকচারে (আরও নতুন x86), শাখার পূর্বাভাস এতটাই দক্ষ যে ডাফের ডিভাইসটি আসলে একটি সাধারণ লুপের চেয়ে ধীর।
একমাসে

4
ওহ না .. ডাফের ডিভাইস নয় দয়া করে ডাফের ডিভাইসটি ব্যবহার করবেন না। অনুগ্রহ. পিজিও ব্যবহার করুন এবং আমাকে সংকলকটি আপনার জন্য লুপ আনরোলিং করতে দিন যেখানে এটি অর্থবোধ করে।
বিলি ওনিল

না, ডাফের ডিভাইসটি সম্ভবত কোনও আধুনিক বাস্তবায়নে ব্যবহৃত হয় না।
gnasher729

3

অন্যদের মতো মেমপ্পির অনুলিপিগুলি 1-বাইট খণ্ডের চেয়ে বড়। শব্দ আকারের খণ্ডে অনুলিপি করা খুব দ্রুত। তবে বেশিরভাগ বাস্তবায়ন এটিকে আরও একধাপ এগিয়ে নিয়ে যায় এবং লুপিংয়ের আগে বেশ কয়েকটি এমওভি (শব্দ) নির্দেশনা চালায়। অনুলিপি করে বলার সুবিধা, লুপ প্রতি 8 টি শব্দ ব্লক হ'ল লুপ নিজেই ব্যয়বহুল। এই কৌশলটি 8 টির একটি ফ্যাক্টর দ্বারা কন্ডিশনাল শাখার সংখ্যা হ্রাস করে, দৈত্যিক ব্লকগুলির জন্য অনুলিপিটিকে অনুকূল করে।


4
আমি এটা সত্য মনে করি না। আপনি লুপটি আনরোল করতে পারেন, তবে আপনি লক্ষ্য আর্কিটেকচারের সময়ে একবারে ঠিকানার চেয়ে বেশি কোনও একক নির্দেশিকায় অনুলিপি করতে পারবেন না। এছাড়াও,
লুপটিও আনরোলিংয়ের

@ বিলি ওনিল: আমি মনে করি না যে ভায়োডস্টার এর অর্থ কি। একাধিক পদক্ষেপের নির্দেশনা পেয়ে ইউনিট সংখ্যা গণনা করার ওভারহেড হ্রাস পেয়েছে।
wallyk

@ বিলি ওনিল: আপনি বিষয়টিটি মিস করছেন missing 1-শব্দ একবারে এমওভি, জেএমপি, এমওভি, জেএমপি ইত্যাদির মতো যেখানে আপনি মোভ মোভ মোভ মোভ জেএমপি করতে পারেন। আমি এর আগে মেম্পসি লিখেছি এবং এটি করার বিভিন্ন উপায় আমি বেঞ্চমার্ক করেছি;)
ভয়েডস্টার

@ওয়ালেক: সম্ভবত তবে তিনি বলেছেন "আরও বড় অংশগুলি অনুলিপি করুন" - যা সত্যই সম্ভব নয়। যদি তার অর্থ লুপটি অনিয়ন্ত্রিত হয় তবে তার উচিত "বেশিরভাগ বাস্তবায়ন এটিকে আরও একধাপ এগিয়ে নিয়ে যায় এবং লুপটি আনলোল করে।" লিখিত হিসাবে উত্তর সেরা বিভ্রান্তিকর, সবচেয়ে খারাপ ভুল।
বিলি ওনিল

@ ভয়েডস্টার: সম্মত --- এটি এখন আরও ভাল। +1
বিলি ওনিল

2

উত্তরগুলি দুর্দান্ত, তবে আপনি যদি এখনও memcpyনিজেই একটি দ্রুত প্রয়োগ করতে চান তবে দ্রুত মেমকিপি, সি-তে ফাস্ট মেমকি সম্পর্কিত একটি আকর্ষণীয় ব্লগ পোস্ট রয়েছে ।

void *memcpy(void* dest, const void* src, size_t count)
{
    char* dst8 = (char*)dest;
    char* src8 = (char*)src;

    if (count & 1) {
        dst8[0] = src8[0];
        dst8 += 1;
        src8 += 1;
    }

    count /= 2;
    while (count--) {
        dst8[0] = src8[0];
        dst8[1] = src8[1];

        dst8 += 2;
        src8 += 2;
    }
    return dest;
}

এমনকি, মেমরি অ্যাক্সেসগুলি অনুকূলকরণের সাথে এটি আরও ভাল হতে পারে।


1

কারণ অনেক লাইব্রেরির রুটিনের মতো এটি আপনি যে আর্কিটেকচারটি চালাচ্ছেন তার জন্য এটি অনুকূলিত হয়েছে। অন্যরা বিভিন্ন কৌশল ব্যবহার করেছেন যা পোস্ট করেছে।

পছন্দ দেওয়া হয়েছে, আপনার নিজের রোল না করে লাইব্রেরির রুটিনগুলি ব্যবহার করুন। এটি ডিআরওয়াইতে একটি প্রকরণ যা আমি ডিআরও (অন্যদের পুনরাবৃত্তি করবেন না) বলি। এছাড়াও, লাইব্রেরির রুটিনগুলি আপনার নিজের প্রয়োগের চেয়ে কম ভুল হতে পারে।

আমি মেমরি অ্যাক্সেস চেকারদের মেমরি বা স্ট্রিং বাফারগুলিতে শব্দের আকারের একাধিক ছিল না এমন পাঠের সীমার বাইরে অভিযোগ করতে দেখেছি। এটি অপটিমাইজেশন ব্যবহারের ফলাফল।


0

আপনি মেমসেট, মেমকি এবং মেমমোভের ম্যাকোস বাস্তবায়ন দেখতে পারেন।

বুট করার সময়, ওএস নির্ধারণ করে যে এটি কোন প্রসেসরটি চলছে। এটি প্রতিটি সমর্থিত প্রসেসরের জন্য বিশেষত অপ্টিমাইজড কোড তৈরি করেছে এবং বুট করার সময় একটি নির্দিষ্ট পঠন / কেবলমাত্র স্থানে সঠিক কোডের জন্য একটি জ্যাম্প নির্দেশ সংরক্ষণ করে।

সি মেমসেট, মেমকি এবং মেমোমোভ বাস্তবায়নগুলি নির্দিষ্ট স্থানে কেবলমাত্র এক লাফ।

বাস্তবায়নগুলি মেমকি এবং মেমমোভের জন্য উত্স এবং গন্তব্যের প্রান্তিককরণের উপর নির্ভর করে বিভিন্ন কোড ব্যবহার করে। তারা স্পষ্টতই সমস্ত উপলব্ধ ভেক্টর ক্ষমতা ব্যবহার করে। আপনি যখন প্রচুর পরিমাণে ডেটা অনুলিপি করেন এবং পৃষ্ঠার টেবিলগুলির জন্য অপেক্ষা কমানোর নির্দেশনা থাকে তখন এগুলি নন-ক্যাশিং বৈকল্পগুলিও ব্যবহার করে। এটি কেবল এসেম্বলারের কোড নয়, এটি প্রতিটি প্রসেসরের আর্কিটেকচার সম্পর্কে অত্যন্ত ভাল জ্ঞানের সাথে কেউ লিখেছেন এসেম্বলার কোড।

ইন্টেল এসেম্বলারের নির্দেশাবলীও যুক্ত করেছে যা স্ট্রিং অপারেশনগুলিকে আরও দ্রুত করতে পারে। উদাহরণস্বরূপ স্ট্রাস্টারকে সমর্থন করার নির্দেশনা সহ যা 256 বাইট এক চক্রের সাথে তুলনা করে।


অ্যাপলের মেমসেট / মেমকি / মেমমোভের ওপেন সোর্স সংস্করণটি কেবল একটি জেনেরিক সংস্করণ যা সিমড ব্যবহার করে আসল সংস্করণটির তুলনায় অনেক ধীর হবে
ফুচলভি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.