জিসিসির জন্য ব্রাঙ্কের ভবিষ্যদ্বাণীকে সর্বদা নির্দিষ্ট পথে যেতে বাধ্য করার জন্য কি কোনও সংকলক ইঙ্গিত রয়েছে?


118

ইন্টেল আর্কিটেকচারের জন্য, জিসিসি সংকলককে কোড উত্পন্ন করার জন্য নির্দেশ দেওয়ার কোনও উপায় যা সর্বদা শাখার পূর্বাভাসকে আমার কোডে একটি নির্দিষ্ট উপায়ে বাধ্য করে? ইন্টেল হার্ডওয়্যার এমনকি এটি সমর্থন করে? অন্যান্য সংকলক বা হার্ডওয়্যার সম্পর্কে কী?

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

for (;;) {
  if (normal) { // How to tell compiler to always branch predict true value?
    doSomethingNormal();
  } else {
    exceptionalCase();
  }
}

এভডজান মোস্তফার প্রশ্নের অনুসরণ অনুসারে, প্রসেসরের নির্দেশের সাথে প্রথম বারের মতো প্রসেসরের মুখোমুখি হিন্টটি কেবল একটি ইঙ্গিত নির্দিষ্ট করতে পারে, পরবর্তী সমস্ত শাখার পূর্বাভাস, স্বাভাবিকভাবে কাজ করে?


কোনও কিছু অস্বাভাবিক হয়ে উঠলে (যা সংকলকটি স্বতন্ত্র) হয়ে যায় তার ব্যতিক্রমও ছুঁড়ে ফেলতে পারে
শেপ

উত্তর:


9

সি ++ ২০-এর হিসাবে সম্ভাব্য এবং সম্ভাবনাযুক্ত বৈশিষ্ট্যগুলি মানক করা উচিত এবং ইতিমধ্যে g ++ 9 এ সমর্থিত । এখানে আলোচনা হিসাবে , আপনি লিখতে পারেন

if (a>b) {
  /* code you expect to run often */
  [[likely]] /* last statement */
}

উদাহরণস্বরূপ নিম্নলিখিত কোডে অন্য ব্লকটি [[unlikely]]যদি ব্লকটি অন্তর্ভুক্ত করে তবে ইনলাইনড ধন্যবাদ পাবেন

int oftendone( int a, int b );
int rarelydone( int a, int b );
int finaltrafo( int );

int divides( int number, int prime ) {
  int almostreturnvalue;
  if ( ( number % prime ) == 0 ) {
    auto k                         = rarelydone( number, prime );
    auto l                         = rarelydone( number, k );
    [[unlikely]] almostreturnvalue = rarelydone( k, l );
  } else {
    auto a            = oftendone( number, prime );
    almostreturnvalue = oftendone( a, a );
  }
  return finaltrafo( almostreturnvalue );
}

গডবোল্ট লিঙ্কটি বৈশিষ্ট্যের উপস্থিতি / অনুপস্থিতির তুলনা করে


কেন ব্যাবহার [[unlikely]]মধ্যে ifবনাম [[likely]]মধ্যে else?
উইলিয়াম কেএফ

কোনও কারণ নেই, এই বৈশিষ্ট্যটি যেখানে যেতে হবে তার চারপাশে চেষ্টা করার পরে এই নক্ষত্রমুখে শেষ হয়েছে।
সিফার্ট

বেশ দারুন. খুব খারাপ পদ্ধতিটি পুরানো সি ++ সংস্করণগুলিতে প্রযোজ্য নয়।
ম্যাক্সিম এগারুশকিন

কল্পনাপ্রসূত গডবোল্ট লিঙ্ক
লুইস কেলসি

87

__builtin_expect(long exp, long c)এই জাতীয় বৈশিষ্ট্য সরবরাহ করতে জিসিসি ফাংশনটিকে সমর্থন করে । আপনি এখানে ডকুমেন্টেশন চেক করতে পারেন ।

expশর্তটি কোথায় ব্যবহৃত cহয় এবং প্রত্যাশিত মান। উদাহরণস্বরূপ আপনার ক্ষেত্রে আপনি চাইবেন

if (__builtin_expect(normal, 1))

