অর্ডার দিয়ে কী প্রভাব পড়বে যদি… অন্যথায় যদি সম্ভাব্যতার দ্বারা বিবৃতি দেওয়া হয়?


187

বিশেষত, যদি আমার কাছে if... else ifবিবৃতিগুলির একটি সিরিজ থাকে এবং আমি একরকম আগেই জানতে পারি যে প্রতিটি বিবৃতি মূল্যায়ন করবে trueযেহেতু সম্ভাব্যতার ক্রম অনুসারে এগুলি সাজাতে কার্যকর করার সময় কতটা তফাত করে? উদাহরণস্বরূপ, আমি কি এটি পছন্দ করি:

if (highly_likely)
  //do something
else if (somewhat_likely)
  //do something
else if (unlikely)
  //do something

এই ?:

if (unlikely)
  //do something
else if (somewhat_likely)
  //do something
else if (highly_likely)
  //do something

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

সুতরাং, এটির পরীক্ষা নিরীক্ষা চলাকালীন আমি একটি নির্দিষ্ট মামলার জন্য আমার নিজের প্রশ্নের উত্তর দিয়ে শেষ করেছি, তবে আমি অন্যান্য মতামত / অন্তর্দৃষ্টিও শুনতে চাই।

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


35
আপনি একটি নোট যোগ করতে চাইতে পারেন
শর্তগুলি পরস্পরযুক্ত

28
এটি একটি আকর্ষণীয় আকর্ষণীয় প্রশ্নটি কীভাবে একটি ঘন্টার মধ্যে খারাপ উত্তর সহ 20+ আপগেট পেয়েছিল তা বেশ আকর্ষণীয়। ওপিতে কোনও কল না করা তবে আপভোটারদের ব্যান্ড ওয়াগনে ঝাঁপ দেওয়ার বিষয়ে সতর্ক হওয়া উচিত। প্রশ্ন আকর্ষণীয় হতে পারে, তবে ফলাফল সন্দেহজনক।
luk32

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

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

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

উত্তর:


96

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

এর পরে, শাখাটি একটি শাখার পূর্বাভাস ক্যাশে চলে যায় এবং অতীত আচরণ ভবিষ্যতের শাখার পূর্বাভাস জানাতে ব্যবহৃত হয়।

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

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

সুতরাং আপনার "শাখাগুলি" "প্রথম মুখোমুখি" থেকে সেরা শাখার পূর্বাভাস পাওয়ার সম্ভাবনা হ্রাসের ক্রমে আপনার শাখাগুলি অর্ডার করা উচিত।

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

তার উপরে, ভেক্টরাইজেশন এবং অন্যান্য অনেকগুলি অপ্টিমাইজেশন ক্ষুদ্র টাইট লুপগুলিতে প্রয়োগ হয়।

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

কিছু পরীক্ষাগুলি অন্যদের তুলনায় অনেক কম সস্তা হলে স্বাভাবিকভাবেই এগুলি সমস্ত উইন্ডোটির বাইরে চলে যায়।


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

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

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

44

আমি দুটি পৃথক if... else ifব্লক কার্যকর করার সময় নিম্নলিখিত পরীক্ষাগুলি তৈরি করেছি , একটি সম্ভাবনার ক্রম অনুসারে বাছাই করা হয়েছে, অন্যটি বিপরীত ক্রমে সাজানো হয়েছে:

#include <chrono>
#include <iostream>
#include <random>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

int main()
{
    long long sortedTime = 0;
    long long reverseTime = 0;

    for (int n = 0; n != 500; ++n)
    {
        //Generate a vector of 5000 random integers from 1 to 100
        random_device rnd_device;
        mt19937 rnd_engine(rnd_device());
        uniform_int_distribution<int> rnd_dist(1, 100);
        auto gen = std::bind(rnd_dist, rnd_engine);
        vector<int> rand_vec(5000);
        generate(begin(rand_vec), end(rand_vec), gen);

        volatile int nLow, nMid, nHigh;
        chrono::time_point<chrono::high_resolution_clock> start, end;

        //Sort the conditional statements in order of increasing likelyhood
        nLow = nMid = nHigh = 0;
        start = chrono::high_resolution_clock::now();
        for (int& i : rand_vec) {
            if (i >= 95) ++nHigh;               //Least likely branch
            else if (i < 20) ++nLow;
            else if (i >= 20 && i < 95) ++nMid; //Most likely branch
        }
        end = chrono::high_resolution_clock::now();
        reverseTime += chrono::duration_cast<chrono::nanoseconds>(end-start).count();

        //Sort the conditional statements in order of decreasing likelyhood
        nLow = nMid = nHigh = 0;
        start = chrono::high_resolution_clock::now();
        for (int& i : rand_vec) {
            if (i >= 20 && i < 95) ++nMid;  //Most likely branch
            else if (i < 20) ++nLow;
            else if (i >= 95) ++nHigh;      //Least likely branch
        }
        end = chrono::high_resolution_clock::now();
        sortedTime += chrono::duration_cast<chrono::nanoseconds>(end-start).count();

    }

    cout << "Percentage difference: " << 100 * (double(reverseTime) - double(sortedTime)) / double(sortedTime) << endl << endl;
}

