c++ - কেন আমি গতি পরিবর্তে মাপের জন্য অপ্টিমাইজ করলে জিএসসি 15-20% দ্রুত কোড তৈরি করে?




performance gcc (4)

আমার সহকর্মী আমাকে আমার প্রশ্নের একটি সম্ভাব্য উত্তর খুঁজে পেতে সাহায্য করেছে। তিনি 256 বাইট সীমানা গুরুত্ব লক্ষ্য। তিনি এখানে নিবন্ধিত নন এবং নিজেকে উত্তর দেওয়ার জন্য আমাকে উত্সাহিত করেছেন (এবং সমস্ত খ্যাতি গ্রহণ করুন)।

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

এই প্যাডিং যে অপরাধী হয় এই ক্ষেত্রে? কেন এবং কিভাবে?

এটা সব সারিবদ্ধ নিচে boils। -falign-* কার্য সম্পাদনের উপর একটি উল্লেখযোগ্য প্রভাব ফেলতে পারে, সেইজন্য আমাদের কাছে -falign-* পতাকাগুলি প্রথম স্থানে রয়েছে।

আমি একটি gcc ডেভেলপারদের একটি (বোগাস?) বাগ রিপোর্ট জমা আছে। ডিফল্ট আচরণটি হল " ডিফল্টভাবে আমরা 8 বাইটে লুপগুলি সারিবদ্ধ করি তবে 16 বাইটে এটিকে সাইন করতে চেষ্টা করুন যদি আমাদের 10 বাইট বেশি পূরণ করতে হয় না।" দৃশ্যত, এই ডিফল্ট এই বিশেষ ক্ষেত্রে এবং আমার মেশিনে সেরা পছন্দ নয়। -O3 3.4 (ট্রাঙ্ক) -O3 সাথে যথাযথ সারিবদ্ধকরণ এবং জেনারেট কোডটি এই অদ্ভুত আচরণটি প্রদর্শন করে না।

অবশ্যই, যদি একটি অনুপযুক্ত সারিবদ্ধ কাজ করা হয় তবে এটি আরও খারাপ করে তোলে। একটি অপ্রয়োজনীয় / খারাপ সারিবদ্ধতা কোন কারণে শুধুমাত্র বাইট খায় এবং সম্ভাব্য ক্যাশে মিস ইত্যাদি বৃদ্ধি করে।

গোলমাল এটি বেশ অনেক সময় তোলে মাইক্রো অপ্টিমাইজেশান সময় অসম্ভব।

সি অথবা সি ++ সোর্স কোডগুলিতে মাইক্রো-অপ্টিমাইজেশানগুলি (অ্যালাইনমেন্ট স্ট্যাকের সাথে সম্পর্কযুক্ত) করার সময় এই ধরনের দুর্ঘটনাজনিত ভাগ্যবান / অপ্রত্যাশিত সারিবদ্ধতাগুলি কীভাবে হস্তক্ষেপ করে না তা আমি কীভাবে নিশ্চিত করতে পারি?

শুধু সঠিক alignment করতে gcc বলার দ্বারা:

g++ -O2 -falign-functions=16 -falign-loops=16

দীর্ঘ উত্তর:

কোড ধীর চলবে যদি:

  • একটি XX বাইট সীমানা মধ্যম () XX মেশিন নির্ভরশীল) যোগ করুন।

  • যদি add() করার add() কল add() একটি XX বাইট সীমানা উপর লাফ দিতে হয় এবং লক্ষ্য সংলগ্ন হয় না।

  • যদি add() সংযুক্ত না হয়।

  • যদি লুপ সংকীর্ণ হয় না।

প্রথম 2 কোডগুলিতে সুন্দরভাবে দৃশ্যমান এবং মারাত দখান দয়া করে পোস্ট করেছেন । এই ক্ষেত্রে, gcc-4.8.1 -Os ( gcc-4.8.1 -Os সেকেন্ডে সঞ্চালিত হয়):

00000000004004fd <_ZL3addRKiS0_.isra.0>:
  4004fd:       8d 04 37                lea    eax,[rdi+rsi*1]
  400500:       c3   

