কোন, যদি কোন হয়, সি ++ সংকলকরা পুচ্ছ-পুনরাবৃত্তি অপ্টিমাইজেশন করবেন?


149

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

কোনও সি ++ কম্পাইলার কি এই অপটিমাইজেশনটি করেন? কেন? কেন না?

কম্পাইলারটিকে এটি করতে বলার বিষয়ে আমি কীভাবে যাব?

  • এমএসভিসির জন্য: /O2বা/Ox
  • জিসিসির জন্য: -O2বা-O3

সংকলকটি একটি নির্দিষ্ট ক্ষেত্রে এটি করেছে কিনা তা যাচাই করার বিষয়ে কীভাবে?

  • এমএসভিসির জন্য, পিডিবি আউটপুটটিকে কোডটি সনাক্ত করতে সক্ষম করুন, তারপরে কোডটি পরীক্ষা করুন
  • জিসিসির জন্য ..?

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

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


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

যদি কোনও ডেস্ট্রাক্টরকে লেজ-কলের পরে চালানো দরকার হয়, তবে টেল-কল অপ্টিমাইজেশন করা যাবে না।

উত্তর:


128

সমস্ত বর্তমান মূলধারার সংকলকগুলি টেল কল অপটিমাইজেশন মোটামুটিভাবে ভাল সম্পাদন করে (এবং এক দশকেরও বেশি সময় ধরে করেছে) এমনকি পারস্পরিক পুনরাবৃত্ত কলগুলির জন্য যেমন:

int bar(int, int);

int foo(int n, int acc) {
    return (n == 0) ? acc : bar(n - 1, acc + 2);
}

int bar(int n, int acc) {
    return (n == 0) ? acc : foo(n - 1, acc + 1);
}

সংকলকটি অপ্টিমাইজেশনটি সোজা করে দেওয়া: গতির জন্য কেবল অনুকূলিতকরণটি স্যুইচ করুন:

  • এমএসভিসির জন্য, ব্যবহার করুন /O2বা /Ox
  • জিসিসি, কলং এবং আইসিসির জন্য ব্যবহার করুন -O3

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

একটি আকর্ষণীয় historicalতিহাসিক নোট হিসাবে, মার্ক প্রোবস্ট দ্বারা ডিপ্লোমা থিসিসের সময় সি-এর জন্য টেল কল অপ্টিমাইজেশনকে জিসিসিতে যুক্ত করা হয়েছিল। থিসিস বাস্তবায়নের কিছু আকর্ষণীয় সতর্কতা বর্ণনা করে। এটা পড়া মূল্য।


আমি বিশ্বাস করি আইসিসি তা করবে। আমার জ্ঞানের সেরা দিক থেকে, আইসিসি বাজারে দ্রুততম কোড তৈরি করে।
পল নাথান

35
@ পল প্রশ্নটি হ'ল আইসিসি কোডের গতি কতটা লেজ কল অপটিমাইজেশনের মতো অ্যালগরিদমিক অপ্টিমাইজেশনের কারণে ঘটে এবং ক্যাশে এবং মাইক্রোইনস্ট্রাকশন অপটিমাইজেশনের ফলে কতটা ঘটেছিল যা কেবলমাত্র ইন্টেল তাদের নিজস্ব প্রসেসরের অন্তরঙ্গ জ্ঞান সহ করতে পারে।
চিত্রগ্রাহক

6
gcc-foptimize-sibling-calls"ভাইবোন এবং লেজ পুনরাবৃত্তি কল অনুকূলিতকরণ" আরও সংকীর্ণ বিকল্প আছে। এই (অনুযায়ী বিকল্প gcc(1)সংস্করণ 4.4, 4.7 এবং 4.8 বিভিন্ন প্ল্যাটফর্মের টার্গেটিংয়ের জন্য ম্যানুয়াল পৃষ্ঠাগুলি) পর্যায়ে সক্রিয় করা হয় -O2, -O3, -Os
এফএফএফ

এছাড়াও, অপ্টিমাইজেশানগুলির স্পষ্টভাবে অনুরোধ না করেই ডিইবিইউজি মোডে চালনা কোনও অপ্টিমাইজেশন মোটেই করবে না। আপনি সত্যিকারের রিলিজ মোড EXE এর জন্য পিডিবি সক্ষম করতে পারেন এবং এটির মাধ্যমে পদক্ষেপের চেষ্টা করতে পারেন তবে নোট করুন যে রিলিজ মোডে ডিবাগিং এর জটিলতা রয়েছে - অদৃশ্য / স্ট্রিপড ভেরিয়েবল, মার্জ ভেরিয়েবলস, ভেরিয়েবলগুলি অজানা / অপ্রত্যাশিত সুযোগে সুযোগের বাইরে চলে যায়, ভেরিয়েবলগুলি কখনও যায় না সুযোগ এবং স্ট্যাক-স্তরীয় ঠিকানাগুলি সহ সত্য ধ্রুবক হয়ে উঠেছে, এবং - ভাল - মার্জ করা বা স্ট্যাক ফ্রেমগুলি হারিয়েছে। সাধারণত একত্রিত স্ট্যাক ফ্রেমগুলির অর্থ হ'ল ক্যালিটি ইনলাইনড থাকে এবং অনুপস্থিত / ব্যাকব্র্যামিত ফ্রেমগুলি সম্ভবত টেল কল।
Петров