MSVC2017 / O2 এর সাথে ব্যবহার করে ফলাফলগুলি দেখায় যে সাজানো সংস্করণটি অবিচ্ছিন্ন সংস্করণের চেয়ে ধারাবাহিকভাবে প্রায় 28% দ্রুত। লুক 32 এর মন্তব্যে, আমি দুটি পরীক্ষার ক্রমটিও স্যুইচ করেছি, যা একটি লক্ষণীয় পার্থক্য তৈরি করে (22% বনাম 28%)। কোডটি উইন্ডোজ 7 এর অধীনে একটি ইন্টেল জিয়ন ই 5-2697 ভি 2 তে চালিত হয়েছিল। এটি অবশ্যই খুব সমস্যা-নির্দিষ্ট এবং এটি একটি চূড়ান্ত উত্তর হিসাবে ব্যাখ্যা করা উচিত নয়।


9
যদিও ওপিকে সতর্ক হওয়া উচিত, কারণ একটি if... else ifবিবৃতি পরিবর্তন করা কীভাবে যুক্তির মাধ্যমে যুক্তির উপর দিয়ে প্রবাহিত হয় তার উপর যথেষ্ট প্রভাব ফেলতে পারে। unlikelyচেক প্রায়ই না আসতে পারে, কিন্তু একটি ব্যবসার জন্য চেক করতে হবে হতে পারে unlikelyপ্রথম অন্যদের জন্য পরীক্ষণ আগে শর্ত।
লুক টি ব্রুকস 15

21
30% দ্রুত? আপনি বোঝাতে চেয়েছিলেন যে এটি প্রায় অতিরিক্ত% দ্বারা দ্রুত ছিল যদি বিবৃতিগুলি সম্পাদন করতে না হয়? একটি দুর্দান্ত যুক্তিসঙ্গত ফলাফল বলে মনে হচ্ছে।
ইউকেমনকি

5
আপনি কিভাবে এটি মানদণ্ড করেছেন? কোন সংকলক, সিপিইউ, ইত্যাদি? আমি নিশ্চিত যে এই ফলাফলটি পোর্টেবল নয়।
luk32

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

6
এই মানদণ্ডটি খুব নির্ভরযোগ্য নয়। জিসিসি .3.৩.০ সহ সংকলন : g++ -O2 -march=native -std=c++14বাছাই করা শর্তাধীন বিবৃতিগুলিকে সামান্য প্রান্ত দেয়, তবে বেশিরভাগ সময়, দুটি রানের মধ্যে পার্থক্য ছিল ~ 5%। বেশ কয়েকবার, এটি আসলে ধীর ছিল (বৈকল্পের কারণে)। আমি মোটামুটি নিশ্চিত যে ifএর মতো অর্ডার দেওয়ার জন্য উদ্বেগ হওয়া উচিত নয়; পিজিও সম্ভবত এ জাতীয় কোনও মামলা পুরোপুরি পরিচালনা করবে
জাস্টিন

30

না আপনার উচিত হবে না, যদি না আপনি নিশ্চিত হন যে টার্গেট সিস্টেমটি প্রভাবিত হয়েছে। ডিফল্টরূপে পাঠযোগ্যতার দ্বারা যান।

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

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

আমি বলব যে শাখার অর্ডারিং অপ্টিমাইজেশনটি বেশ নাজুক এবং ক্ষুদ্রতর। এটি কেবলমাত্র কিছু সূক্ষ্ম সুরের পদক্ষেপ হিসাবে করুন।

কোড:

#include <chrono>
#include <iostream>
#include <random>
#include <algorithm>
#include <iterator>
#include <functional>

using namespace std;

int main()
{
    //Generate a vector of random integers from 1 to 100
    random_device rnd_device;
    mt19937 rnd_engine(rnd_device());
    uniform_int_distribution<int> rnd_dist(1, 100);
    auto gen = std::bind(rnd_dist, rnd_engine);
    vector<int> rand_vec(5000);
    generate(begin(rand_vec), end(rand_vec), gen);
    volatile int nLow, nMid, nHigh;

    //Count the number of values in each of three different ranges
    //Run the test a few times
    for (int n = 0; n != 10; ++n) {

        //Run the test again, but now sort the conditional statements in reverse-order of likelyhood
        {
          nLow = nMid = nHigh = 0;
          auto start = chrono::high_resolution_clock::now();
          for (int& i : rand_vec) {
              if (i >= 95) ++nHigh;               //Least likely branch
              else if (i < 20) ++nLow;
              else if (i >= 20 && i < 95) ++nMid; //Most likely branch
          }
          auto end = chrono::high_resolution_clock::now();
          cout << "Reverse-sorted: \t" << chrono::duration_cast<chrono::nanoseconds>(end-start).count() << "ns" << endl;
        }

        {
          //Sort the conditional statements in order of likelyhood
          nLow = nMid = nHigh = 0;
          auto start = chrono::high_resolution_clock::now();
          for (int& i : rand_vec) {
              if (i >= 20 && i < 95) ++nMid;  //Most likely branch
              else if (i < 20) ++nLow;
              else if (i >= 95) ++nHigh;      //Least likely branch
          }
          auto end = chrono::high_resolution_clock::now();
          cout << "Sorted:\t\t\t" << chrono::duration_cast<chrono::nanoseconds>(end-start).count() << "ns" << endl;
        }
        cout << endl;
    }
}

আমি আপনার কোড অনুসারে বাছাই করা এবং বিপরীত-সাজানো যদি-ব্লকের ক্রমটি স্যুইচ করি তখন আমি পারফরম্যান্সে একই ~ 30% পার্থক্য পাই। আমি নিশ্চিত নই যে কেন আইডিয়ন এবং কলিরু কোনও তফাত দেখায় না।
কার্লটন

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