বিশ্রী সিনট্যাক্সের কারণে এটি সাধারণত দুটি কাস্টম ম্যাক্রোর মতো সংজ্ঞায়িত করে ব্যবহৃত হয়

#define likely(x)    __builtin_expect (!!(x), 1)
#define unlikely(x)  __builtin_expect (!!(x), 0)

কাজটি সহজ করার জন্য

মনে আছে:

  1. এটি মানহীন
  2. একটি সংকলক / সিপিইউ শাখার পূর্বাভাসক সম্ভবত এই জাতীয় জিনিসগুলি সিদ্ধান্ত নেওয়ার ক্ষেত্রে আপনার চেয়ে বেশি দক্ষ, যাতে এটি অকাল মাইক্রো-অপটিমাইজেশন হতে পারে

3
এমন কোনও কারণ আছে যা আপনি কোনও ম্যাক্রো দেখান এবং একটি constexprফাংশন না ?
কলম্বো

22
@ কলম্বো: আমি মনে করি না কোনও constexprফাংশন এই ম্যাক্রোটিকে প্রতিস্থাপন করতে পারে । এটি ifসরাসরি বিবৃতিতে থাকতে হবে আমি বিশ্বাস করি। একই কারণে assertকোনও constexprফাংশন হতে পারে না ।
মাকিং হাঁস


7
@ কলম্বো ম্যাক্রো ব্যবহারের একটি কারণ হ'ল এটি সি বা সি ++ এর কয়েকটি জায়গার মধ্যে একটি যেখানে ম্যাক্রো কোনও ফাংশনের চেয়ে শব্দার্থগতভাবে সঠিক । ফাংশন শুধুমাত্র অপ্টিমাইজেশান কারণে কাজ মনে হচ্ছে (এটা হল একটি অপ্টিমাইজেশান: constexprশুধুমাত্র মান শব্দার্থবিদ্যা, সমাবেশ বাস্তবায়ন-নির্দিষ্ট ইনলাইনিং না সম্পর্কে আলোচনা); কোডটির সরল ব্যাখ্যা (কোনও ইনলাইন নয়) অর্থহীন। এর জন্য কোনও ফাংশন ব্যবহার করার কোনও কারণ নেই।
লুশেনকো

2
@ লুশেনকো বিবেচনা করুন যে এটি __builtin_expectনিজেই একটি অপ্টিমাইজেশনের ইঙ্গিত, তাই যুক্তিযুক্ত যে কোনও পদ্ধতি তার ব্যবহারকে সহজীকরণের উপর নির্ভর করে যা অপ্টিমাইজেশানের উপর নির্ভর করে ... তা বিশ্বাসযোগ্য নয়। এছাড়াও, আমি constexprএটিকে প্রথম স্থানে কাজ করার জন্য স্পেসিফায়ারটি যুক্ত করিনি , তবে ধ্রুবক প্রকাশে এটিকে কাজ করার জন্য। এবং হ্যাঁ, একটি ফাংশন ব্যবহার করার কারণ রয়েছে। উদাহরণস্বরূপ, আমি আমার পুরো নেমস্পেসকে এমন কোনও সুন্দর নামের সাথে দূষিত করতে চাই না likely। আমি উদাহরণস্বরূপ LIKELY, এটি একটি ম্যাক্রো এবং সংঘর্ষ এড়াতে জোর দেওয়ার জন্য ব্যবহার করতে হবে, তবে এটি কেবল কুৎসিত।
কলম্বো

46

জিসিসি হয়েছে দীর্ঘ __builtin_expect (দীর্ঘ মেপুঃ, দীর্ঘ গ) ( জোর খনি ):

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

রিটার্ন মান এক্সপ এর মান, যা একটি অবিচ্ছেদ্য অভিব্যক্তি হওয়া উচিত। অন্তর্নির্মিত শব্দার্থবিজ্ঞান হ'ল এটি প্রত্যাশিত যে exp == গ। উদাহরণ স্বরূপ:

if (__builtin_expect (x, 0))
   foo ();

ইঙ্গিত দেয় যে আমরা xo শূন্য হওয়ার প্রত্যাশা করার কারণে আমরা foo কল করার প্রত্যাশা করি না। যেহেতু আপনি এক্সপের জন্য অবিচ্ছেদ্য প্রকাশের মধ্যে সীমাবদ্ধ, আপনার যেমন নির্মাণগুলি ব্যবহার করা উচিত