21

জিসিসি ৪.৩.২ সম্পূর্ণরূপে এই ফাংশনটিকে (ক্রেপি / তুচ্ছ atoi()বাস্তবায়ন) ইনলাইন করে main()। অপটিমাইজেশন স্তর হয় -O1। আমি (এটা দিয়ে চারপাশে খেলা এমনকি থেকে এটিকে পরিবর্তন করা লক্ষ্য staticকরতে extern, লেজ পুনরাবৃত্তির দূরে বেশ দ্রুত যায়, তাই আমি প্রোগ্রাম শুদ্ধি জন্য এটি উপর নির্ভর করে না।

#include <stdio.h>
static int atoi(const char *str, int n)
{
    if (str == 0 || *str == 0)
        return n;
    return atoi(str+1, n*10 + *str-'0');
}
int main(int argc, char **argv)
{
    for (int i = 1; i != argc; ++i)
        printf("%s -> %d\n", argv[i], atoi(argv[i], 0));
    return 0;
}

1
আপনি যদিও লিঙ্ক-টাইম অপ্টিমাইজেশন সক্রিয় করতে পারেন এবং আমি অনুমান করি যে এমনকি কোনও externপদ্ধতিটি তখন অন্তর্ভুক্ত হতে পারে।
কনরাড রুডল্ফ

5
স্ট্রেঞ্জ। আমি শুধু জিসিসি 4.2.3 (এক্স 86, স্ল্যাকওয়্যার 12.1) এবং জিসিসি 4.6.2 (যে AMD64, ডেবিয়ান হুইজি) এবং পরীক্ষিত সঙ্গে-O1 আছে কোন ইনলাইনিং এবং কোন লেজ-পুনরাবৃত্তির অপ্টিমাইজেশান । আপনাকে এটির জন্য ব্যবহার-O2 করতে হবে (ভাল, 4.2.x এ, যা এখনকার চেয়ে প্রাচীন, এটি এখনও অন্তর্ভুক্ত হবে না)। বিটিডাব্লু যোগ করার মতো এটিও মূল্যবান যে সিসিটি কঠোরভাবে কোনও লেজ নয় (এমনকি ফ্যাকটোরিয়াল ডাব্লু / ও অ্যাকসুমুলেটরের মতো) না হলেও পুনরাবৃত্তি অপ্টিমাইজ করতে পারে।
przemoc

16

সুস্পষ্টর পাশাপাশি (কম্পাইলাররা আপনি এটি না জিজ্ঞাসা না করে এই ধরণের অপ্টিমাইজেশানটি করেন না), সি ++: ডিস্ট্রাক্টরগুলিতে টেল-কল অপ্টিমাইজেশন সম্পর্কে জটিলতা রয়েছে।

এরকম কিছু দেওয়া হয়েছে:

   int fn(int j, int i)
   {
      if (i <= 0) return j;
      Funky cls(j,i);
      return fn(j, i-1);
   }

সংকলকটি (সাধারণভাবে) টেল-কলটিকে অনুকূল করতে পারে না কারণ এটি পুনরাবৃত্ত কল রিটার্ন cls পরে ডেস্ট্রাক্টরকে কল করতে হবে ।

কখনও কখনও সংকলকটি দেখতে পাবেন যে ডেস্ট্রাক্টরের কোনও বাহ্যিকভাবে দৃশ্যমান পার্শ্ব প্রতিক্রিয়া নেই (তাই এটি তাড়াতাড়ি করা যেতে পারে), তবে প্রায়শই এটি করা যায় না।

এটির একটি বিশেষরূপ Funkyযা প্রকৃতপক্ষে একটি std::vectorবা অনুরূপ।


আমার জন্য কাজ করে না। সিস্টেমগুলি আমাকে বলে যে উত্তরটি সম্পাদনা না করা পর্যন্ত আমার ভোটটি লক করা আছে।
হিউমেলনার 21

সবেমাত্র উত্তরটি সম্পাদনা করা হয়েছে (সরানো প্যারান্থেসিস) এবং এখন আমি আমার ডাউনওয়েটটি পূর্বাবস্থায় ফেরাতে পারি।
হিউমেলনার

11

বেশিরভাগ সংকলকগণ কোনও ডিবাগ বিল্ডে কোনও ধরণের অপ্টিমাইজেশন করেন না।

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


2
gcc কেন -g -O3 চেষ্টা করুন এবং একটি ডিবাগ বিল্ডে অপিমেশন পেতে। xlC এর একই আচরণ রয়েছে।
g24l

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

7

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

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