যদি প্রশ্নটি হয় তবে এর প্রভাব কী? উত্তর হতে পারে না কোন !
পিজেট্রাইল

হা. তবে আমি মূল প্রশ্নের আপডেটের জন্য বিজ্ঞপ্তি পাই না। তারা উত্তর ফর্মুলেশন অপ্রচলিত তৈরি। দুঃখিত। আমি পরে বিষয়বস্তুটি সম্পাদনা করব, এটির মূল প্রশ্নের উত্তর দেওয়ার জন্য এবং কিছু ফলাফল দেখিয়েছি যা মূল বিষয়টি প্রমাণ করে proved
luk32

এটি পুনরাবৃত্তি করার মতো: "ডিফল্টরূপে পাঠযোগ্যতার দ্বারা যান।" পঠনযোগ্য কোড রচনাগুলি প্রায়শই আপনাকে আপনার কোডকে পার্স করার পক্ষে আরও কঠিন করে কোডের (নিখুঁত শর্তে) একটি ক্ষুদ্র পারফরম্যান্স বৃদ্ধির চেষ্টা করার চেয়ে ভাল ফলাফল পাবে।
অ্যান্ড্রু ব্রাজা

26

শুধু আমার 5 সেন্ট। বিবৃতিগুলির উপর নির্ভর করা উচিত কিনা এটি অর্ডার করার প্রভাব বলে মনে হচ্ছে:

  1. বিবৃতি যদি প্রতিটি সম্ভাবনা।

  2. পুনরাবৃত্তির সংখ্যা, যাতে শাখার ভবিষ্যদ্বাণী কিক করতে পারে।

  3. সম্ভবত / অসম্ভব সংকলক ইঙ্গিতগুলি, অর্থাত্ কোড বিন্যাস।

এই কারণগুলি অন্বেষণ করতে, আমি নিম্নলিখিত ফাংশনগুলিকে মানি:

ordered_ifs ()

for (i = 0; i < data_sz * 1024; i++) {
    if (data[i] < check_point) // highly likely
        s += 3;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (data[i] == check_point) // very unlikely
        s += 1;
}

reversed_ifs ()

for (i = 0; i < data_sz * 1024; i++) {
    if (data[i] == check_point) // very unlikely
        s += 1;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (data[i] < check_point) // highly likely
        s += 3;
}

ordered_ifs_with_hints ()

for (i = 0; i < data_sz * 1024; i++) {
    if (likely(data[i] < check_point)) // highly likely
        s += 3;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (unlikely(data[i] == check_point)) // very unlikely
        s += 1;
}

reversed_ifs_with_hints ()

for (i = 0; i < data_sz * 1024; i++) {
    if (unlikely(data[i] == check_point)) // very unlikely
        s += 1;
    else if (data[i] > check_point) // samewhat likely
        s += 2;
    else if (likely(data[i] < check_point)) // highly likely
        s += 3;
}

উপাত্ত

ডেটা অ্যারেতে 0 এবং 100 এর মধ্যে এলোমেলো সংখ্যা রয়েছে:

const int RANGE_MAX = 100;
uint8_t data[DATA_MAX * 1024];

static void data_init(int data_sz)
{
    int i;
        srand(0);
    for (i = 0; i < data_sz * 1024; i++)
        data[i] = rand() % RANGE_MAX;
}

ফলাফলগুলো

নিম্নলিখিত ফলাফলগুলি ইন্টেল আই 5 @ 3,2 গিগাহার্টজ এবং জি ++ 6.3.0 এর জন্য। প্রথম যুক্তিটি হ'ল চেকপয়েন্ট (অর্থাত্ সম্ভাব্য% স্টেটমেন্টের ক্ষেত্রে সম্ভাব্য% যদি সম্ভাব্যতা থাকে), দ্বিতীয় আর্গুমেন্টটি ডেটা_স্জ (অর্থাত্ পুনরাবৃত্তির সংখ্যা)।

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
ordered_ifs/50/8                   25636 ns      25635 ns      27852
ordered_ifs/75/4                    4326 ns       4325 ns     162613
ordered_ifs/75/8                   18242 ns      18242 ns      37931
ordered_ifs/100/4                   1673 ns       1673 ns     417073
ordered_ifs/100/8                   3381 ns       3381 ns     207612
reversed_ifs/50/4                   5342 ns       5341 ns     126800
reversed_ifs/50/8                  26050 ns      26050 ns      26894
reversed_ifs/75/4                   3616 ns       3616 ns     193130
reversed_ifs/75/8                  15697 ns      15696 ns      44618
reversed_ifs/100/4                  3738 ns       3738 ns     188087
reversed_ifs/100/8                  7476 ns       7476 ns      93752
ordered_ifs_with_hints/50/4         5551 ns       5551 ns     125160
ordered_ifs_with_hints/50/8        23191 ns      23190 ns      30028
ordered_ifs_with_hints/75/4         3165 ns       3165 ns     218492
ordered_ifs_with_hints/75/8        13785 ns      13785 ns      50574
ordered_ifs_with_hints/100/4        1575 ns       1575 ns     437687
ordered_ifs_with_hints/100/8        3130 ns       3130 ns     221205
reversed_ifs_with_hints/50/4        6573 ns       6572 ns     105629
reversed_ifs_with_hints/50/8       27351 ns      27351 ns      25568
reversed_ifs_with_hints/75/4        3537 ns       3537 ns     197470
reversed_ifs_with_hints/75/8       16130 ns      16130 ns      43279
reversed_ifs_with_hints/100/4       3737 ns       3737 ns     187583
reversed_ifs_with_hints/100/8       7446 ns       7446 ns      93782

