টি এল: ডিআর:
- সহজেই এই অপ্টিমাইজেশনটি সন্ধানের জন্য সংকলক অভ্যন্তরীণগুলি সম্ভবত সেট আপ করা হয় না এবং এটি সম্ভবত কেবলমাত্র ছোট ফাংশনগুলির জন্য দরকারী, কলগুলির মধ্যে বৃহত ফাংশনের অভ্যন্তরে নয়।
- বড় ফাংশন তৈরি করতে সন্নিবেশ করা বেশিরভাগ সময় একটি ভাল সমাধান
foo
আরবিএক্স সংরক্ষণ / পুনরুদ্ধার না হলে কিছুটা বিলম্ব বনাম থ্রুপুট ট্রেড অফ থাকতে পারে।
সংকলকগুলি জটিল যন্ত্রের টুকরো। তারা কোনও মানুষের মতো "স্মার্ট" নয় এবং প্রতিটি সম্ভাব্য অপটিমাইজেশন খুঁজে পেতে ব্যয়বহুল অ্যালগরিদমগুলি প্রায়শই অতিরিক্ত সংকলনের সময় ব্যয়যোগ্য নয়।
আমি এটি জিসিসি বাগ 69986 হিসাবে জানিয়েছি - 2016 সালে ফিরে স্পিল / পুনরায় লোড করতে পুশ / পপ ব্যবহার করে -ও এর সাথে আরও ছোট কোড সম্ভব ; জিসিসি ডেভস থেকে কোনও ক্রিয়াকলাপ বা উত্তর পাওয়া যায় নি। : /
সামান্যভাবে সম্পর্কিত: জিসিসি বাগ 70408 - একই কল-সংরক্ষিত রেজিস্টারটি পুনরায় ব্যবহার করা কিছু ক্ষেত্রে ছোট কোড দেবে - সংকলক দেবগণ আমাকে বলেছেন যে জিসিসি সেই অপটিমাইজেশনটি করতে সক্ষম হতে পারে কারণ এটি মূল্যায়নের ক্রমবর্ধমান ক্রম প্রয়োজন foo(int)
লক্ষ্যটিকে কীভাবে সহজ করে তুলবে তার ভিত্তিতে দুটি কল।
যদি নিজেকে foo
সংরক্ষণ / পুনরুদ্ধার না rbx
করে, তবে x
-> রেভালাল নির্ভরতা শৃঙ্খলে একটি অতিরিক্ত স্টোর / পুনরায় লোড বিলম্বের মাধ্যমে থ্রুপুট (নির্দেশের গণনা) এর মধ্যে একটি বাণিজ্য রয়েছে ।
কম্পাইলার সাধারণত লেটেন্সি থ্রুপুট উপর যেমন পরিবর্তে 2x কর্মদিবসের ব্যবহার পক্ষপাতী, imul reg, reg, 10
(3-চক্র লেটেন্সি, 1 / ঘড়ি থ্রুপুট), কারণ অধিকাংশ কোড গড় উল্লেখযোগ্যভাবে কম 4 uops / Skylake মত টিপিক্যাল 4 ব্যাপী পাইপলাইনগুলি উপর ঘড়ি। (আরও নির্দেশাবলী / উফগুলি আরওবিতে আরও বেশি জায়গা নেয়, একই আউট-অফ-অর্ডার উইন্ডোটি আরও কতটা দেখতে পারে তা হ্রাস করে এবং বাস্তবায়ন কার্যকরভাবে স্টলগুলি দিয়ে ফেটে যায় সম্ভবত 4-এরও কম ইউপগুলির জন্য অ্যাকাউন্টিং / ঘড়ির গড়।)
foo
আরবিএক্সকে যদি ধাক্কা দেয় / পপ করে, তবে বিলম্বের জন্য বেশি কিছু পাওয়ার নেই। পুনরুদ্ধারের ঠিক ঠিক ret
পরিবর্তে হওয়ার আগেই ret
ঘটানো সম্ভবত প্রাসঙ্গিক নয়, যদি না কোনও ভুল অনুমান বা আই-ক্যাশে মিস না করে যা ফেরতের ঠিকানায় কোড আনতে বিলম্ব করে।
বেশিরভাগ অ-তুচ্ছ ফাংশনগুলি আরবিএক্সকে সংরক্ষণ / পুনরুদ্ধার করবে, তাই প্রায়শই এটি একটি ভাল অনুমান নয় যে আরবিএক্সে একটি পরিবর্তনশীল রেখে যাওয়ার অর্থ এটি পুরো কল জুড়েই সত্যিকার অর্থে একটি রেজিস্টারে থাকবে। (যদিও কল-সংরক্ষিত রেজিস্ট্রেশন ফাংশনগুলি এলোমেলো করে তোলে এটি কখনও কখনও প্রশমিত করার পক্ষে ভাল ধারণা হতে পারে))
সুতরাং হ্যাঁ push rdi
/ এই ক্ষেত্রে pop rax
আরও দক্ষ হবে , এবং সম্ভবত সম্ভবত ক্ষুদ্র নন-পাত ফাংশনগুলির জন্য একটি মিসড অপ্টিমাইজেশন যা নির্ভর করে কলারের সংরক্ষণ / পুনরুদ্ধার করার জন্য বনামের আরও নির্দেশাবলীর জন্য অতিরিক্ত স্টোর / পুনরায় লোডের বিলম্বের মধ্যে ভারসাম্য ।foo
x
rbx
স্ট্যাক-আনওয়াইন্ড মেটাডেটা এখানে আরএসপিতে পরিবর্তনের প্রতিনিধিত্ব করা সম্ভব, ঠিক যেমন এটি স্ট্যাক স্লটে sub rsp, 8
স্পিল / পুনরায় লোড ব্যবহার করত x
। (তবে সংকলকগণও এই অপ্টিমাইজেশনটি জানেন না, push
স্থান সংরক্ষণ এবং একটি ভেরিয়েবল আরম্ভ করার জন্য ব্যবহার করছেন C কোন সি / সি ++ সংকলক কেবল একবার এসএসপি বাড়ানোর পরিবর্তে স্থানীয় ভেরিয়েবলগুলি তৈরি করার জন্য পুশ পপ নির্দেশাবলী ব্যবহার করতে পারে? এবং এর চেয়ে আরও বেশি কিছু করার জন্য একটি স্থানীয় ভেরি বড় .eh_frame
স্ট্যাক আনওয়াইন্ড মেটাডেটা বাড়ে কারণ আপনি স্ট্যাক পয়েন্টারকে প্রতিটি ধাক্কা দিয়ে আলাদাভাবে সরিয়ে নিয়ে যাচ্ছেন That এটি কল-সংরক্ষিত রেজিগুলি সংরক্ষণ / পুনরুদ্ধার করতে পুশ / পপ ব্যবহার করা থেকে বিরত রাখে না))
আইডি কে এই অপটিমাইজেশনটি সন্ধান করার জন্য কম্পাইলারদের শেখানো উপযুক্ত হবে
এটি কোনও ফাংশনের অভ্যন্তরে এক কল জুড়েই নয়, পুরো ফাংশনটির চারপাশে খুব ভাল ধারণা। এবং আমি যেমন বলেছি, এটি হতাশাবাদী অনুমানের উপর ভিত্তি করে foo
যেভাবেই আরবিএক্সকে সংরক্ষণ / পুনরুদ্ধার করবে। (বা থ্রুটপুটটির জন্য অনুকূলিতকরণ যদি আপনি জানেন যে এক্স থেকে প্রেরণের মান ফেরত দেওয়া গুরুত্বপূর্ণ নয় But তবে সংকলকরা এটি জানেন না এবং সাধারণত বিলম্বের জন্য অনুকূলিত হন)।
যদি আপনি প্রচুর কোডে (যেমন ফাংশনগুলির মধ্যে একক ফাংশন কলগুলির আশেপাশে) হতাশাবাদী অনুমান করা শুরু করেন, আপনি আরবিএক্স সংরক্ষণ করা / পুনরুদ্ধার করা হয়নি এমন আরও মামলা পেতে শুরু করেছেন এবং আপনি সুবিধা নিতে পারেন।
আপনি এই অতিরিক্ত সংরক্ষণ / পুনরুদ্ধার পুশ / পপটিকে কোনও লুপে চান না, কেবল লুপের বাইরে আরবিএক্স সংরক্ষণ / পুনরুদ্ধার করুন এবং ফাংশন কলগুলি করে এমন লুপগুলিতে কল-সংরক্ষিত রেজিস্টারগুলি ব্যবহার করুন। এমনকি লুপ ছাড়াই, সাধারণ ক্ষেত্রে বেশিরভাগ ফাংশন একাধিক ফাংশন কল করে। এই অপ্টিমাইজেশন ধারণাটি প্রয়োগ হতে পারে যদি আপনি x
প্রথমটির আগে এবং শেষের ঠিক আগে কোনও কলগুলির মধ্যে না ব্যবহার করেন, অন্যথায় call
যদি আপনি একটি পপ করার পরে একটি পপ করছেন তবে আপনার প্রতিটির জন্য 16-বাইট স্ট্যাক সারিবদ্ধতা বজায় রাখার সমস্যা আছে কল, অন্য কল আগে।
সংযোজনকারীরা সাধারণভাবে ছোট কার্যগুলিতে দুর্দান্ত হয় না। তবে সিপিইউগুলির পক্ষে এটি দুর্দান্ত নয়। নন-ইনলাইন ফাংশন কলগুলি সর্বোত্তম সময়ে অনুকূলিতকরণের উপর প্রভাব ফেলে, যদি না সংকলকরা কলির অভ্যন্তরীণ অংশ দেখতে এবং স্বাভাবিকের চেয়ে বেশি অনুমান করতে না পারে। একটি অন-ইনলাইন ফাংশন কল একটি অন্তর্নিহিত মেমরি বাধা: একজন কলকারীকে ধরে নিতে হয় যে কোনও ফাংশন বিশ্বব্যাপী অ্যাক্সেসযোগ্য ডেটা পড়তে বা লিখতে পারে, সুতরাং এই জাতীয় সমস্ত ভার সি সি বিমূর্ত মেশিনের সাথে সিঙ্ক করতে হবে। (এস্কেপ এনালাইসিসের সাহায্যে স্থানীয়দের কলগুলিতে রেজিস্টারে রাখার অনুমতি দেয় যদি তাদের ঠিকানা ফাংশনটি এড়ায় না)) এছাড়াও, সংকলকটি ধরে নিতে হবে যে কল-ক্লোবারযুক্ত রেজিস্টারগুলি সমস্ত ক্লোবারড। এটি x86-64 সিস্টেম ভি-তে ভাসমান পয়েন্টটির জন্য স্তন্যপান করে, এতে কোনও কল-সংরক্ষিত এক্সএমএম রেজিস্টর নেই।
ক্ষুদ্র ফাংশনগুলি যেমন bar()
তাদের কলকারীদের মধ্যে অন্তর্ভুক্ত করা ভাল। সংকলন করুন -flto
যাতে এটি বেশিরভাগ ক্ষেত্রে ফাইলের সীমানা জুড়েও ঘটতে পারে। (ফাংশন পয়েন্টার এবং ভাগ-লাইব্রেরি সীমানা এটি পরাস্ত করতে পারে।)
আমি মনে করি যে একটি কারণ সংকলকগণ এই অপ্টিমাইজেশানগুলি করার চেষ্টা করতে বিরক্ত করেননি তা হ'ল এটির জন্য সাধারণ স্ট্যাক বনাম রেজিস্টার-বরাদ্দ কোডের চেয়ে পৃথক সংস্থাগুলির বিভিন্ন কোডের পুরো গোছা প্রয়োজন হবে যা কল-সংরক্ষিত কীভাবে সংরক্ষণ করতে জানে knows নিবন্ধ এবং তাদের ব্যবহার।
অর্থাত্ এটি বাস্তবায়নের জন্য অনেক কাজ হবে এবং অনেকগুলি কোড বজায় রাখতে হবে এবং এটি করার বিষয়ে যদি এটি অত্যধিক উত্সাহী হয় তবে এটি আরও খারাপ কোড তৈরি করতে পারে ।
এবং এটিও (আশাকরি) তাৎপর্যপূর্ণ নয়; যদি এটি গুরুত্বপূর্ণ bar
হয় তবে আপনার এটির কলারের সাথে সন্নিবেশ foo
করাতে বা ইনলাইন করা উচিত bar
। এটি ঠিক আছে যদি না প্রচুর রকমের bar
মতো ফাংশন থাকে এবং foo
এটি বড় না হয় এবং কোনও কারণে তারা তাদের কলকারীদের সাথে ইনলাইন করতে না পারে।