আমি STAPL প্রকল্পে কাজ করি যা একটি ভারী-টেম্পলেটেড সি ++ লাইব্রেরি। একবারে একবারে, সংকলনের সময় হ্রাস করার জন্য আমাদের সমস্ত কৌশল পুনর্বিবেচনা করতে হবে। এখানে, আমি যে কৌশলগুলি ব্যবহার করি তার সংক্ষিপ্তসার করেছি। এর মধ্যে কয়েকটি কৌশল ইতিমধ্যে উপরে তালিকাবদ্ধ রয়েছে:
সর্বাধিক সময় ব্যয়কারী বিভাগগুলি সন্ধান করা
যদিও প্রতীক দৈর্ঘ্য এবং সংকলনের সময়ের মধ্যে কোনও প্রমাণিত সম্পর্ক নেই, আমরা লক্ষ্য করেছি যে ছোট গড় প্রতীক মাপগুলি সমস্ত সংকলকগুলির সংকলনের সময়কে উন্নত করতে পারে। সুতরাং আপনার কোডটিতে সর্বাধিক চিহ্নগুলি খুঁজে পেতে আপনার প্রথম লক্ষ্যগুলি।
পদ্ধতি 1 - আকারের ভিত্তিতে চিহ্নগুলি বাছাই করুন
nmচিহ্নগুলি তাদের আকারের উপর ভিত্তি করে তালিকা তৈরি করতে আপনি কমান্ডটি ব্যবহার করতে পারেন :
nm --print-size --size-sort --radix=d YOUR_BINARY
এই কমান্ডটিতে --radix=dআপনাকে দশমিক সংখ্যায় মাপ দেখতে দেয় (ডিফল্ট হেক্স হেক্স)। এখন বৃহত্তম প্রতীকটি দেখে আপনি শনাক্ত করতে পারেন যে আপনি সংশ্লিষ্ট বর্গটি ভেঙে ফেলতে পারেন এবং বেস-ক্লাসে অ-টেম্প্লেটেড অংশগুলি ফ্যাক্টর করে বা ক্লাসটিকে একাধিক শ্রেণিতে বিভক্ত করে পুনরায় ডিজাইনের চেষ্টা করতে পারেন।
পদ্ধতি 2 - দৈর্ঘ্যের ভিত্তিতে প্রতীকগুলি বাছাই করুন
আপনি নিয়মিত nmকমান্ড চালাতে পারেন এবং চিহ্নগুলির দৈর্ঘ্যের উপর ভিত্তি করে সাজানোর জন্য এটি আপনার প্রিয় স্ক্রিপ্ট ( এডাব্লুকে , পাইথন , ইত্যাদি) এ পাইপ করতে পারেন । আমাদের অভিজ্ঞতার ভিত্তিতে, এই পদ্ধতিটি পদ্ধতি 1 এর চেয়ে ভাল প্রার্থীদের তৈরি করা সবচেয়ে বড় সমস্যা চিহ্নিত করে।
পদ্ধতি 3 - টেম্পলাইট ব্যবহার করুন
" Templight একটি হল ঝনঝন ভিত্তিক সময় এবং টেমপ্লেট instantiations স্মৃতির খরচ প্রোফাইলে এবং টেমপ্লেট ইনস্ট্যান্স প্রক্রিয়ার মধ্যে অন্তর্দর্শন লাভ ইন্টারেক্টিভ ডিবাগিং সেশন সম্পাদন করতে টুল"।
আপনি এলএলভিএম এবং কলং ( নির্দেশাবলী ) পরীক্ষা করে এবং এতে টেম্পলাইট প্যাচ প্রয়োগ করে টেম্পলাইট ইনস্টল করতে পারেন । এলএলভিএম এবং ক্ল্যাংয়ের ডিফল্ট সেটিংটি ডিবাগ এবং দৃ .়তার সাথে চলছে এবং এগুলি আপনার সংকলনের সময়কে উল্লেখযোগ্যভাবে প্রভাবিত করতে পারে। দেখে মনে হচ্ছে টেম্পলাইট উভয়েরই দরকার, তাই আপনাকে ডিফল্ট সেটিংস ব্যবহার করতে হবে। এলএলভিএম এবং কলং ইনস্টল করার প্রক্রিয়াটিতে প্রায় এক ঘন্টা বা আরও বেশি সময় লাগবে।
প্যাচ প্রয়োগ করার পরে আপনি templight++আপনার কোডটি সংকলন করার জন্য ইনস্টলেশনের উপরে নির্দিষ্ট বিল্ড ফোল্ডারে অবস্থিত ব্যবহার করতে পারেন ।
templight++এটি আপনার রাস্তায় রয়েছে তা নিশ্চিত করুন । CXXFLAGSআপনার মেকফাইলে বা আপনার কমান্ড লাইন বিকল্পগুলিতে নিম্নলিখিত স্যুইচগুলি সংকলন করতে:
CXXFLAGS+=-Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system
অথবা
templight++ -Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system
সংকলন সম্পন্ন হওয়ার পরে, আপনি একই ফোল্ডারে একটি .trace.memory.pbf এবং .trace.pbf তৈরি করতে পারবেন। এই চিহ্নগুলি কল্পনা করতে, আপনি টেম্পলাইট সরঞ্জামগুলি ব্যবহার করতে পারেন যা এগুলিকে অন্য ফর্ম্যাটে রূপান্তর করতে পারে। টেমপ্লাইট-রূপান্তর ইনস্টল করতে এই নির্দেশাবলী অনুসরণ করুন । আমরা সাধারণত কলগ্রিনড আউটপুট ব্যবহার করি। আপনার প্রকল্পটি যদি ছোট হয় তবে আপনি গ্রাফভিজ আউটপুটও ব্যবহার করতে পারেন:
$ templight-convert --format callgrind YOUR_BINARY --output YOUR_BINARY.trace
$ templight-convert --format graphviz YOUR_BINARY --output YOUR_BINARY.dot
উত্পাদিত কলগ্রাইন্ড ফাইলটি কেচেচেগ্রিন্ড ব্যবহার করে খোলার সুযোগ রয়েছে যেখানে আপনি সর্বাধিক সময় / মেমরি গ্রহণকারী ইনস্ট্যান্টেশন ব্যবহার করতে পারেন।
টেমপ্লেট ইনস্ট্যান্টেশনের সংখ্যা হ্রাস করা হচ্ছে
যদিও টেমপ্লেট ইনস্ট্যান্টেশনগুলির সংখ্যা হ্রাস করার কোনও সঠিক সমাধান নেই, তবে কয়েকটি নির্দেশিকা যা সহায়তা করতে পারে:
একাধিক টেম্পলেট আর্গুমেন্ট সহ রিফ্যাক্টর ক্লাস
উদাহরণস্বরূপ, যদি আপনার কোনও ক্লাস থাকে,
template <typename T, typename U>
struct foo { };
এবং উভয় Tএবং U10 বিভিন্ন অপশন থাকতে পারে, আপনি এই শ্রেণীর সম্ভাব্য টেমপ্লেট instantiations 100 ওয়ান ওয়ে এই বিমূর্ত একটি ভিন্ন ক্লাসে কোডের সাধারণ অংশ সমাধান করতে বেড়েছে। অন্য পদ্ধতিটি হ'ল উত্তরাধিকার বিপরীতমুখীকরণ (শ্রেণি শ্রেণিবিন্যাসকে বিপরীত করে) ব্যবহার করা, তবে নিশ্চিত করুন যে এই কৌশলটি ব্যবহারের আগে আপনার নকশাগুলির লক্ষ্যগুলি আপোষযুক্ত নয়।
রিফ্যাক্টর স্বতন্ত্র অনুবাদ ইউনিটগুলিতে অ-তাত্পর্যযুক্ত কোড
এই কৌশলটি ব্যবহার করে আপনি সাধারণ বিভাগটি একবার সংকলন করতে পারেন এবং এটির পরে আপনার অন্যান্য টিউ (অনুবাদ ইউনিট) এর সাথে লিঙ্ক করতে পারেন।
বাহ্যিক টেম্পলেট ইনস্ট্যান্টেশন ব্যবহার করুন (সি ++ 11 থেকে)
আপনি যদি কোনও শ্রেণীর সমস্ত সম্ভাব্য ইনস্ট্যানটিশনগুলি জানেন তবে আপনি এই কৌশলটি কোনও ভিন্ন অনুবাদ ইউনিটে সমস্ত কেস সংকলন করতে ব্যবহার করতে পারেন।
উদাহরণস্বরূপ, এতে:
enum class PossibleChoices = {Option1, Option2, Option3}
template <PossibleChoices pc>
struct foo { };
আমরা জানি যে এই শ্রেণীর তিনটি সম্ভাব্য তাত্পর্য থাকতে পারে:
template class foo<PossibleChoices::Option1>;
template class foo<PossibleChoices::Option2>;
template class foo<PossibleChoices::Option3>;
উপরেরটিকে একটি অনুবাদ ইউনিটে রাখুন এবং শ্রেণীর সংজ্ঞার নীচে আপনার শিরোনাম ফাইলে বহিরাগত কীওয়ার্ডটি ব্যবহার করুন:
extern template class foo<PossibleChoices::Option1>;
extern template class foo<PossibleChoices::Option2>;
extern template class foo<PossibleChoices::Option3>;
আপনি যদি ইনস্ট্যান্টেশনের একটি সাধারণ সেট দিয়ে বিভিন্ন পরীক্ষা সংকলন করেন তবে এই কৌশলটি আপনার সময় বাঁচাতে পারে।
দ্রষ্টব্য: এমপিআইএইচ 2 এই মুহূর্তে সুস্পষ্ট ইনস্ট্যান্টেশন উপেক্ষা করে এবং সর্বদা সমস্ত সংকলন ইউনিটে ইনস্ট্যান্টেটেড ক্লাসগুলি সংকলন করে।
Unityক্য গড়ে তোলে ব্যবহার করুন
Unityক্য তৈরির পেছনের পুরো ধারণাটি হ'ল আপনি একটি ফাইলের মধ্যে ব্যবহার করেন এমন সমস্ত .cc ফাইল অন্তর্ভুক্ত করা এবং সেই ফাইলটি কেবল একবার সংকলন করা। এই পদ্ধতিটি ব্যবহার করে, আপনি বিভিন্ন ফাইলগুলির সাধারণ বিভাগগুলিকে পুনর্বহাল করা এড়াতে পারবেন এবং যদি আপনার প্রকল্পে প্রচুর প্রচলিত ফাইল অন্তর্ভুক্ত থাকে তবে আপনি সম্ভবত ডিস্ক অ্যাক্সেসগুলিতেও সঞ্চয় করতে পারেন।
উদাহরণস্বরূপ, এর অনুমান করা আপনি তিনটি ফাইল আছে যাক foo1.cc, foo2.cc, foo3.ccএবং তারা সব অন্তর্ভুক্ত tupleথেকে STL । আপনি দেখতে এমন একটি তৈরি করতে foo-all.ccপারেন:
#include "foo1.cc"
#include "foo2.cc"
#include "foo3.cc"
আপনি কেবল একবার এই ফাইলটি সঙ্কলন করুন এবং তিনটি ফাইলের মধ্যে সাধারণ তাত্পর্যকে সম্ভাব্যভাবে হ্রাস করুন। উন্নতিটি তাৎপর্যপূর্ণ হতে পারে কি না তা সাধারণত অনুমান করা শক্ত। তবে একটি স্পষ্ট সত্য হ'ল আপনি নিজের বিল্ডগুলির মধ্যে সমান্তরালতা হারাবেন (আপনি আর তিনটি ফাইল একই সাথে সংকলন করতে পারবেন না)।
তদ্ব্যতীত, এই ফাইলগুলির মধ্যে যদি খুব বেশি মেমরি নেওয়ার ঘটনা ঘটে তবে সংকলন শেষ হওয়ার আগে আপনি সম্ভবত মেমরির বাইরে চলে যাবেন। কিছু সংকলক যেমন জিসিসিতে , এটি মেমরির অভাবে আপনার সংকলককে আইসিই (অভ্যন্তরীণ সংকলক ত্রুটি) করতে পারে। সুতরাং আপনি সমস্ত উপকারিতা এবং কনস যদি না জানেন তবে এই কৌশলটি ব্যবহার করবেন না।
পূর্বনির্ধারিত শিরোনাম
প্রম্পম্পাইল্ড শিরোনাম (পিসিএইচ) আপনার শিরোনামের ফাইলগুলি সংকলক দ্বারা সনাক্তযোগ্য একটি মধ্যবর্তী প্রতিনিধিতে সংকলন করে আপনাকে অনেক সময় সাশ্রয় করতে পারে। প্রাকম্পম্পাইল্ড হেডার ফাইলগুলি তৈরি করতে আপনাকে কেবল আপনার নিয়মিত সংকলন কমান্ড দিয়ে আপনার শিরোনাম ফাইলটি সংকলন করতে হবে। উদাহরণস্বরূপ, জিসিসিতে:
$ g++ YOUR_HEADER.hpp
এটি একই ফোল্ডারে একটি YOUR_HEADER.hpp.gch file( .gchজিসিসিতে পিসিএইচ ফাইলগুলির জন্য এক্সটেনশন) উত্পন্ন করবে । এর অর্থ হ'ল আপনি যদি YOUR_HEADER.hppঅন্য কোনও ফাইলে অন্তর্ভুক্ত করেন তবে সংকলকটি আগের ফোল্ডারের YOUR_HEADER.hpp.gchপরিবর্তে আপনার ব্যবহার করবে YOUR_HEADER.hpp।
এই কৌশলটি নিয়ে দুটি সমস্যা রয়েছে:
- আপনাকে নিশ্চিত করতে হবে যে হেডার ফাইলগুলি পূর্বনির্ধারিত হচ্ছে স্থিতিশীল এবং কোনও পরিবর্তন হচ্ছে না ( আপনি সর্বদা নিজের মেকফিল পরিবর্তন করতে পারেন )
- আপনি কেবল প্রতি সংকলন ইউনিটে একটি পিসিএইচ অন্তর্ভুক্ত করতে পারেন (বেশিরভাগ সংকলককে)। এর অর্থ হ'ল যদি আপনার একাধিক হেডার ফাইল প্রাকপম্পাইল করতে হয় তবে আপনাকে সেগুলি একটি ফাইলে অন্তর্ভুক্ত করতে হবে (যেমন,
all-my-headers.hpp)। তবে এর অর্থ হ'ল আপনাকে নতুন জায়গায় সমস্ত জায়গায় অন্তর্ভুক্ত করতে হবে। ভাগ্যক্রমে, জিসিসির কাছে এই সমস্যার সমাধান রয়েছে। এটি ব্যবহার -includeকরে নতুন হেডার ফাইলটি দিন। আপনি এই কৌশলটি ব্যবহার করে কমা বিভিন্ন ফাইল পৃথক করতে পারেন।
উদাহরণ স্বরূপ:
g++ foo.cc -include all-my-headers.hpp
নামবিহীন বা নামবিহীন নেমস্পেস ব্যবহার করুন
নামবিহীন নেমস্পেসস (ওরফে নামবিহীন নেমস্পেসস) উত্পাদিত বাইনারি আকারগুলি উল্লেখযোগ্যভাবে হ্রাস করতে পারে। নামবিহীন নেমস্পেসগুলি অভ্যন্তরীণ লিঙ্কেজ ব্যবহার করে, যার অর্থ এই যে নামগুলি স্পেসে উত্পন্ন চিহ্নগুলি অন্যান্য টিইউতে (অনুবাদ বা সংকলনের ইউনিট) দৃশ্যমান হবে না। সংকলক সাধারণত নামবিহীন নামের জন্য অনন্য নাম উত্পন্ন করে। এর অর্থ হল আপনার যদি foo.hpp ফাইল থাকে:
namespace {
template <typename T>
struct foo { };
} // Anonymous namespace
using A = foo<int>;
এবং আপনি এই ফাইলটিকে দুটি টিইউতে অন্তর্ভুক্ত করতে পারেন (দুটি .সিসি ফাইল এবং এগুলি পৃথকভাবে সংকলন করুন)। দুটি ফু টেম্পলেট উদাহরণ এক হবে না। এটি ওয়ান ডেফিনিশন রুল (ওডিআর) লঙ্ঘন করে । একই কারণে, শিরোনাম ফাইলগুলিতে নামবিহীন নেমস্পেস ব্যবহার করা নিরুৎসাহিত করা হয়। .ccআপনার বাইনারি ফাইলগুলিতে চিহ্নগুলি প্রদর্শিত না থেকে বাঁচতে এগুলি আপনার ফাইলগুলিতে নির্দ্বিধায় ব্যবহার করুন । কিছু ক্ষেত্রে, কোনও .ccফাইলের জন্য সমস্ত অভ্যন্তরীণ বিবরণ পরিবর্তন করা উত্পন্ন বাইনারি আকারগুলিতে 10% হ্রাস দেখিয়েছিল।
দৃশ্যমানতার বিকল্পগুলি পরিবর্তন করা
নতুন সংকলকগুলিতে আপনি ডায়নামিক শেয়ার্ড অবজেক্টস (ডিএসও) তে দৃশ্যমান বা অদৃশ্য হওয়ার জন্য আপনার প্রতীকগুলি নির্বাচন করতে পারেন। আদর্শভাবে, দৃশ্যমানতা পরিবর্তন করা সংকলক কর্মক্ষমতা, লিংক সময় অপ্টিমাইজেশন (এলটিও), এবং বাইনারি আকারের উত্পন্ন করতে পারে। আপনি যদি জিসিসিতে এসটিএল হেডার ফাইলগুলি দেখেন তবে দেখতে পাবেন এটি ব্যাপকভাবে ব্যবহৃত হয়েছে। দৃশ্যমানতার পছন্দগুলি সক্ষম করতে, আপনাকে প্রতি ক্লাসে প্রতি ক্লাসে প্রতি ভেরিয়েবল এবং আরও গুরুত্বপূর্ণভাবে প্রতি সংকলক প্রতি আপনার কোড পরিবর্তন করতে হবে।
দৃশ্যমানতার সাহায্যে আপনি যে চিহ্নগুলি তৈরি করেছেন তা ভাগ করা বস্তুগুলি থেকে ব্যক্তিগত হিসাবে বিবেচনা করতে পারবেন hide জিসিসিতে আপনি -visibilityআপনার সংকলকটির বিকল্পটিতে ডিফল্ট বা লুকিয়ে রেখে চিহ্নগুলির দৃশ্যমানতা নিয়ন্ত্রণ করতে পারেন । এটি কিছুটা নামবিহীন নেমস্পেসের অনুরূপ তবে আরও বিস্তৃত এবং অনুপ্রবেশজনক উপায়ে।
আপনি যদি প্রতি কেস দৃশ্যমানতা নির্দিষ্ট করতে চান, আপনাকে আপনার ফাংশন, ভেরিয়েবল এবং ক্লাসে নিম্নলিখিত বৈশিষ্ট্যগুলি যুক্ত করতে হবে:
__attribute__((visibility("default"))) void foo1() { }
__attribute__((visibility("hidden"))) void foo2() { }
__attribute__((visibility("hidden"))) class foo3 { };
void foo4() { }
জিসিসিতে ডিফল্ট দৃশ্যমানতা ডিফল্ট (সর্বজনীন), এর অর্থ হ'ল আপনি উপরেরটি একটি ভাগ করা লাইব্রেরি ( -shared) পদ্ধতি হিসাবে সংকলন করেন foo2এবং ক্লাসটি foo3অন্যান্য টিইউতে দৃশ্যমান হবে না ( foo1এবং foo4দৃশ্যমান হবে)। আপনি যদি সংকলন করেন -visibility=hiddenতবে কেবল foo1দৃশ্যমান হবে। এমনকি foo4গোপন করা হবে।
আপনি জিসিসি উইকিতে দৃশ্যমানতা সম্পর্কে আরও পড়তে পারেন ।