বিশ্লেষণ

অর্ডারিংয়ের বিষয়টি গুরুত্বপূর্ণ

4K পুনরাবৃত্তির জন্য এবং (প্রায়) 100% খুব পছন্দ করা বক্তব্যটির সম্ভাবনাটি পার্থক্যটি বিশাল 223%:

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/100/4                   1673 ns       1673 ns     417073
reversed_ifs/100/4                  3738 ns       3738 ns     188087

4K পুনরাবৃত্তির জন্য এবং অত্যন্ত পছন্দিত বক্তব্যের 50% সম্ভাবনার জন্য পার্থক্যটি প্রায় 14%:

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
reversed_ifs/50/4                   5342 ns       5341 ns     126800

2. পরিসংখ্যানগুলির সংখ্যা সংখ্যা

4K এবং 8K পুনরাবৃত্তির মধ্যে পার্থক্যটি (প্রায়) 100% সম্ভাব্যতার পক্ষে অত্যন্ত পছন্দ হওয়া বক্তব্যটির প্রায় দ্বিগুণ (যেমন প্রত্যাশিত):

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/100/4                   1673 ns       1673 ns     417073
ordered_ifs/100/8                   3381 ns       3381 ns     207612

তবে অত্যন্ত পছন্দ করা স্টেটমেন্টের 50% সম্ভাবনার জন্য 4K এবং 8K পুনরাবৃত্তির মধ্যে পার্থক্য 5,5 বার:

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
ordered_ifs/50/8                   25636 ns      25635 ns      27852

কেন এমন হয়? কারণ শাখার ভবিষ্যদ্বাণী মিস করে। এখানে উল্লিখিত প্রতিটি ক্ষেত্রে শাখাটি মিস করেছে:

ordered_ifs/100/4    0.01% of branch-misses
ordered_ifs/100/8    0.01% of branch-misses
ordered_ifs/50/4     3.18% of branch-misses
ordered_ifs/50/8     15.22% of branch-misses

সুতরাং আমার আই 5-তে শাখার ভবিষ্যদ্বাণীটি সম্ভাব্য নয় এমন শাখা এবং বড় ডেটা সেটগুলির জন্য দর্শনীয়ভাবে ব্যর্থ।

৩. ইঙ্গিতগুলি একটি বিটকে সহায়তা করে

4 কে পুনরাবৃত্তির জন্য ফলাফলগুলি 50% সম্ভাবনার জন্য কিছুটা খারাপ এবং 100% সম্ভাব্যতার জন্য কিছুটা ভাল:

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/4                    4660 ns       4658 ns     150948
ordered_ifs/100/4                   1673 ns       1673 ns     417073
ordered_ifs_with_hints/50/4         5551 ns       5551 ns     125160
ordered_ifs_with_hints/100/4        1575 ns       1575 ns     437687

তবে 8 কে পুনরাবৃত্তির জন্য ফলাফলগুলি সর্বদা কিছুটা ভাল থাকে:

---------------------------------------------------------------------
Benchmark                              Time           CPU Iterations
---------------------------------------------------------------------
ordered_ifs/50/8                   25636 ns      25635 ns      27852
ordered_ifs/100/8                   3381 ns       3381 ns     207612
ordered_ifs_with_hints/50/8        23191 ns      23190 ns      30028
ordered_ifs_with_hints/100/8        3130 ns       3130 ns     221205

সুতরাং, ইঙ্গিতগুলিও সহায়তা করে তবে একটি সামান্য সামান্য।

সামগ্রিক উপসংহারটি হ'ল: সর্বদা কোডটি বেঞ্চমার্ক করুন কারণ ফলাফলটি অবাক করে দিতে পারে।

আশা করি এইটি কাজ করবে.


1
আই 5 নেহালেম? আই 5 স্কাইলেকে? শুধু "আই 5" বলা খুব নির্দিষ্ট নয়। এছাড়াও, আমি ধরে নিয়েছি আপনি ব্যবহার করেছেন g++ -O2বা -O3 -fno-tree-vectorize, তবে আপনার এটি বলা উচিত।
পিটার

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

1
শাখার ভবিষ্যদ্বাণীকারী 4K ইনপুট ডেটা আকারে এমনকি ভালভাবে ভবিষ্যদ্বাণী করতে সক্ষম হ'ল, অর্থাত্, হাজারে একটি সময়কালে একটি লুপ জুড়ে শাখার ফলাফলগুলি স্মরণ করে বেঞ্চমার্ককে "ব্রেক" করতে সক্ষম হ'ল আধুনিক শক্তিটির প্রমাণ শাখা ভবিষ্যদ্বাণী। মনে রাখবেন যে ভবিষ্যদ্বাণীকারীরা কিছু ক্ষেত্রে প্রান্তিককরণের মতো বিষয়ে বেশ সংবেদনশীল, তাই কিছু পরিবর্তন সম্পর্কে দৃ strong় সিদ্ধান্ত নেওয়া শক্ত। উদাহরণস্বরূপ, আপনি বিভিন্ন ক্ষেত্রে ইঙ্গিতটির জন্য বিপরীত আচরণ লক্ষ্য করেছেন তবে এটি ইঙ্গিতটি এলোমেলোভাবে কোড লেআউট পরিবর্তন করে যা ভবিষ্যদ্বাণীকে প্রভাবিত করেছিল তা দ্বারা ব্যাখ্যা করা যেতে পারে।
BeeOnRope