if (__builtin_expect (ptr != NULL, 1))
   foo (*ptr);

পয়েন্টার বা ভাসমান-পয়েন্ট মানগুলির পরীক্ষা করার সময়।

ডকুমেন্টেশন নোট হিসাবে আপনার প্রকৃত প্রোফাইল প্রতিক্রিয়া ব্যবহার করতে পছন্দ করা উচিত এবং এই নিবন্ধটি এর একটি ব্যবহারিক উদাহরণ দেখায় এবং কীভাবে এটি তাদের ক্ষেত্রে অন্তত ব্যবহারের উন্নতি হিসাবে শেষ হয় __builtin_expect। এছাড়াও g ++ এ প্রোফাইল গাইডেড অপ্টিমাইজেশন কীভাবে ব্যবহার করবেন?

আমরা কার্নাল ম্যাক্রোতে সম্ভাব্য () এবং অসম্ভব () যা এই বৈশিষ্ট্যটি ব্যবহার করে: তার উপর একটি লিনাক্স কার্নেল নববিযুক্ত নিবন্ধটি খুঁজে পেতে পারি :

#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

!!ম্যাক্রোতে ব্যবহৃত নোটটি আমরা এর শর্তটি (শর্তের পরিবর্তে) কেন ব্যবহার করতে পারি (শর্ত)?

এই কৌশলটি লিনাক্স কার্নেলে ব্যবহৃত হওয়ার অর্থ এই নয় যে এটি সর্বদা এটি ব্যবহার করা বুদ্ধিমান। এই প্রশ্নটি থেকে আমরা দেখতে পাচ্ছি যে আমি সম্প্রতি প্যারামিটারটি সংকলন সময় ধ্রুবক বা ভেরিয়েবল হিসাবে পাস করার সময় ফাংশন পারফরম্যান্সের মধ্যে পার্থক্যের উত্তর দিয়েছিলাম যে অনেকগুলি হাত ঘূর্ণিত অপ্টিমাইজেশান কৌশল সাধারণ ক্ষেত্রে কাজ করে না। কোনও কৌশল কার্যকর কিনা তা বোঝার জন্য আমাদের সাবধানতার সাথে প্রোফাইল কোডের প্রয়োজন। অনেক পুরানো কৌশল এমনকি আধুনিক সংকলক অপ্টিমাইজেশনের সাথে প্রাসঙ্গিক নাও হতে পারে।

দ্রষ্টব্য, যদিও বিল্টিনগুলি পোর্টেবল ঝাঁকুনি নয় তবে __builtin_expect সমর্থন করে

কিছু কিছু স্থাপত্যের ক্ষেত্রে এটি কোনও পার্থক্য নাও করতে পারে


লিনাক্স কার্নেলের জন্য যা যথেষ্ট ভাল তা সি ++ 11 এর পক্ষে যথেষ্ট নয়।
ম্যাক্সিম এগারুশকিন

@ ম্যাক্সিম এগারোশকিন নোট, আমি আসলে এটির ব্যবহারের প্রস্তাব দিই না, বাস্তবে আমি যে সিসি ডকুমেন্টেশন উদ্ধৃত করি তা আমার প্রথম উদ্ধৃতিও সেই কৌশলটি ব্যবহার করে না। আমি বলব যে আমার উত্তরের মূল জোর এই পথটি নামার আগে সাবধানতার সাথে বিকল্পগুলি বিবেচনা করা।
শফিক ইয়াঘমোর

44

কোন নেই. (কমপক্ষে আধুনিক x86 প্রসেসরের উপর))

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

আরও বিশদের জন্য এই প্রশ্নটি দেখুন: ইন্টেল x86 0x2E / 0x3E উপসর্গ শাখা পূর্বাভাস আসলে ব্যবহৃত?

