সংকলকরা কেন সব কিছু ইনলাইন করে না? [বন্ধ]


13

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

সুতরাং আমার প্রশ্ন হ'ল কম্পাইলাররা কেন সব কিছু ইনলাইন করে না? আমি ধরে নিই এটি কার্যকরভাবে দ্রুততর করে তুলবে।

একমাত্র কারণটি আমি উল্লেখযোগ্যভাবে বৃহত্তর এক্সিকিউটেবল হিসাবে বিবেচনা করতে পারি, তবে শত শত গিগাবাইট মেমরির সাথে কি আজকাল সত্যই এটি গুরুত্বপূর্ণ? উন্নত পারফরম্যান্স কি মূল্যহীন নয়?

কম্পাইলাররা কেবল সমস্ত ফাংশন কলগুলিকেই ইনলাইন না করে তার অন্য কোনও কারণ রয়েছে কি?


18
আপনার সম্পর্কে আইডিকে, তবে আমার কাছে কয়েকশ 'গিগাবাইট মেমরি নেই।
Ampt

2
Isn't the improved performance worth it?এমন একটি পদ্ধতির জন্য যা 100 বার লুপ চালাবে এবং কিছু গুরুতর সংখ্যার ক্রাচ করবে, 2 বা 3 আর্গুমেন্ট সিপিইউ রেজিস্টারে স্থানান্তরিত করার ওভারহেড কিছুই নয়।
ডোভাল

5
আপনি অত্যধিক জেনেরিক, "সংকলক" এর অর্থ কি "সমস্ত সংকলক" এবং "সবকিছু" এর অর্থ সত্যই "সবকিছু"? তারপরে উত্তরটি সহজ, এমন পরিস্থিতি রয়েছে যেখানে আপনি কেবল ইনলাইন করতে পারবেন না। পুনরাবৃত্তি মনে আসে।
ওটিভিও ডাসিও

17
ছোট ফাংশন কল ওভারহেডের চেয়ে ক্যাশে লোকালটি অনেক বেশি গুরুত্বপূর্ণ।
এসকে-যুক্তি

3
শত শত জিএফএলপিএস প্রসেসিং পাওয়ারের সাথে পারফরম্যান্সের উন্নতি কি আজকাল সত্যিই গুরুত্বপূর্ণ?
মাউভিচিয়েল

উত্তর:


22

প্রথম নোট করুন যে ইনলাইনটির একটি বড় প্রভাবটি এটি কল সাইটে আরও অনুকূলিতকরণের অনুমতি দেয়।

আপনার প্রশ্নের জন্য: এমন কিছু জিনিস রয়েছে যা ইনলাইন করা কঠিন বা এমনকি অসম্ভব:

  • গতিশীলভাবে সংযুক্ত লাইব্রেরি

  • গতিশীলভাবে নির্ধারিত ফাংশন (গতিশীল প্রেরণ, ফাংশন পয়েন্টারগুলির মাধ্যমে বলা হয়)

  • পুনরাবৃত্তি ফাংশন (লেজ পুনরাবৃত্তি করতে পারেন)

  • যে ফাংশনগুলির জন্য আপনার কাছে কোড নেই (তবে লিঙ্ক টাইম অপ্টিমাইজেশান এটির কিছুটির জন্য এটি অনুমতি দেয়)

তারপরে ইনলাইনিংয়ের কেবল উপকারী প্রভাব নেই:

  • বড় এক্সিকিউটেবল মানে আরও বেশি ডিস্ক প্লেস এবং বড় লোড টাইম

  • বৃহত্তর এক্সিকিউটেবল মানে ক্যাশে চাপ বৃদ্ধি (নোট করুন যে যথেষ্ট ছোট ছোট ফাংশনগুলি যেমন সহজ গেটারগুলি কার্যকর করা কার্যকরকরণের আকার এবং ক্যাশে চাপ হ্রাস করতে পারে)

এবং পরিশেষে, এমন ক্রিয়াকলাপগুলির জন্য যা নির্বাহ করতে একটি তুচ্ছ সময় লাগে, লাভটি কেবল ব্যথার পক্ষে নয়।


3
কিছু পুনরাবৃত্ত কলগুলি ইনলাইন করা যেতে পারে (টেইল কল), তবে আপনি aচ্ছিকভাবে একটি স্পষ্ট স্ট্যাক যোগ করলে সবগুলি পুনরাবৃত্তিতে রূপান্তরিত হতে পারে
র‌্যাচেট ফ্রিক

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

11

একটি প্রধান সীমাবদ্ধতা রানটাইম পলিমারফিজম। আপনি লেখার সময় যদি কোনও গতিশীল প্রেরণ ঘটে থাকে foo.bar()তবে পদ্ধতি কলটি ইনলাইন করা অসম্ভব। এটি ব্যাখ্যা করে যে সংকলকরা কেন সমস্ত কিছু ইনলাইন করে না।

পুনরাবৃত্ত কলগুলি খুব সহজেই প্রবেশ করানো যায় না।