1
@ পিটারকর্ডস আমার মূল বিষয়টি হ'ল আমরা যখন পরিবর্তনের ফলাফল সম্পর্কে পূর্বাভাস দেওয়ার চেষ্টা করতে পারি, তবুও আমরা পরিবর্তনের আগে এবং পরে পারফরম্যান্সটি আরও ভালভাবে পরিমাপ করতে পারি ... এবং আপনি ঠিক বলেছেন, আমার উল্লেখ করা উচিত ছিল যে এটি -O3 এবং প্রসেসরের সাথে অনুকূল হয়েছিল was i5-4460 @ 3.20GHz
Andriy Berestovskyy

19

এখানে অন্যান্য কয়েকটি উত্তরের ভিত্তিতে দেখে মনে হচ্ছে একমাত্র আসল উত্তর: এটি নির্ভর করে । এটি অন্তত নিম্নলিখিতটির উপর নির্ভর করে (যদিও এই ক্রমের গুরুত্বপূর্নভাবে নয়):

  • প্রতিটি শাখার আপেক্ষিক সম্ভাবনা। এটিই মূল প্রশ্নটি জিজ্ঞাসা করা হয়েছিল। বিদ্যমান উত্তরের উপর ভিত্তি করে, এমন কিছু শর্ত রয়েছে বলে মনে হয় যার অধীনে সম্ভাব্যতার ক্রমটি অর্ডার করা সহায়তা করে, তবে এটি সর্বদা তেমনটি হয় না বলে মনে হয়। যদি আপেক্ষিক সম্ভাবনাগুলি খুব আলাদা না হয় তবে তারা কোন অর্ডারে রয়েছে তা নিয়ে কোনও পার্থক্য হওয়ার সম্ভাবনা নেই However তবে, যদি প্রথম শর্তটি 99.999% সময়ের হয় এবং পরেরটিটি যা বাকী থাকে তার একটি ভগ্নাংশ হয়, তবে আমি চাই ধরে নিন যে সবচেয়ে সম্ভবত একটি স্থাপন করা সময়োপযোগের ক্ষেত্রে উপকারী হবে।
  • প্রতিটি শাখার জন্য সত্য / মিথ্যা শর্ত গণনা করার ব্যয়। যদি শর্তগুলির পরীক্ষার সময় ব্যয় অন্য শাখার তুলনায় অন্য শাখার পক্ষে সত্যই বেশি হয়, তবে এটির সময় এবং দক্ষতার উপর উল্লেখযোগ্য প্রভাব পড়ার সম্ভাবনা রয়েছে। উদাহরণস্বরূপ, এমন একটি শর্ত বিবেচনা করুন যা গণনা করতে 1 টাইম ইউনিট নেয় (উদাহরণস্বরূপ, বুলিয়ান ভেরিয়েবলের অবস্থা পরীক্ষা করা) বনাম অন্য শর্তের তুলনায় দশ, শত, হাজার, এমনকি কয়েক মিলিয়ন সময় ইউনিট নিরূপণ করতে লাগে (যেমন, এর সামগ্রীগুলি পরীক্ষা করে ডিস্কে থাকা কোনও ফাইল বা একটি বৃহত ডাটাবেসের বিপরীতে একটি জটিল এসকিউএল কোয়েরি সম্পাদন)। কোডটি প্রত্যেকবার শর্তাবলী যথাযথভাবে পরীক্ষা করে নিছে তা দ্রুত গ্রহণ করা শর্তগুলি সম্ভবত প্রথম হওয়া উচিত (যদি না তারা প্রথমে ব্যর্থ অন্যান্য শর্তের উপর নির্ভর করে)।
  • সংকলক / দোভাষী কিছু সংকলক (বা দোভাষী) পারফরম্যান্সকে প্রভাবিত করতে পারে এমন এক ধরণের অপ্টিমাইজেশন অন্তর্ভুক্ত করতে পারে (এবং এর কয়েকটি কেবল তখনই উপস্থিত থাকে যদি সংকলন এবং / বা সম্পাদনের সময় নির্দিষ্ট বিকল্পগুলি নির্বাচিত হয়)। সুতরাং যদি না আপনি দুটি সংকলন এবং একই সিস্টেমের অন্যথায় অভিন্ন কোডের মৃত্যুদন্ড কার্যকর না করে একই একই সংকলকটি ব্যবহার করেন যেখানে কেবলমাত্র পার্থক্যটি প্রশ্নযুক্ত শাখার ক্রম হয়, আপনাকে সংকলক পরিবর্তনের জন্য কিছুটা ছাড় দিতে হবে।
  • অপারেটিং সিস্টেম / হার্ডওয়্যার যেমন luk32 এবং ইয়াক দ্বারা উল্লিখিত হয়েছে, বিভিন্ন সিপিইউগুলির নিজস্ব অপ্টিমাইজেশন রয়েছে (যেমন অপারেটিং সিস্টেমগুলিও)। সুতরাং বেঞ্চমার্কগুলি আবার এখানে পরিবর্তনের পক্ষে সংবেদনশীল।
  • কোড ব্লক কার্যকরকরণের ফ্রিকোয়েন্সি যদি শাখাগুলির অন্তর্ভুক্ত ব্লকটি খুব কমই অ্যাক্সেস করা হয় (যেমন, শুধুমাত্র একবার প্রারম্ভকালে), তবে আপনি সম্ভবত শাখাগুলি কী অর্ডার করেছেন তা খুব সামান্যই গুরুত্বপূর্ণ matters অন্যদিকে, যদি আপনার কোডের একটি সমালোচনামূলক অংশের সময় যদি এই কোড ব্লকটিতে আপনার কোডটি হাতুড়ি হয়ে থাকে, তবে অর্ডার দেওয়ার ক্ষেত্রে অনেক কিছুই আসতে পারে (বেঞ্চমার্কের উপর নির্ভর করে)।

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