একটি 256 বাইট সীমানা কাটা add() মাঝখানে ডান এবং না add() না লুপ একত্রিত করা হয়। বিস্মিত, অবাক, এই ধীরতম কেস!

যদি gcc-4.7.3 -Os (0.8২২ সেকেন্ডে সঞ্চালিত হয়), 256 বাইট সীমাটি শুধুমাত্র একটি ঠান্ডা অংশে (তবে লুপও না বা যোগও add() কাটা হয়):

00000000004004fa <_ZL3addRKiS0_.isra.0>:
  4004fa:       8d 04 37                lea    eax,[rdi+rsi*1]
  4004fd:       c3                      ret

[...]

  40051a:       e8 db ff ff ff          call   4004fa <_ZL3addRKiS0_.isra.0>

কিছুই সংলগ্ন হয় না, এবং add() করার add() কল add() 256 বাইট সীমানা উপর লাফ দিতে হয়েছে। এই কোড দ্বিতীয় ধীরতম।

যদি gcc-4.6.4 -Os (0.709 সেকেন্ডে সঞ্চালিত হয়) ক্ষেত্রে, যদিও কিছুই সংলগ্ন থাকে না, তবে add() করার add() কলটি 256 বাইট সীমারেখার উপরে লাফ দিতে হবে না এবং লক্ষ্য ঠিক 32 বিট দূরে:

  4004f2:       e8 db ff ff ff          call   4004d2 <_ZL3addRKiS0_.isra.0>
  4004f7:       01 c3                   add    ebx,eax
  4004f9:       ff cd                   dec    ebp
  4004fb:       75 ec                   jne    4004e9 <_ZL4workii+0x13>

এই তিনটি দ্রুততম। কেন 256 বাইট সীমানা তার মেশিনে speascial হয়, আমি এটা খুঁজে বের করতে এটি ছেড়ে দেওয়া হবে। আমি যেমন একটি প্রসেসর আছে না।

এখন, আমার মেশিনে আমি এই 256 বাইট সীমানা প্রভাব পাবেন না। শুধুমাত্র আমার ফাংশন এবং লুপ সারিবদ্ধতা আমার মেশিনে kicks। যদি আমি g++ -O2 -falign-functions=16 -falign-loops=16 পাস করি তবে সবকিছু স্বাভাবিক অবস্থায় ফিরে আসে: আমি সর্বদা দ্রুততম -fno-omit-frame-pointer এবং -fno-omit-frame-pointer পতাকা আর সংবেদনশীল নয় । আমি g++ -O2 -falign-functions=32 -falign-loops=32 বা 16 এর যেকোন গুণক পাস করতে পারি, g++ -O2 -falign-functions=32 -falign-loops=32 জন্য সংবেদনশীল নয়।

আমি প্রথমে ২009 সালে লক্ষ্য করেছি যে জিপিসি (অন্তত আমার প্রোজেক্টগুলিতে এবং আমার মেশিনে) দ্রুত গতির কোড (-O2 বা -O3) এর পরিবর্তে আকার (-Os) এর জন্য অপ্টিমাইজ করার ক্ষেত্রে দ্রুতভাবে দ্রুত কোড তৈরি করার প্রবণতা আছে এবং আমি ভাবছি কেন কখনও থেকে।

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

ওহ, এবং আরও একটি জিনিস। উদাহরণস্বরূপ দেখানো যেমন হটস্পট কিভাবে উঠতে পারে? কিভাবে add() যেমন) একটি ক্ষুদ্র ফাংশন ইনলাইনিং ব্যর্থ করতে পারেন?

এই বিবেচনা:

// add.cpp
int add(const int& x, const int& y) {
    return x + y;
}

এবং একটি পৃথক ফাইলের মধ্যে:

// main.cpp
int add(const int& x, const int& y);

const int LOOP_BOUND = 200000000;

__attribute__((noinline))
static int work(int xval, int yval) {
    int sum(0);
    for (int i=0; i<LOOP_BOUND; ++i) {
        int x(xval+sum);
        int y(yval+sum);
        int z = add(x, y);
        sum += z;
    }
    return sum;
}