প্রযুক্তিগত কারণে ক্রস মডিউল ইনলাইনিং সম্পাদন করাও কঠিন (বর্ধিত পুনঃসংশোধন প্রাক্তনের পক্ষে অসম্ভব)

তবে সংকলকগণ অনেক কিছুই ইনলাইন করেন।


3
ভার্চুয়াল প্রেরণের মাধ্যমে ইনলাইন করা খুব কঠিন, তবে অসম্ভব নয়। কিছু সি ++ সংকলক নির্দিষ্ট পরিস্থিতিতে এটি করতে সক্ষম হয়।
বিস্টামুর

2
... পাশাপাশি কিছু জেআইটি সংকলক (ডিভ্রিচুয়ালাইজেশন)।
ফ্রাঙ্ক

@bstamour যথাযথ অপটিমাইজেশন সহ যে কোনও ভাষার অর্ধ-শালীন সংকলক স্থিতিশীলভাবে প্রেরণ করবে, অর্থাত্‍ ডিভ্যাচুয়ালাইজেশন, কোনও অবজেক্টের ডিকামিকাল টাইপটি সংকলন-সময় জানা যায় এমন একটি ঘোষিত-ভার্চুয়াল পদ্ধতিতে কল। যদি (বা অন্য কোনও) ইনলাইনিং পর্বের আগে ডেভেরচুয়ালাইজেশন পর্বটি ঘটে তবে এটি ইনলাইনিংয়ের সুবিধে করতে পারে। তবে এটি তুচ্ছ। তুমি বোঝানোর মতো কিছু ছিল? কোনও বাস্তব "ভার্চুয়াল প্রেরণের মাধ্যমে অন্তর্নিহিত" কীভাবে অর্জন করা যায় তা আমি দেখছি না। অর্থাত devirtualise - - ইনলাইন করার জন্য, এক স্ট্যাটিক টাইপ জানতে হবে তাই ইনলাইনিং মানে অস্তিত্ব সেখানে নেই কোন ভার্চুয়াল প্রেরণ
underscore_d

9

প্রথমত, আপনি সর্বদা ইনলাইন করতে পারবেন না, উদাহরণস্বরূপ রিকার্সিভ ফাংশনগুলি সর্বদা অন্তর্নিহিত হতে পারে না (তবে factকেবলমাত্র একটি মুদ্রণের সাথে একটি পুনরাবৃত্ত সংজ্ঞাযুক্ত একটি প্রোগ্রাম অন্তর্ভুক্ত করা fact(8)যেতে পারে)।

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

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


1
রেকর্ডের জন্য, এলএলভিএম / কলং (এবং আরও কয়েকটি সংকলক) লিঙ্ক-টাইম অপ্টিমাইজেশান সমর্থন করে
আপনি

আমি জানি; পূর্ববর্তী শতাব্দীতে এলটিওর অস্তিত্ব ছিল (আইআইআরসি, কিছুটা এমআইপিএসের স্বত্বাধিকারী সংকলকটিতে অন্তত)।
বেসাইল স্টারিনকিভিচ

7

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

হেডারের ফাইলগুলির বাইরে 'ইনলাইন' হিসাবে চিহ্নিত কোডের বৃহত অংশ নিয়ে সোর্স কোডে রেখেছি, সময়ে কোড কলটি প্রতিটি কল সাইটের পরিবর্তে কেবলমাত্র এক জায়গায় থাকে time তারপরে সিপিইউ ক্যাশে আরও ভালভাবে ব্যবহার করা হয় এবং আপনি আরও কমপাইল সময় পান ...


এই নিছক পুনরাবৃত্তি পয়েন্ট হয়েছে এবং একটি ব্যাখ্যা বলে মনে হয় পূর্বে উত্তর যে এক ঘন্টা আগে পোস্ট করা হয়েছে
মশা

1
কি ক্যাশে? এটি L1? ও L2? L3? কোনটি আরও গুরুত্বপূর্ণ?
পিটার মর্টেনসেন

1

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

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


1

এক, এখানে সহজ উদাহরণ রয়েছে যেখানে ইনলাইন করা সমস্ত কিছু খুব খারাপভাবে কাজ করে। এই সাধারণ সি কোড বিবেচনা করুন:

void f1 (void) { printf ("Hello, world\n"); }
void f2 (void) { f1 (); f1 (); f1 (); f1 (); }
void f3 (void) { f2 (); f2 (); f2 (); f2 (); }
...
void f99 (void) { f98 (); f98 (); f98 (); f98 (); }

অনুমান করুন কী অন্তর্ভুক্ত সমস্ত কিছুই আপনার সাথে কি করবে।

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

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

BTW। আমার কাছে "কয়েকশো জিবি স্মৃতি" নেই। আমার ওয়ার্কস কম্পিউটারে "কয়েকশো জিবি হার্ডড্রাইভ স্পেস" নেই। এবং যদি আমার অ্যাপ্লিকেশনটি যেখানে "কয়েকশো গিগাবাইট মেমরি রয়েছে", অ্যাপ্লিকেশনটিকে স্মৃতিতে লোড করতে 20 মিনিট সময় লাগবে।

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