আমার থাম্বের ব্যক্তিগত নিয়ম (বেশিরভাগ ক্ষেত্রে, একটি বেঞ্চমার্কের অভাবে) এর ভিত্তিতে অর্ডার করতে হয়:

  1. পূর্ববর্তী শর্তগুলির ফলাফলের উপর নির্ভরশীল শর্তাদি,
  2. শর্তের গণনা ব্যয়, তারপরে
  3. প্রতিটি শাখার আপেক্ষিক সম্ভাবনা।

13

উচ্চ-পারফরম্যান্স কোডের জন্য আমি সাধারণত যেভাবে সমাধান করেছি তা হ'ল সর্বাধিক পঠনযোগ্য অর্ডারটি রাখা, তবে সংকলককে ইঙ্গিত সরবরাহ করা। লিনাক্স কার্নেলের একটি উদাহরণ এখানে :

if (likely(access_ok(VERIFY_READ, from, n))) {
    kasan_check_write(to, n);
    res = raw_copy_from_user(to, from, n);
}
if (unlikely(res))
    memset(to + (n - res), 0, res);

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

এই ম্যাক্রোগুলির লিনাক্স বাস্তবায়ন জিসিসির নির্দিষ্ট বৈশিষ্ট্য ব্যবহার করে । দেখে মনে হচ্ছে ঝনঝন এবং ইন্টেল সি সংকলক একই সিনট্যাক্স সমর্থন করে তবে এমএসভিসির তেমন বৈশিষ্ট্য নেই


4
এটি কীভাবে আপনি likely()এবং unlikely()ম্যাক্রোগুলি সংজ্ঞায়িত করা যায় এবং সংশ্লিষ্ট সংকলক বৈশিষ্ট্য সম্পর্কে কিছু তথ্য অন্তর্ভুক্ত করতে পারলে এটি আরও সহায়ক হবে helpful
নেট এল্ডারেজ

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

@ হ্যাগেভনএইটজেন হুম, হ্যাঁ, এটি একটি ভাল বিষয়, else ifশর্তগুলি পরস্পর একচেটিয়া কিনা তা জানতে কম্পাইলার যদি যথেষ্ট স্মার্ট না হয় তবে এটি ক্রমকে প্রভাবিত করতে পারে না ।
jpa

7

আপনার সংকলক এবং আপনি যে প্ল্যাটফর্মটি সংকলন করছেন তার উপরও নির্ভর করে।

তত্ত্ব অনুসারে, সর্বাধিক সম্ভাব্য অবস্থার নিয়ন্ত্রণ নিয়ন্ত্রণ যতটা সম্ভব কম করা উচিত।

সাধারণত সবচেয়ে সম্ভবত শর্তটি প্রথম হওয়া উচিত:

if (most_likely) {
     // most likely instructions
} else 

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

jump to ELSE if not(most_likely)
// most likely instructions
jump to end
ELSE:

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


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

1
আমি "না (সর্বাধিক_সভা)" রেখেছি তাই যদি বেশিরভাগই যদি সত্য হয় তবে নিয়ন্ত্রণটি লাফানো ছাড়াই চলে যাবে।
NoImaginationGuy

1
"সর্বাধিক জনপ্রিয় এএসএম শর্তাধীন শাখাগুলির উপর ভিত্তি করে যা শর্ত সত্য হলে লাফিয়ে যায়" .. কোন আইএসএ হবে? এটি অবশ্যই x86 বা আর্মের পক্ষে সত্য নয়। মৌলিক এআরএম সিপিইউ (এবং খুবই প্রাচীন এক্স 86 বেশী, এমনকি জটিল BPS জন্য তারা সাধারণত এখনও ধৃষ্টতা দিয়ে শুরু এবং তারপর খাপ খাওয়ানো) শাখা predictor ধরে নেয় যে একটা ফরওয়ার্ড শাখা জন্যে রয়েছে জাহান্নামের না নেয়া এবং পিছনের দিকে শাখা সবসময় হয়, তাই দাবির বিপরীত সত্য.
ভু

1
যে সংকলকগুলি আমি বেশিরভাগ ক্ষেত্রে চেষ্টা করেছি তারা সাধারণ পরীক্ষার জন্য উপরে উল্লিখিত পদ্ধতির ব্যবহার করে। নোট করুন যে clangপ্রকৃতপক্ষে test2এবং এর জন্য একটি পৃথক পদ্ধতি গ্রহণ করেছে test3: হিউরিস্টিক্সের কারণে যেটি ইঙ্গিত দেয় যে একটি < 0বা == 0পরীক্ষাটি ভুল হতে পারে, তাই এটি উভয় পথে ফাংশনের বাকী অংশটি ক্লোন করার সিদ্ধান্ত নিয়েছে, সুতরাং এটি condition == falseপতনের পথটি তৈরি করতে সক্ষম হয় । এটি কেবলমাত্র কার্যকর কারণ ফাংশনটির বাকী অংশটি সংক্ষিপ্ত: test4আমি আরও একটি অপারেশন যুক্ত করেছি এবং এটি উপরে বর্ণিত পদ্ধতির কাছে ফিরে এসেছি।
BeeOnRope