int main(int , char* argv[]) {
    int result = work(*argv[1], *argv[2]);
    return result;
}

এবং হিসাবে কম্পাইল: g++ -O2 add.cpp main.cpp

GCC ইনলাইন add() হবে না add() !

এটি সব, অপ্রত্যাশিতভাবে অপারেটিং সিস্টেমের মত হটস্পট তৈরি করা যে সহজ। অবশ্যই এটি আংশিকভাবে আমার দোষ: GCC একটি চমৎকার কম্পাইলার। যদি উপরের হিসাবে কম্পাইল করা হয়: g++ -O2 -flto add.cpp main.cpp , যা আমি লিঙ্ক সময় অপ্টিমাইজেশান সম্পাদন করি , তাহলে g++ -O2 -flto add.cpp main.cpp চালায়!

(ইনলাইনিং OP তে কৃত্রিমভাবে নিষ্ক্রিয়, তাই, OP তে কোড 2x ধীর ছিল)।

আমি প্রথম ২009 সালে লক্ষ্য করেছি যে জিसीसी (কমপক্ষে আমার প্রোজেক্ট এবং আমার মেশিনে) -Os দ্রুত কোড তৈরি করতে প্রবণতা আছে যদি আমি গতি ( -O2 বা -O3 ) এর পরিবর্তে আকার ( -Os ) এর জন্য অপ্টিমাইজ করে -O3 , এবং আমি কেন কখনও থেকে অবাক।

আমি তৈরি করতে পরিচালিত (বরং মূর্খ) কোড যা এই বিস্ময়কর আচরণ দেখায় এবং এখানে পোস্ট করার জন্য যথেষ্ট ছোট।

const int LOOP_BOUND = 200000000;

__attribute__((noinline))
static int add(const int& x, const int& y) {
    return x + y;
}

__attribute__((noinline))
static int work(int xval, int yval) {
    int sum(0);
    for (int i=0; i<LOOP_BOUND; ++i) {
        int x(xval+sum);
        int y(yval+sum);
        int z = add(x, y);
        sum += z;
    }
    return sum;
}

int main(int , char* argv[]) {
    int result = work(*argv[1], *argv[2]);
    return result;
}

যদি আমি ও-এর সাথে কম্পাইল করে -Os , তবে এই প্রোগ্রামটি চালানোর জন্য 0.38 সেকেন্ড সময় লাগে এবং 0.44 গুলি যদি -O2 বা -O3 সাথে সংকলিত হয়। এই সময়গুলি ধারাবাহিকভাবে এবং প্রকৃতপক্ষে কোন গোলমালের সাথে (GCC 4.7.2, x86_64 GNU / Linux, Intel Core i5-3320M) প্রাপ্ত হয়।

(আপডেট: আমি সব সমাবেশ কোডটি fno-align-* স্থানান্তরিত করেছি: তারা পোস্টটি ফেটে গেছে এবং স্পষ্টভাবে প্রশ্নগুলিতে খুব কম মূল্য যুক্ত করেছে যেমন fno-align-* পতাকাগুলির একই প্রভাব রয়েছে।)

এখানে -Os এবং -O2 সঙ্গে উত্পন্ন সমাবেশ।

দুর্ভাগ্যবশত, সমাবেশ সম্পর্কে আমার বোঝার খুব সীমিত ছিল, তাই আমি যা করেছি তা আমি বুঝতে পারিনি যে আমি যা পরবর্তী করেছি তা সঠিক ছিল: আমি -O2 জন্য -O2 দখল করেছি এবং সমাবেশের মধ্যে তার সমস্ত পার্থক্যগুলিকে একত্রিত করেছি - -Os.p2align লাইন ব্যতীত , here ফলাফল। এই কোড এখনও 0.38s রান এবং শুধুমাত্র পার্থক্য .p2align উপাদান।

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

এই প্যাডিং যে অপরাধী হয় এই ক্ষেত্রে? কেন এবং কিভাবে?

গোলমাল এটি বেশ অনেক সময় তোলে মাইক্রো অপ্টিমাইজেশান সময় অসম্ভব।