পরিষ্কার হতে, __builtin_expectএবং / অথবা এর ব্যবহার উভয়ই কোড লেআউটের মাধ্যমে শাখা প্রেডিক্টরকে ইঙ্গিত দিয়ে ( x86-64 বিধানসভাটির পারফরম্যান্স অপটিমাইজেশন - প্রান্তিককরণ এবং শাখার পূর্বাভাস দেখুন ) এবং ক্যাশের আচরণ উন্নত করে আপনার কোডের কার্যকারিতা উন্নত -fprofile-arcs করতে পারে "সম্ভাব্য" কোডটি "সম্ভাব্য" কোড থেকে দূরে রেখে।


9
এটি ভুল। X86 এর সমস্ত আধুনিক সংস্করণে, পূর্বনির্ধারিত পূর্বাভাস অ্যালগরিদমটি ভবিষ্যদ্বাণী করা হয় যে ফরোয়ার্ড শাখা নেওয়া হয় নি এবং পশ্চাদপদ শাখাগুলি রয়েছে ( সফটওয়্যার ..intel.com/en-us/articles/… দেখুন )। সুতরাং আপনার কোডটি পুনরায় সাজিয়ে আপনি কার্যকরভাবে সিপিইউতে একটি ইঙ্গিত দিতে পারেন । আপনি যখন ব্যবহার করবেন তখন জিসিসি ঠিক এটি করে __builtin_expect
নিমো

6
@ নেমো, আপনি আমার উত্তরের প্রথম বাক্যটি পড়েছেন? আপনি যা কিছু বলেছেন তা আমার উত্তর বা প্রদত্ত লিঙ্কগুলিতে আচ্ছাদিত। আপনি যদি "শাখার পূর্বাভাসকে সর্বদা একটি নির্দিষ্ট পথে যেতে বাধ্য করতে" পারেন কিনা এমন প্রশ্ন জিজ্ঞাসা করা হয়েছিল, যার উত্তরটি "না", এবং আমি অন্যান্য উত্তরগুলি এ সম্পর্কে যথেষ্ট পরিষ্কার বলে অনুভব করি না।
আর্টেলিয়াস 9:38

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

আইএমও এটি অকেজো নয়; এটি সিপিইউ এবং সংকলকরা আসলে কীভাবে কাজ করে তার একটি কার্যকর ব্যাখ্যা, যা এই বিকল্পগুলির সাথে / ছাড়া কর্মক্ষমতা বিশ্লেষণের সাথে প্রাসঙ্গিক হতে পারে। উদাহরণস্বরূপ, আপনি সাধারণত __builtin_expectতুচ্ছভাবে একটি পরীক্ষা-কেস তৈরি করতে ব্যবহার করতে পারবেন না যা আপনি perf statএটির সাথে পরিমাপ করতে পারবেন যে খুব উচ্চ শাখার ভুল অনুমানের হার থাকবে। এটি কেবল শাখার বিন্যাসকে প্রভাবিত করে । এবং বিটিডাব্লু, স্যান্ডিব্রিজ বা অন্তত হাসওয়েল যেহেতু স্থির পূর্বাভাস বেশি / মোটে ব্যবহার করে না ; বিএইচটি-তে সবসময় কিছুটা পূর্বাভাস থাকে, এটি বাসি উপন্যাস হোক বা না হোক। xania.org/201602/bpu-part-two
পিটার

24

সি ++ 11 এ সম্ভাব্য / সম্ভাব্য ম্যাক্রোস সংজ্ঞায়নের সঠিক উপায়টি নিম্নলিখিত:

#define LIKELY(condition) __builtin_expect(static_cast<bool>(condition), 1)
#define UNLIKELY(condition) __builtin_expect(static_cast<bool>(condition), 0)

এই পদ্ধতিটি বিপরীতে সমস্ত সি ++ সংস্করণের সাথে সামঞ্জস্যপূর্ণ [[likely]]তবে অ-মানক এক্সটেনশনের উপর নির্ভর করে __builtin_expect


যখন এই ম্যাক্রোগুলি এইভাবে সংজ্ঞায়িত হয়:

#define LIKELY(condition) __builtin_expect(!!(condition), 1)

এটি ifবিবৃতিগুলির অর্থ পরিবর্তন করতে এবং কোডটি ভেঙে দিতে পারে। নিম্নলিখিত কোড বিবেচনা করুন:

#include <iostream>

struct A
{
    explicit operator bool() const { return true; }
    operator int() const { return 0; }
};