1
@ আর্নভোগেল - সঠিকভাবে পূর্বাভাস নেওয়া নেওয়া শাখাগুলি আধুনিক সিপিইউগুলিতে পাইপলাইন পুরোপুরি স্টল করে না তবে সেগুলি গ্রহণ না করা থেকে প্রায়শই উল্লেখযোগ্যভাবে খারাপ হয়: (1) তারা বোঝায় যে নিয়ন্ত্রণ প্রবাহটি সামঞ্জস্যপূর্ণ নয় তাই বাকি নির্দেশাবলীর পরে jmpনয় কার্যকর তাই আনতে / ডিকোড ব্যান্ডউইথটি নষ্ট হয় (2) এমনকি আধুনিক বড় কোর কেবল চক্রের জন্য একটি আনতে পারে তাই এটি 1 নেওয়া শাখা / চক্রের একটি সীমাবদ্ধতা রাখে (OTOH আধুনিক ইন্টেল 2 না-নেওয়া / চক্র করতে পারে) (3 )
নিয়মিত

6

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

mingw32-g ++। exe -O3 -Wall -std = c ++ 11 -পরিবর্তন -জি

vector<int> rand_vec(10000000);

জিসিসি উভয় মূল কোডে একই রূপান্তর করেছে।

মনে রাখবেন যে কেবলমাত্র দুটি প্রথম শর্তটি তৃতীয় হিসাবে সর্বদা সত্য হিসাবে পরীক্ষা করা উচিত, জিসিসি এখানে এক ধরণের শার্লক।

বিপরীত

.L233:
        mov     DWORD PTR [rsp+104], 0
        mov     DWORD PTR [rsp+100], 0
        mov     DWORD PTR [rsp+96], 0
        call    std::chrono::_V2::system_clock::now()
        mov     rbp, rax
        mov     rax, QWORD PTR [rsp+8]
        jmp     .L219
.L293:
        mov     edx, DWORD PTR [rsp+104]
        add     edx, 1
        mov     DWORD PTR [rsp+104], edx
.L217:
        add     rax, 4
        cmp     r14, rax
        je      .L292
.L219:
        mov     edx, DWORD PTR [rax]
        cmp     edx, 94
        jg      .L293 // >= 95
        cmp     edx, 19
        jg      .L218 // >= 20
        mov     edx, DWORD PTR [rsp+96]
        add     rax, 4
        add     edx, 1 // < 20 Sherlock
        mov     DWORD PTR [rsp+96], edx
        cmp     r14, rax
        jne     .L219
.L292:
        call    std::chrono::_V2::system_clock::now()

.L218: // further down
        mov     edx, DWORD PTR [rsp+100]
        add     edx, 1
        mov     DWORD PTR [rsp+100], edx
        jmp     .L217

And sorted

        mov     DWORD PTR [rsp+104], 0
        mov     DWORD PTR [rsp+100], 0
        mov     DWORD PTR [rsp+96], 0
        call    std::chrono::_V2::system_clock::now()
        mov     rbp, rax
        mov     rax, QWORD PTR [rsp+8]
        jmp     .L226
.L296:
        mov     edx, DWORD PTR [rsp+100]
        add     edx, 1
        mov     DWORD PTR [rsp+100], edx
.L224:
        add     rax, 4
        cmp     r14, rax
        je      .L295
.L226:
        mov     edx, DWORD PTR [rax]
        lea     ecx, [rdx-20]
        cmp     ecx, 74
        jbe     .L296
        cmp     edx, 19
        jle     .L297
        mov     edx, DWORD PTR [rsp+104]
        add     rax, 4
        add     edx, 1
        mov     DWORD PTR [rsp+104], edx
        cmp     r14, rax
        jne     .L226
.L295:
        call    std::chrono::_V2::system_clock::now()

.L297: // further down
        mov     edx, DWORD PTR [rsp+96]
        add     edx, 1
        mov     DWORD PTR [rsp+96], edx
        jmp     .L224

সুতরাং এটি শেষের ক্ষেত্রে কোনও শাখার পূর্বাভাসের প্রয়োজন হয় না তা ছাড়া আমাদের বেশি কিছু বলে না।

এখন আমি if এর সমস্ত 6 টি সমন্বয় চেষ্টা করেছি, শীর্ষ 2 টি মূল বিপরীত এবং সাজানো হয়েছে। উচ্চ>> = 95, কম হ'ল <20, মাঝের প্রতিটি 10000000 পুনরাবৃত্তি সহ 20-94।

high, low, mid: 43000000ns
mid, low, high: 46000000ns
high, mid, low: 45000000ns
low, mid, high: 44000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns

high, low, mid: 44000000ns
mid, low, high: 47000000ns
high, mid, low: 44000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 45000000ns

high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 44000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns

high, low, mid: 42000000ns
mid, low, high: 46000000ns
high, mid, low: 46000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 43000000ns

high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 44000000ns
low, mid, high: 44000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns

high, low, mid: 43000000ns
mid, low, high: 48000000ns
high, mid, low: 44000000ns
low, mid, high: 44000000ns
mid, high, low: 45000000ns
low, high, mid: 45000000ns

high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 45000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns

high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 45000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns

high, low, mid: 43000000ns
mid, low, high: 46000000ns
high, mid, low: 45000000ns
low, mid, high: 45000000ns
mid, high, low: 45000000ns
low, high, mid: 44000000ns

high, low, mid: 42000000ns
mid, low, high: 46000000ns
high, mid, low: 44000000ns
low, mid, high: 45000000ns
mid, high, low: 45000000ns
low, high, mid: 44000000ns

1900020, 7498968, 601012

Process returned 0 (0x0)   execution time : 2.899 s
Press any key to continue.

তাহলে কেন ক্রমটি উচ্চ, নিম্ন, মধ্যবর্তী তবে দ্রুত (প্রান্তিক)

কারণ সবচেয়ে অপ্রত্যাশিত শেষ এবং তাই কোনও শাখার ভবিষ্যদ্বাণীকের মাধ্যমে কখনও চালিত হয় না।

          if (i >= 95) ++nHigh;               // most predictable with 94% taken
          else if (i < 20) ++nLow; // (94-19)/94% taken ~80% taken
          else if (i >= 20 && i < 95) ++nMid; // never taken as this is the remainder of the outfalls.

সুতরাং শাখাগুলি নেওয়া, নেওয়া এবং এর সাথে বাকী অংশের পূর্বাভাস দেওয়া হবে

6% + (0.94 *) 20% মিসপ্রেডিক্টস।

"সাজানো"

          if (i >= 20 && i < 95) ++nMid;  // 75% not taken
          else if (i < 20) ++nLow;        // 19/25 76% not taken
          else if (i >= 95) ++nHigh;      //Least likely branch

শাখাগুলি নেওয়া হয়নি, নেওয়া হয়নি এবং শার্লক নিয়ে ভবিষ্যদ্বাণী করা হবে।

25% + (0.75 *) 24% ভুল ধারণা

18-23% পার্থক্য দেওয়া (~ 9% এর পরিমাপযুক্ত পার্থক্য) তবে আমাদের ভুল অনুমানের পরিবর্তে চক্র গণনা করতে হবে।

আসুন ধরে নিই যে আমার নেহালেম সিপিইউতে 17 টি চক্রের ভুল অনুমানের জরিমানা রয়েছে এবং প্রতিটি চেক ইস্যু করতে 1 চক্র লাগে (4-5 নির্দেশ) এবং লুপটিও একটি চক্র নেয়। ডেটা নির্ভরতা হ'ল কাউন্টার এবং লুপ ভেরিয়েবলগুলি, তবে একবারের ভুল প্রভাবগুলি সময়সীমার উপর প্রভাব ফেলতে না পারে out

সুতরাং "বিপরীত" জন্য, আমরা সময়গুলি পাই (এটি কম্পিউটার আর্কিটেকচারে ব্যবহৃত সূত্র হওয়া উচিত: একটি কোয়ান্টেটিভেটিভ অ্যাপ্রোচ আইআইআরসি)।

mispredict*penalty+count+loop
0.06*17+1+1+    (=3.02)
(propability)*(first check+mispredict*penalty+count+loop)
(0.19)*(1+0.20*17+1+1)+  (= 0.19*6.4=1.22)
(propability)*(first check+second check+count+loop)
(0.75)*(1+1+1+1) (=3)
= 7.24 cycles per iteration

এবং "সাজানো" এর জন্য একই

0.25*17+1+1+ (=6.25)
(1-0.75)*(1+0.24*17+1+1)+ (=.25*7.08=1.77)
(1-0.75-0.19)*(1+1+1+1)  (= 0.06*4=0.24)
= 8.26

(8.26-7.24) /8.26 = 13.8% বনাম ~ 9% পরিমাপ করা (মাপার কাছাকাছি!?!)।

সুতরাং ওপি স্পষ্টভাবে স্পষ্ট নয়।

এই পরীক্ষাগুলির সাহায্যে আরও জটিল কোড বা আরও ডেটা নির্ভরতা সহ অন্যান্য পরীক্ষা অবশ্যই আলাদা হবে তাই আপনার কেসটি পরিমাপ করুন।

পরীক্ষার ক্রম পরিবর্তন করার ফলে ফলাফলগুলি পরিবর্তিত হয়েছে তবে লুপ শুরুর বিভিন্ন প্রান্তিককরণের কারণ হতে পারে যা আদর্শভাবে সমস্ত নতুন ইনটেল সিপিইউতে 16 বাইট হওয়া উচিত তবে এই ক্ষেত্রে নয়।


4

আপনার পছন্দসই যৌক্তিক ক্রমে এগুলি রাখুন। অবশ্যই, শাখাটি ধীর হতে পারে, তবে শাখা প্রশাখাগুলি আপনার কম্পিউটারের বেশিরভাগ কাজ করে না।

আপনি যদি কোডের পারফরম্যান্সের সমালোচনামূলক অংশে কাজ করছেন, তবে অবশ্যই লজিকাল অর্ডার, প্রোফাইল গাইডেড অপ্টিমাইজেশন এবং অন্যান্য কৌশলগুলি ব্যবহার করুন তবে সাধারণ কোডের জন্য, আমি মনে করি এটি একটি স্টাইলিস্টিক পছন্দ হিসাবে সত্যই বেশি।


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

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

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

3

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

অমীমাংসিত পদ্ধতিতে সংকলক অযৌক্তিকভাবে সমস্ত শর্তাদি পরীক্ষা করবে এবং সময় নিবে।

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