সি অথবা সি ++ সোর্স কোডে মাইক্রো-অপ্টিমাইজেশান (অ্যালাইনমেন্ট স্ট্যাকের সাথে সম্পর্কযুক্ত) করার সময় এই ধরনের দুর্ঘটনাজনিত ভাগ্যবান / অপ্রত্যাশিত সারিবদ্ধতাগুলি কীভাবে হস্তক্ষেপ করা যায় তা আমি কীভাবে নিশ্চিত করতে পারি?

হালনাগাদ:

প্যাসকাল কুওক এর উত্তরের পর আমি সামঞ্জস্যের সাথে সামান্য বিট করলাম। -O2 -fno-align-functions -fno-align-loops .p2align , সমস্ত .p2align সমাবেশ থেকে উত্পন্ন হয় এবং 0.38s মধ্যে উত্পাদিত এক্সিকিউটেবল রান। জিসি ডকুমেন্টেশন অনুযায়ী :

-Os সমস্ত -O2 অপ্টিমাইজেশান সক্ষম [কিন্তু] -আমরা নিম্নলিখিত অপ্টিমাইজেশান পতাকা অক্ষম করে:

  -falign-functions  -falign-jumps  -falign-loops <br/>
  -falign-labels  -freorder-blocks  -freorder-blocks-and-partition <br/>
  -fprefetch-loop-arrays <br/>

সুতরাং, এটি বেশ একটি (ভুল) সারিবদ্ধ সমস্যা মত মনে হয়।

মারাত -march=native উত্তর -march=native আমি এখনও -march=native নই। আমি দৃঢ়প্রত্যয়ী নই যে এটি কেবল এই (ভুল) সংলগ্ন ইস্যুতে হস্তক্ষেপ করছে না; এটা আমার মেশিনে একেবারে কোন প্রভাব আছে। (তবুও, আমি তার উত্তর উত্থাপিত।)

আপডেট 2:

আমরা -Os বাইরে নিতে পারেন। নিম্নলিখিত সময় সঙ্গে কম্পাইল দ্বারা প্রাপ্ত করা হয়

  • -O2 -fno-omit-frame-pointer 0.37s

  • -O2 -fno-align-functions -fno-align-loops 0.37s

  • -S -O2 তারপর নিজে work() 0.37s পরে add() এর সমাবেশ সরাতে

  • -O2 0.44s

এটি আমার মত মনে করে কল সাইট থেকে add() এর দূরত্ব অনেক বেশি। আমি perf চেষ্টা করেছি, কিন্তু perf stat এবং perf report আউটপুট আমাকে খুব সামান্য ইন্দ্রিয় তোলে। যাইহোক, আমি কেবল এটির একটি সামঞ্জস্যপূর্ণ ফলাফল পেতে পারি:

-O2 :

 602,312,864 stalled-cycles-frontend   #    0.00% frontend cycles idle
       3,318 cache-misses
 0.432703993 seconds time elapsed
 [...]
 81.23%  a.out  a.out              [.] work(int, int)
 18.50%  a.out  a.out              [.] add(int const&, int const&) [clone .isra.0]
 [...]
       ¦   __attribute__((noinline))
       ¦   static int add(const int& x, const int& y) {
       ¦       return x + y;
100.00 ¦     lea    (%rdi,%rsi,1),%eax
       ¦   }
       ¦   ? retq
[...]
       ¦            int z = add(x, y);
  1.93 ¦    ? callq  add(int const&, int const&) [clone .isra.0]
       ¦            sum += z;
 79.79 ¦      add    %eax,%ebx

fno-align-* :

 604,072,552 stalled-cycles-frontend   #    0.00% frontend cycles idle
       9,508 cache-misses
 0.375681928 seconds time elapsed
 [...]
 82.58%  a.out  a.out              [.] work(int, int)
 16.83%  a.out  a.out              [.] add(int const&, int const&) [clone .isra.0]
 [...]
       ¦   __attribute__((noinline))
       ¦   static int add(const int& x, const int& y) {
       ¦       return x + y;
 51.59 ¦     lea    (%rdi,%rsi,1),%eax
       ¦   }