#define LIKELY(condition) __builtin_expect((condition), 1)

int main() {
    A a;
    if(a)
        std::cout << "if(a) is true\n";
    if(LIKELY(a))
        std::cout << "if(LIKELY(a)) is true\n";
    else
        std::cout << "if(LIKELY(a)) is false\n";
}

এবং এর আউটপুট:

if(a) is true
if(LIKELY(a)) is false

আপনি দেখতে পাচ্ছেন, এর শব্দার্থকে ভাঙ্গার জন্য !!cast ালাই হিসাবে ব্যবহারের মতো লাইকের সংজ্ঞা ।boolif

এখানে বিষয়টি এটি নয় operator int()এবং operator bool()এটি সম্পর্কিত হওয়া উচিত। যা ভাল অনুশীলন।

পরিবর্তে এর !!(x)পরিবর্তে ব্যবহার করা C ++ 11 প্রসঙ্গেগত রূপান্তরগুলিরstatic_cast<bool>(x) জন্য প্রসঙ্গটি হারায় ।


নোট প্রাসঙ্গিক রূপান্তরগুলি 2012 এর ত্রুটির মাধ্যমে এসেছিল এবং এমনকি 2014 এর শেষের দিকে এখনও বাস্তবায়ন বিচ্যুতি ছিল। আসলে দেখে মনে হচ্ছে যে কেসটি আমি সংযুক্ত করেছি এখনও জিসিসির জন্য কাজ করে না।
শফিক ইয়াঘমুর

@ শফিকিক ইয়াঘমুর এটি একটি আকর্ষণীয় পর্যবেক্ষণ যা প্রসঙ্গে প্রাসঙ্গিক রূপান্তর জড়িত switch, এর সাথে ধন্যবাদ জানায়। এখানে জড়িত প্রাসঙ্গিক রূপান্তরটি টাইপ করতে পার্টুক্লুয়ার boolএবং সেখানে তালিকাভুক্ত পাঁচটি নির্দিষ্ট প্রসঙ্গ যা switchপ্রসঙ্গ অন্তর্ভুক্ত করে না ।
ম্যাক্সিম এগারুশকিন

এটি কেবল সি ++ প্রভাবিত করে, তাই না? সুতরাং বিদ্যমান সি প্রকল্পগুলি ব্যবহারের জন্য যাওয়ার এবং পরিবর্তন করার কোনও কারণ নেই (_Bool)(condition)কারণ সি এর সাথে অপারেটর ওভারলোডিং নেই।
পিটার কর্ডেস

2
আপনার উদাহরণে, আপনি ঠিক ব্যবহার করেছেন (condition), না !!(condition)। উভয়ই এটি trueপরিবর্তন করার পরে (জি ++ 7.1 দিয়ে পরীক্ষা করা)। আপনি যখন !!বুলেটিনাইজ করতে ব্যবহার করছেন তখন আপনি এমন একটি সমস্যা তৈরি করতে পারেন যা প্রকৃতপক্ষে আপনি যে সমস্যার কথা বলছেন তা প্রদর্শিত করে?
পিটার

3
পিটার কর্ডস যেমন উল্লেখ করেছেন, আপনি বলেছেন "যখন এই ম্যাক্রোগুলি [এভাবে] সংজ্ঞায়িত হয়:" এবং তারপরে '!!' ব্যবহার করে একটি ম্যাক্রো দেখানো যেতে পারে এবং কোডটি ভঙ্গ করতে পারে তবে নিম্নলিখিত কোডটি বিবেচনা করুন: " ... এবং তারপরে আপনি এমন কোড দেখান যা '!!' ব্যবহার করে না মোটেও - যা সি ++ 11 এর আগেও ভেঙে গেছে বলে জানা গেছে। প্রদত্ত ম্যাক্রো (ব্যবহার করে !!) ভুল হয়ে যায় এমন উদাহরণ দেখানোর জন্য দয়া করে উত্তরটি পরিবর্তন করুন।
কার্লো উড

18

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

অনুরূপ লাইনের পাশাপাশি, তবে এখনও উল্লেখ করা হয়নি, একটি "ঠান্ডা" পথে সংকলককে কোড উত্পন্ন করতে বাধ্য করার এক জিসিসি-নির্দিষ্ট উপায়। এর মধ্যে noinlinecoldবৈশিষ্ট্যগুলির ব্যবহার জড়িত , যা তারা যা বলে ঠিক তেমন করে। এই বৈশিষ্ট্যগুলি কেবল ফাংশনে প্রয়োগ করা যেতে পারে তবে সি ++ 11 এর মাধ্যমে আপনি ইনলাইন ল্যাম্বদা ফাংশনগুলি ঘোষণা করতে পারেন এবং এই দুটি বৈশিষ্ট্যটি ল্যাম্বদা ফাংশনেও প্রয়োগ করা যেতে পারে।

যদিও এটি এখনও একটি মাইক্রো-অপ্টিমাইজেশনের সাধারণ বিভাগে আসে এবং এইভাবে স্ট্যান্ডার্ড পরামর্শটি প্রয়োগ হয় — পরীক্ষা অনুমান করবেন না — আমি মনে করি এটি এর চেয়ে বেশি কার্যকর __builtin_expect। X86 প্রসেসরের কোনও প্রজন্মই শাখা প্রেডিকশন ইঙ্গিতগুলি ( রেফারেন্স ) ব্যবহার করে না, সুতরাং আপনি যেভাবেই প্রভাব ফেলতে সক্ষম হচ্ছেন সেটি হ'ল সমাবেশ কোডের ক্রম of যেহেতু আপনি জানেন যে ত্রুটি-পরিচালনা বা "এজ কেস" কোডটি কী তাই আপনি এই টীকাটি ব্যবহার করে এটি নিশ্চিত করতে পারেন যে কম্পাইলারটি এর সাথে কোনও শাখার পূর্বাভাস দেয় না এবং আকারের জন্য অনুকূলিত করার সময় এটিকে "হট" কোড থেকে দূরে সরিয়ে রাখবে।

নমুনা ব্যবহার:

void FooTheBar(void* pFoo)
{
    if (pFoo == nullptr)
    {
        // Oh no! A null pointer is an error, but maybe this is a public-facing
        // function, so we have to be prepared for anything. Yet, we don't want
        // the error-handling code to fill up the instruction cache, so we will
        // force it out-of-line and onto a "cold" path.
        [&]() __attribute__((noinline,cold)) {
            HandleError(...);
        }();
    }

    // Do normal stuff
    
}

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

অফিসিয়াল ডকুমেন্টেশন এখানে দেখুন: https://gcc.gnu.org/onlinesocs/gcc/Common-Function-Attributes.html#Common-Function-Aribributes


2
শাখার পূর্বাভাস ইঙ্গিতের উপসর্গগুলি এড়ানো হয় কারণ তাদের প্রয়োজন হয় না; আপনি ঠিক আপনার কোডটি পুনরায় অর্ডার করে ঠিক একই প্রভাব অর্জন করতে পারেন। (ডিফল্ট শাখার পূর্বাভাস অ্যালগরিদমটি অনুমান করা হয় যে পশ্চাৎ শাখা নেওয়া হয় এবং ফরোয়ার্ড শাখাগুলি হয় না)) সুতরাং আপনি কার্যকরভাবে সিপিইউকে একটি ইঙ্গিত দিতে পারেন, এবং এটি এটি __builtin_expectকরে। এটি মোটেও অকেজো নয়। আপনি ঠিক বলেছেন যে coldবৈশিষ্ট্যটিও কার্যকর, তবে আপনি __builtin_expectআমার মনে করেন যে ইউটিলিটিটি মূল্যায়ন করেন না।
নিমো

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

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

"আধুনিক ইন্টেল সিপিইউগুলি স্থির শাখার পূর্বাভাস ব্যবহার করে না" এর জন্য আপনার কাছে কি কোনও রেফারেন্স রয়েছে? ইন্টেলের নিজস্ব নিবন্ধ ( software.intel.com/en-us/articles/… ) অন্যথায় বলে ... তবে এটি ২০১১ সালের
নেমো

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

5

__builtin_expect আপনি কোন শাখাটি কীভাবে যেতে চান তা সংকলকটি বলতে ব্যবহার করা যেতে পারে। এটি কীভাবে কোড উত্পন্ন হয় তা প্রভাবিত করতে পারে। সাধারণ প্রসেসরগুলি ক্রমান্বয়ে কোড দ্রুত চালায়। সুতরাং আপনি যদি লিখুন