[...]
       ¦    __attribute__((noinline))
       ¦    static int work(int xval, int yval) {
       ¦        int sum(0);
       ¦        for (int i=0; i<LOOP_BOUND; ++i) {
       ¦            int x(xval+sum);
  8.20 ¦      lea    0x0(%r13,%rbx,1),%edi
       ¦            int y(yval+sum);
       ¦            int z = add(x, y);
 35.34 ¦    ? callq  add(int const&, int const&) [clone .isra.0]
       ¦            sum += z;
 39.48 ¦      add    %eax,%ebx
       ¦    }

-fno-omit-frame-pointer :

 404,625,639 stalled-cycles-frontend   #    0.00% frontend cycles idle
      10,514 cache-misses
 0.375445137 seconds time elapsed
 [...]
 75.35%  a.out  a.out              [.] add(int const&, int const&) [clone .isra.0]                                                                                     ¦
 24.46%  a.out  a.out              [.] work(int, int)
 [...]
       ¦   __attribute__((noinline))
       ¦   static int add(const int& x, const int& y) {
 18.67 ¦     push   %rbp
       ¦       return x + y;
 18.49 ¦     lea    (%rdi,%rsi,1),%eax
       ¦   const int LOOP_BOUND = 200000000;
       ¦
       ¦   __attribute__((noinline))
       ¦   static int add(const int& x, const int& y) {
       ¦     mov    %rsp,%rbp
       ¦       return x + y;
       ¦   }
 12.71 ¦     pop    %rbp
       ¦   ? retq
 [...]
       ¦            int z = add(x, y);
       ¦    ? callq  add(int const&, int const&) [clone .isra.0]
       ¦            sum += z;
 29.83 ¦      add    %eax,%ebx

মনে হচ্ছে আমরা ধীর ক্ষেত্রে add() কল করার add() স্থগিত করছি।

আমি সবকিছু পরীক্ষা করেছি যা perf -e আমার মেশিনে থুতু আউট করতে পারেন; শুধু উপরে দেওয়া হয় যে পরিসংখ্যান।

একই এক্সিকিউটেবল জন্য, stalled-cycles-frontend মৃত্যুদন্ড সময় সঙ্গে রৈখিক সম্পর্ক দেখায়; আমি এত স্পষ্টভাবে সম্পর্কযুক্ত যে অন্য কিছু লক্ষ্য করা হয়নি। (বিভিন্ন এক্সিকিউটেবলগুলির জন্য stalled-cycles-frontend তুলনা করা আমার পক্ষে অর্থবহ নয়।)

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


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

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

যে বলেন, আমি কিভাবে যাচাই করতে হয় তা আমার কাছে কোন ধারণা নেই এবং আমি কেবল আপনাকে জানাতে চাই যে এটি এমন কিছু হতে পারে যা আপনি দেখতে চান।


আমি মনে করি আপনি যা করেছেন তা একই ফলাফল পেতে পারেন:

আমি -O2 এর জন্য সমাবেশটি দখল করেছিলাম এবং এর সমস্ত পার্থক্যগুলিকে বিভাজনে বিভাজিত করেছি - পি। পিলাইন লাইন ব্যতীত -

... -O2 -falign-functions=1 -falign-jumps=1 -falign-loops=1 -falign-labels=1 । আমি এই বিকল্পগুলির সাথে সবকিছু সংকলন করছি, যা সমতল চেয়ে দ্রুত ছিল -O2 15 -O2 আমি পরিমাপ করতে বিরক্ত।

এছাড়াও, একটি সম্পূর্ণ ভিন্ন প্রেক্ষাপটে (একটি ভিন্ন কম্পাইলার সহ), আমি লক্ষ্য করেছি যে পরিস্থিতিটি একই রকম : "সাইজের আকারের তুলনায় কোড আকার অপ্টিমাইজ করা" বিকল্পটি কোড আকার এবং গতির জন্য সর্বোত্তম।

আমি সঠিকভাবে অনুমান, স্ট্যাক সারিবদ্ধ জন্য এই প্যাডিং হয়।

না, এই স্ট্যাকের সাথে কিছুই করার নেই, ডিফল্টভাবে উত্পন্ন NOPs এবং যে বিকল্পগুলি -ফ্যালাইন - * = 1 প্রতিরোধ কোড সংমিশ্রণের জন্য হয়।

কেন NOPs সঙ্গে GCC প্যাড ফাংশন অনুযায়ী? এটি আশা করা হয় যে কোড দ্রুত চালানো হবে তবে দৃশ্যত এই অপটিমাইজেশনটি আমার ক্ষেত্রে ব্যাকফায়ার করা হয়েছে।

এই প্যাডিং যে অপরাধী হয় এই ক্ষেত্রে? কেন এবং কিভাবে?

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


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

এখানে time ./test 0 0 ফলাফল time ./test 0 0 বিভিন্ন প্রসেসরগুলিতে (ব্যবহারকারীর সময় প্রতিবেদন করা হয়েছে):

Processor (System-on-Chip)             Compiler   Time (-O2)  Time (-Os)  Fastest
AMD Opteron 8350                       gcc-4.8.1    0.704s      0.896s      -O2
AMD FX-6300                            gcc-4.8.1    0.392s      0.340s      -Os
AMD E2-1800                            gcc-4.7.2    0.740s      0.832s      -O2
Intel Xeon E5405                       gcc-4.8.1    0.603s      0.804s      -O2
Intel Xeon E5-2603                     gcc-4.4.7    1.121s      1.122s       -
Intel Core i3-3217U                    gcc-4.6.4    0.709s      0.709s       -
Intel Core i3-3217U                    gcc-4.7.3    0.708s      0.822s      -O2
Intel Core i3-3217U                    gcc-4.8.1    0.708s      0.944s      -O2
Intel Core i7-4770K                    gcc-4.8.1    0.296s      0.288s      -Os
Intel Atom 330                         gcc-4.8.1    2.003s      2.007s      -O2
ARM 1176JZF-S (Broadcom BCM2835)       gcc-4.6.3    3.470s      3.480s      -O2
ARM Cortex-A8 (TI OMAP DM3730)         gcc-4.6.3    2.727s      2.727s       -
ARM Cortex-A9 (TI OMAP 4460)           gcc-4.6.3    1.648s      1.648s       -
ARM Cortex-A9 (Samsung Exynos 4412)    gcc-4.6.3    1.250s      1.250s       -
ARM Cortex-A15 (Samsung Exynos 5250)   gcc-4.7.2    0.700s      0.700s       -
Qualcomm Snapdragon APQ8060A           gcc-4.8       1.53s       1.52s      -Os

কিছু ক্ষেত্রে আপনি আপনার নির্দিষ্ট প্রসেসরের জন্য অপ্টিমাইজ করতে gcc জিজ্ঞাসা করে -mtune=native অপটিমাইজেশনগুলির প্রভাবকে কমিয়ে আনতে পারেন (বিকল্পগুলি -mtune=native বা -march=native ):

Processor            Compiler   Time (-O2 -mtune=native) Time (-Os -mtune=native)
AMD FX-6300          gcc-4.8.1         0.340s                   0.340s
AMD E2-1800          gcc-4.7.2         0.740s                   0.832s
Intel Xeon E5405     gcc-4.8.1         0.603s                   0.803s
Intel Core i7-4770K  gcc-4.8.1         0.296s                   0.288s

আপডেট: আইভি ব্রিজ ভিত্তিক কোর i3 এ 4.6.4 তিনটি সংস্করণ ( 4.6.4 , 4.7.3 , এবং 4.8.1 ) উল্লেখযোগ্যভাবে বিভিন্ন কর্মক্ষমতা সহ বাইনারি উত্পাদন করে, তবে সমাবেশ 4.7.3 কেবল সূক্ষ্ম পরিবর্তন রয়েছে। এ পর্যন্ত, আমি এই সত্য কোন ব্যাখ্যা আছে।

gcc-4.6.4 -Os থেকে সমাবেশ (0.709 সেকেন্ডে কার্যকর):

00000000004004d2 <_ZL3addRKiS0_.isra.0>:
  4004d2:       8d 04 37                lea    eax,[rdi+rsi*1]
  4004d5:       c3                      ret

00000000004004d6 <_ZL4workii>:
  4004d6:       41 55                   push   r13
  4004d8:       41 89 fd                mov    r13d,edi
  4004db:       41 54                   push   r12
  4004dd:       41 89 f4                mov    r12d,esi
  4004e0:       55                      push   rbp
  4004e1:       bd 00 c2 eb 0b          mov    ebp,0xbebc200
  4004e6:       53                      push   rbx
  4004e7:       31 db                   xor    ebx,ebx
  4004e9:       41 8d 34 1c             lea    esi,[r12+rbx*1]
  4004ed:       41 8d 7c 1d 00          lea    edi,[r13+rbx*1+0x0]
  4004f2:       e8 db ff ff ff          call   4004d2 <_ZL3addRKiS0_.isra.0>
  4004f7:       01 c3                   add    ebx,eax
  4004f9:       ff cd                   dec    ebp
  4004fb:       75 ec                   jne    4004e9 <_ZL4workii+0x13>
  4004fd:       89 d8                   mov    eax,ebx
  4004ff:       5b                      pop    rbx
  400500:       5d                      pop    rbp
  400501:       41 5c                   pop    r12
  400503:       41 5d                   pop    r13
  400505:       c3                      ret

gcc-4.7.3 -Os থেকে সমাবেশ (0.822 সেকেন্ডে কার্যকর):

00000000004004fa <_ZL3addRKiS0_.isra.0>:
  4004fa:       8d 04 37                lea    eax,[rdi+rsi*1]
  4004fd:       c3                      ret

00000000004004fe <_ZL4workii>:
  4004fe:       41 55                   push   r13
  400500:       41 89 f5                mov    r13d,esi
  400503:       41 54                   push   r12
  400505:       41 89 fc                mov    r12d,edi
  400508:       55                      push   rbp
  400509:       bd 00 c2 eb 0b          mov    ebp,0xbebc200
  40050e:       53                      push   rbx
  40050f:       31 db                   xor    ebx,ebx
  400511:       41 8d 74 1d 00          lea    esi,[r13+rbx*1+0x0]
  400516:       41 8d 3c 1c             lea    edi,[r12+rbx*1]
  40051a:       e8 db ff ff ff          call   4004fa <_ZL3addRKiS0_.isra.0>
  40051f:       01 c3                   add    ebx,eax
  400521:       ff cd                   dec    ebp
  400523:       75 ec                   jne    400511 <_ZL4workii+0x13>
  400525:       89 d8                   mov    eax,ebx
  400527:       5b                      pop    rbx
  400528:       5d                      pop    rbp
  400529:       41 5c                   pop    r12
  40052b:       41 5d                   pop    r13
  40052d:       c3                      ret

gcc-4.8.1 -Os থেকে সমাবেশ ( gcc-4.8.1 -Os সেকেন্ডে সঞ্চালিত হয়):

00000000004004fd <_ZL3addRKiS0_.isra.0>:
  4004fd:       8d 04 37                lea    eax,[rdi+rsi*1]
  400500:       c3                      ret

0000000000400501 <_ZL4workii>:
  400501:       41 55                   push   r13
  400503:       41 89 f5                mov    r13d,esi
  400506:       41 54                   push   r12
  400508:       41 89 fc                mov    r12d,edi
  40050b:       55                      push   rbp
  40050c:       bd 00 c2 eb 0b          mov    ebp,0xbebc200
  400511:       53                      push   rbx
  400512:       31 db                   xor    ebx,ebx
  400514:       41 8d 74 1d 00          lea    esi,[r13+rbx*1+0x0]
  400519:       41 8d 3c 1c             lea    edi,[r12+rbx*1]
  40051d:       e8 db ff ff ff          call   4004fd <_ZL3addRKiS0_.isra.0>
  400522:       01 c3                   add    ebx,eax
  400524:       ff cd                   dec    ebp
  400526:       75 ec                   jne    400514 <_ZL4workii+0x13>
  400528:       89 d8                   mov    eax,ebx
  40052a:       5b                      pop    rbx
  40052b:       5d                      pop    rbp
  40052c:       41 5c                   pop    r12
  40052e:       41 5d                   pop    r13
  400530:       c3                      ret





assembly