if (__builtin_expect (x == 0, 0)) ++count;
if (__builtin_expect (y == 0, 0)) ++count;
if (__builtin_expect (z == 0, 0)) ++count;

সংকলক কোডটির মতো উত্পন্ন করবে

if (x == 0) goto if1;
back1: if (y == 0) goto if2;
back2: if (z == 0) goto if3;
back3: ;
...
if1: ++count; goto back1;
if2: ++count; goto back2;
if3: ++count; goto back3;

যদি আপনার ইঙ্গিতটি সঠিক হয় তবে এটি আসলে সম্পাদিত কোনও শাখা ছাড়াই কোডটি কার্যকর করবে। এটি স্বাভাবিক ক্রমগুলির চেয়ে দ্রুত চলবে, যেখানে প্রতিটি যদি বিবৃতি শর্তাধীন কোডের চারপাশে শাখা করে এবং তিনটি শাখা চালিত করে।

নতুন x86 প্রসেসরের শাখাগুলির জন্য নির্দেশাবলী রয়েছে যা নেওয়া হবে বলে আশা করা হয়, বা যে শাখাগুলি নেওয়া হবে না বলে আশা করা হয় (সেখানে একটি নির্দেশ উপসর্গ আছে; বিশদ সম্পর্কে নিশ্চিত নয়)। প্রসেসর এটি ব্যবহার করে কিনা তা নিশ্চিত নয়। এটি খুব কার্যকর নয়, কারণ শাখার পূর্বাভাস এটি ঠিক জরিমানা করবে। সুতরাং আমি মনে করি না আপনি আসলে শাখার পূর্বাভাসকে প্রভাবিত করতে পারেন ।


2

ও.পি. এর প্রতি শ্রদ্ধা জানায়, না, প্রসেসরকে সর্বদা শাখাটি গ্রহণ করা হয়েছে বা নেওয়া হয়নি তা অনুমান করার জন্য জিসিসিতে কোনও উপায় নেই। আপনার কাছে যা আছে তা হ'ল _ বিল্টিন_ এক্সপেক্ট, যা অন্যেরা যা বলে তা করে does তদুপরি, আমি মনে করি আপনি শাখাটি সর্বদা নেওয়া হয় কি না তা প্রসেসরকে বলতে চান না । ইন্টেল আর্কিটেকচারের মতো আজকের প্রসেসরগুলি মোটামুটি জটিল নিদর্শনগুলি সনাক্ত করতে পারে এবং কার্যকরভাবে মানিয়ে নিতে পারে।

যাইহোক, এমন সময় আছে যেগুলি আপনি ডিফল্টরূপে কোনও শাখা গ্রহণের পূর্বাভাস দেওয়া হয়েছে কিনা তা নিয়ন্ত্রণ নিতে চান : আপনি যখন জানবেন শাখা প্রশাখার পরিসংখ্যানের ক্ষেত্রে কোডটি "ঠান্ডা" বলা হবে।

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

আর একটি উদাহরণ: আপনি নিজের ইনপুটকে শ্রেণিবদ্ধ করতে পারেন এবং কোডটিতে ঝাঁপিয়ে পড়তে পারেন যা আপনার শ্রেণিবিন্যাসের ফলাফলকে পরিচালনা করে। যদি অনেক শ্রেণিবিন্যাস থাকে তবে প্রসেসর পরিসংখ্যান সংগ্রহ করতে পারে তবে সেগুলি হারাতে পারে কারণ একই শ্রেণিবিন্যাস খুব শীঘ্রই ঘটে না এবং পূর্বাভাসের সংস্থানগুলি সম্প্রতি বলা কোডটিতে উত্সর্গীকৃত। আমি আশা করি প্রসেসরটিকে বলার জন্য কোনও আদিম মানুষ থাকবেন "দয়া করে এই কোডটিতে পূর্বাভাসের সংস্থানগুলি উত্সর্গ করবেন না" আপনি কখনও কখনও যেভাবে বলতে পারেন "এটি ক্যাশে করবেন না"।

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