ভূমিকা
ড্যানিয়েল ক্লিফোর্ড V8-এ JavaScript পারফরম্যান্স উন্নত করার জন্য টিপস এবং কৌশলগুলির বিষয়ে Google I/O-এ একটি চমৎকার বক্তৃতা দিয়েছেন। ড্যানিয়েল আমাদেরকে "দ্রুত ডিমান্ড" করতে উৎসাহিত করেছেন - C++ এবং JavaScript-এর মধ্যে পারফরম্যান্সের পার্থক্যগুলিকে সাবধানে বিশ্লেষণ করতে এবং জাভাস্ক্রিপ্ট কীভাবে কাজ করে সে বিষয়ে মন দিয়ে কোড লিখতে। ড্যানিয়েলের আলোচনার সবচেয়ে গুরুত্বপূর্ণ বিষয়গুলির একটি সারসংক্ষেপ এই নিবন্ধে ধারণ করা হয়েছে, এবং আমরা এই নিবন্ধটিকে কর্মক্ষমতা নির্দেশিকা পরিবর্তন হিসাবে আপডেট রাখব।
সবচেয়ে গুরুত্বপূর্ণ পরামর্শ
কোন পারফরম্যান্স পরামর্শ প্রসঙ্গে রাখা গুরুত্বপূর্ণ। পারফরম্যান্স পরামর্শ আসক্তিযুক্ত, এবং কখনও কখনও প্রথমে গভীর পরামর্শের উপর ফোকাস করা আসল সমস্যাগুলি থেকে বেশ বিভ্রান্তিকর হতে পারে। আপনার ওয়েব অ্যাপ্লিকেশানের পারফরম্যান্সের একটি সামগ্রিক দৃষ্টিভঙ্গি নিতে হবে - এই পারফরম্যান্স টিপগুলিতে ফোকাস করার আগে, আপনার সম্ভবত PageSpeed এর মতো সরঞ্জামগুলির সাথে আপনার কোড বিশ্লেষণ করা উচিত এবং আপনার স্কোর বাড়াতে হবে৷ এটি আপনাকে অকাল অপ্টিমাইজেশন এড়াতে সাহায্য করবে।
ওয়েব অ্যাপ্লিকেশনগুলিতে ভাল পারফরম্যান্স পাওয়ার জন্য সর্বোত্তম প্রাথমিক পরামর্শ হল:
- আপনার কোন সমস্যা (বা লক্ষ্য করার) আগে প্রস্তুত থাকুন
- তারপর, আপনার সমস্যার মূলটি সনাক্ত করুন এবং বুঝুন
- অবশেষে, যা গুরুত্বপূর্ণ তা ঠিক করুন
এই পদক্ষেপগুলি সম্পন্ন করার জন্য, V8 কীভাবে JS অপ্টিমাইজ করে তা বোঝা গুরুত্বপূর্ণ হতে পারে, যাতে আপনি JS রানটাইম ডিজাইনের প্রতি সচেতন হয়ে কোড লিখতে পারেন। উপলভ্য সরঞ্জামগুলি এবং সেগুলি কীভাবে আপনাকে সাহায্য করতে পারে সে সম্পর্কে জানাও গুরুত্বপূর্ণ৷ ড্যানিয়েল তার বক্তৃতায় বিকাশকারী সরঞ্জামগুলি কীভাবে ব্যবহার করবেন তার আরও কিছু ব্যাখ্যায় যায়; এই ডকুমেন্টটি V8 ইঞ্জিন ডিজাইনের সবচেয়ে গুরুত্বপূর্ণ কিছু পয়েন্ট ক্যাপচার করে।
সুতরাং, ভি 8 টিপস এ!
লুকানো ক্লাস
জাভাস্ক্রিপ্টে সীমিত কম্পাইল-টাইপ টাইপ তথ্য রয়েছে: রানটাইমে প্রকারগুলি পরিবর্তন করা যেতে পারে, তাই এটি আশা করা স্বাভাবিক যে কম্পাইলের সময় JS প্রকারগুলি সম্পর্কে যুক্তি দেওয়া ব্যয়বহুল। এটি আপনাকে প্রশ্ন করতে পারে যে কীভাবে জাভাস্ক্রিপ্টের কার্যকারিতা C++ এর কাছাকাছি কোথাও যেতে পারে। যাইহোক, V8 লুকানো প্রকার রয়েছে যা রানটাইমে বস্তুর জন্য অভ্যন্তরীণভাবে তৈরি করা হয়েছে; একই হিডেন ক্লাসের অবজেক্টগুলি একই অপ্টিমাইজড জেনারেটেড কোড ব্যবহার করতে পারে।
যেমন:
function Point(x, y) {
this.x = x;
this.y = y;
}
var p1 = new Point(11, 22);
var p2 = new Point(33, 44);
// At this point, p1 and p2 have a shared hidden class
p2.z = 55;
// warning! p1 and p2 now have different hidden classes!```
অবজেক্ট ইন্সট্যান্স p2-এ অতিরিক্ত সদস্য ".z" যোগ না হওয়া পর্যন্ত, p1 এবং p2 অভ্যন্তরীণভাবে একই লুকানো শ্রেণী থাকে - তাই V8 জাভাস্ক্রিপ্ট কোডের জন্য অপ্টিমাইজ করা সমাবেশের একটি একক সংস্করণ তৈরি করতে পারে যা p1 বা p2 উভয়ই হেরফের করে। আপনি যত বেশি লুকানো ক্লাসগুলিকে বিচ্ছিন্ন করার কারণ এড়াতে পারবেন, ততই ভাল পারফরম্যান্স আপনি পাবেন।
অতএব
- কনস্ট্রাক্টর ফাংশনে সমস্ত অবজেক্ট সদস্যদের শুরু করুন (তাই দৃষ্টান্তগুলি পরে টাইপ পরিবর্তন না করে)
- সর্বদা একই ক্রমে অবজেক্ট সদস্য শুরু করুন
সংখ্যা
V8 মানগুলিকে দক্ষতার সাথে উপস্থাপন করতে ট্যাগিং ব্যবহার করে যখন প্রকারগুলি পরিবর্তন হতে পারে। V8 মানগুলি থেকে অনুমান করে যে আপনি কোন ধরণের সংখ্যার সাথে কাজ করছেন। একবার V8 এই অনুমান তৈরি করলে, এটি মানগুলিকে দক্ষতার সাথে উপস্থাপন করতে ট্যাগিং ব্যবহার করে, কারণ এই প্রকারগুলি গতিশীলভাবে পরিবর্তিত হতে পারে। যাইহোক, কখনও কখনও এই ধরনের ট্যাগগুলি পরিবর্তন করতে খরচ হয়, তাই ধারাবাহিকভাবে সংখ্যার ধরনগুলি ব্যবহার করা সর্বোত্তম, এবং সাধারণভাবে যেখানে উপযুক্ত সেখানে 31-বিট স্বাক্ষরিত পূর্ণসংখ্যা ব্যবহার করা সবচেয়ে অনুকূল।
যেমন:
var i = 42; // this is a 31-bit signed integer
var j = 4.2; // this is a double-precision floating point number```
অতএব
- সাংখ্যিক মান পছন্দ করুন যা 31-বিট স্বাক্ষরিত পূর্ণসংখ্যা হিসাবে উপস্থাপন করা যেতে পারে।
অ্যারে
বড় এবং স্পার্স অ্যারেগুলি পরিচালনা করার জন্য, অভ্যন্তরীণভাবে দুটি ধরণের অ্যারে স্টোরেজ রয়েছে:
- দ্রুত উপাদান: কমপ্যাক্ট কী সেটের জন্য লিনিয়ার স্টোরেজ
- অভিধান উপাদান: হ্যাশ টেবিল স্টোরেজ অন্যথায়
অ্যারে স্টোরেজকে এক প্রকার থেকে অন্য প্রকারে ফ্লিপ না করাই ভাল।
অতএব
- অ্যারেগুলির জন্য 0 থেকে শুরু হওয়া সংলগ্ন কীগুলি ব্যবহার করুন
- বড় অ্যারেগুলিকে (যেমন > 64K উপাদানগুলি) তাদের সর্বাধিক আকারে আগে থেকে বরাদ্দ করবেন না, পরিবর্তে আপনি যেতে যেতে বাড়ান
- অ্যারেগুলিতে উপাদানগুলি মুছে ফেলবেন না, বিশেষ করে সংখ্যাসূচক অ্যারে
- শুরু না করা বা মুছে ফেলা উপাদানগুলি লোড করবেন না:
for (var b = 0; b < 10; b++) {
a[0] |= b; // Oh no!
}
//vs.
a = new Array();
a[0] = 0;
for (var b = 0; b < 10; b++) {
a[0] |= b; // Much better! 2x faster.
}
এছাড়াও, ডবলের অ্যারেগুলি দ্রুততর হয় - অ্যারের লুকানো ক্লাস ট্র্যাক উপাদানের ধরন, এবং কেবলমাত্র ডাবল সম্বলিত অ্যারেগুলি আনবক্স করা হয় (যা একটি লুকানো শ্রেণী পরিবর্তনের কারণ হয়)৷ তবে, অ্যারেগুলির অসাবধান হেরফের বক্সিং এবং আনবক্সিং-এর কারণে অতিরিক্ত কাজ করতে পারে - যেমন
var a = new Array();
a[0] = 77; // Allocates
a[1] = 88;
a[2] = 0.5; // Allocates, converts
a[3] = true; // Allocates, converts```
এর চেয়ে কম দক্ষ:
var a = [77, 88, 0.5, true];
কারণ প্রথম উদাহরণে স্বতন্ত্র অ্যাসাইনমেন্টগুলি একের পর এক সঞ্চালিত হয়, এবং a[2]
এর অ্যাসাইনমেন্টের ফলে অ্যারেটিকে আনবক্সড ডাবলের অ্যারেতে রূপান্তরিত করা হয়, কিন্তু তারপরে a[3]
এর অ্যাসাইনমেন্ট এটিকে পুনরায় হতে দেয়। আবার একটি অ্যারেতে রূপান্তরিত করা হয়েছে যাতে যেকোনো মান (সংখ্যা বা বস্তু) থাকতে পারে। দ্বিতীয় ক্ষেত্রে, কম্পাইলার আক্ষরিক সমস্ত উপাদানের ধরন জানে এবং লুকানো শ্রেণীটি সামনের দিকে নির্ধারণ করা যেতে পারে।
- ছোট নির্দিষ্ট আকারের অ্যারের জন্য অ্যারে লিটারেল ব্যবহার করে শুরু করুন
- ছোট অ্যারে (<64k) ব্যবহার করার আগে সঠিক আকারের জন্য পূর্বনির্ধারণ করুন
- সংখ্যাসূচক অ্যারেগুলিতে অ-সংখ্যাসূচক মান (বস্তু) সংরক্ষণ করবেন না
- আপনি যদি আক্ষরিক ছাড়াই আরম্ভ করেন তবে ছোট অ্যারের পুনরায় রূপান্তর না হওয়ার বিষয়ে সতর্ক থাকুন।
জাভাস্ক্রিপ্ট সংকলন
যদিও জাভাস্ক্রিপ্ট একটি খুব গতিশীল ভাষা, এবং এটির মূল বাস্তবায়ন ছিল দোভাষী, আধুনিক জাভাস্ক্রিপ্ট রানটাইম ইঞ্জিনগুলি সংকলন ব্যবহার করে। V8 (Chrome's JavaScript) এর দুটি ভিন্ন জাস্ট-ইন-টাইম (JIT) কম্পাইলার রয়েছে, আসলে:
- "সম্পূর্ণ" কম্পাইলার, যা যেকোনো জাভাস্ক্রিপ্টের জন্য ভালো কোড তৈরি করতে পারে
- অপ্টিমাইজিং কম্পাইলার, যা বেশিরভাগ জাভাস্ক্রিপ্টের জন্য দুর্দান্ত কোড তৈরি করে, কিন্তু কম্পাইল করতে বেশি সময় নেয়।
সম্পূর্ণ কম্পাইলার
V8-এ, সম্পূর্ণ কম্পাইলার সমস্ত কোডে চলে এবং যত তাড়াতাড়ি সম্ভব কোড নির্বাহ করা শুরু করে, দ্রুত ভালো কোড তৈরি করে কিন্তু দুর্দান্ত কোড নয়। এই কম্পাইলার কম্পাইলেশনের সময় প্রকার সম্পর্কে প্রায় কিছুই অনুমান করে না - এটি আশা করে যে প্রকারের ভেরিয়েবল রানটাইমে পরিবর্তিত হতে পারে এবং হবে। ফুল কম্পাইলার দ্বারা উত্পন্ন কোড ইনলাইন ক্যাশে (ICs) ব্যবহার করে প্রোগ্রাম চালানোর সময় প্রকার সম্পর্কে জ্ঞান পরিমার্জিত করতে, উড়ে যাওয়ার সময় দক্ষতা উন্নত করে।
ইনলাইন ক্যাশের লক্ষ্য হল অপারেশনের জন্য টাইপ-নির্ভর কোড ক্যাশিং করে দক্ষতার সাথে প্রকারগুলি পরিচালনা করা; যখন কোড রান হয়, এটি প্রথমে টাইপ অনুমান যাচাই করবে, তারপর অপারেশন শর্টকাট করতে ইনলাইন ক্যাশে ব্যবহার করবে। যাইহোক, এর মানে হল যে অপারেশনগুলি যেগুলি একাধিক প্রকার গ্রহণ করে সেগুলি কম কার্যকরী হবে৷
অতএব
- পলিমরফিক অপারেশনের চেয়ে অপারেশনের মনোমরফিক ব্যবহার পছন্দ করা হয়
ইনপুটগুলির লুকানো শ্রেণীগুলি সর্বদা একই থাকলে অপারেশনগুলি মনোমরফিক হয় - অন্যথায় সেগুলি পলিমরফিক, যার অর্থ কিছু আর্গুমেন্ট অপারেশনের বিভিন্ন কল জুড়ে ধরন পরিবর্তন করতে পারে। উদাহরণস্বরূপ, এই উদাহরণে দ্বিতীয় add() কলটি পলিমরফিজম সৃষ্টি করে:
function add(x, y) {
return x + y;
}
add(1, 2); // + in add is monomorphic
add("a", "b"); // + in add becomes polymorphic```
অপ্টিমাইজিং কম্পাইলার
সম্পূর্ণ কম্পাইলারের সমান্তরালে, V8 একটি অপ্টিমাইজিং কম্পাইলারের সাহায্যে "হট" ফাংশন (অর্থাৎ, অনেকবার চালানো হয়) ফাংশন পুনরায় কম্পাইল করে। এই কম্পাইলারটি কম্পাইল করা কোডকে দ্রুততর করার জন্য টাইপ ফিডব্যাক ব্যবহার করে - আসলে, এটি আইসি থেকে নেওয়া টাইপগুলি ব্যবহার করে যা আমরা এইমাত্র কথা বলেছি!
অপ্টিমাইজিং কম্পাইলারে, অপারেশনগুলি অনুমানমূলকভাবে ইনলাইন করা হয় (সরাসরি যেখানে তাদের বলা হয় সেখানে স্থাপন করা হয়)। এটি কার্যকর করার গতি বাড়ায় (মেমরির পদচিহ্নের মূল্যে), তবে অন্যান্য অপ্টিমাইজেশনও সক্ষম করে। মনোমরফিক ফাংশন এবং কনস্ট্রাক্টরগুলি সম্পূর্ণরূপে ইনলাইন করা যেতে পারে (এটি আরেকটি কারণ যে V8 এ মনোমরফিজম একটি ভাল ধারণা)।
V8 ইঞ্জিনের স্বতন্ত্র "d8" সংস্করণ ব্যবহার করে যা অপ্টিমাইজ করা হয় তা আপনি লগ করতে পারেন:
d8 --trace-opt primes.js
(এটি অপ্টিমাইজ করা ফাংশনের নাম stdout এ লগ করে।)
সমস্ত ফাংশন অপ্টিমাইজ করা যায় না, তবে - কিছু বৈশিষ্ট্য অপ্টিমাইজিং কম্পাইলারকে প্রদত্ত ফাংশনে চলতে বাধা দেয় (একটি "বেল-আউট")। বিশেষ করে, অপ্টিমাইজিং কম্পাইলার বর্তমানে ট্রাই {} ক্যাচ {} ব্লকের সাহায্যে ফাংশনগুলির উপর নির্ভর করে!
অতএব
- একটি নেস্টেড ফাংশনে পারফ-সংবেদনশীল কোড রাখুন যদি আপনি চেষ্টা করে থাকেন {} ক্যাচ {} ব্লকগুলি: ```js ফাংশন perf_sensitive() { // এখানে কর্মক্ষমতা-সংবেদনশীল কাজ করুন }
চেষ্টা করুন { perf_sensitive() } ধরুন (e) { // এখানে ব্যতিক্রমগুলি পরিচালনা করুন } ```
এই নির্দেশিকা সম্ভবত ভবিষ্যতে পরিবর্তিত হবে, কারণ আমরা অপ্টিমাইজিং কম্পাইলারে চেষ্টা/ক্যাচ ব্লক সক্ষম করি। আপনি উপরের মত d8-এর সাথে "--trace-opt" বিকল্পটি ব্যবহার করে কীভাবে অপ্টিমাইজিং কম্পাইলার ফাংশনগুলিতে বেইল আউট করছে তা পরীক্ষা করতে পারেন, যা আপনাকে কোন ফাংশনগুলি বেইল আউট করা হয়েছিল সে সম্পর্কে আরও তথ্য দেয়:
d8 --trace-opt primes.js
ডি-অপ্টিমাইজেশন
অবশেষে, এই কম্পাইলার দ্বারা সঞ্চালিত অপ্টিমাইজেশন অনুমানমূলক - কখনও কখনও এটি কাজ করে না, এবং আমরা পিছিয়ে যাই। "ডিঅপ্টিমাইজেশন" প্রক্রিয়াটি অপ্টিমাইজ করা কোডকে দূরে ফেলে দেয় এবং "সম্পূর্ণ" কম্পাইলার কোডে সঠিক জায়গায় এক্সিকিউশন পুনরায় শুরু করে। পুনঃঅপ্টিমাইজেশন পরে আবার ট্রিগার হতে পারে, কিন্তু স্বল্পমেয়াদী জন্য, কার্যকর করা ধীর হয়ে যায়। বিশেষ করে, ফাংশন অপ্টিমাইজ করার পর ভেরিয়েবলের লুকানো শ্রেণীতে পরিবর্তন ঘটালে এই ডিঅপ্টিমাইজেশন ঘটবে।
অতএব
- ফাংশন অপ্টিমাইজ করার পরে লুকানো ক্লাস পরিবর্তনগুলি এড়িয়ে চলুন
আপনি, অন্যান্য অপ্টিমাইজেশানের মতো, ফাংশনগুলির একটি লগ পেতে পারেন যা V8 একটি লগিং পতাকার সাথে অপ্টিমাইজ করতে হয়েছিল:
d8 --trace-deopt primes.js
অন্যান্য V8 সরঞ্জাম
যাইহোক, আপনি স্টার্টআপে Chrome-এ V8 ট্রেসিং বিকল্পগুলিও পাস করতে পারেন:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --js-flags="--trace-opt --trace-deopt"```
বিকাশকারী টুল প্রোফাইলিং ব্যবহার করার পাশাপাশি, আপনি প্রোফাইলিং করতে d8 ব্যবহার করতে পারেন:
% out/ia32.release/d8 primes.js --prof
এটি অন্তর্নির্মিত স্যাম্পলিং প্রোফাইলার ব্যবহার করে, যা প্রতি মিলিসেকেন্ডে একটি নমুনা নেয় এবং v8.log লিখে।
সংক্ষেপে
পারফরম্যান্ট জাভাস্ক্রিপ্ট তৈরি করার জন্য আপনার কোডের সাথে V8 ইঞ্জিন কীভাবে কাজ করে তা চিহ্নিত করা এবং বোঝা গুরুত্বপূর্ণ। আরও একবার, মৌলিক পরামর্শ হল:
- আপনার কোন সমস্যা (বা লক্ষ্য করার) আগে প্রস্তুত থাকুন
- তারপর, আপনার সমস্যার মূলটি সনাক্ত করুন এবং বুঝুন
- অবশেষে, যা গুরুত্বপূর্ণ তা ঠিক করুন
এর অর্থ হল আপনার জাভাস্ক্রিপ্টে সমস্যাটি নিশ্চিত করা উচিত, প্রথমে পেজস্পীডের মতো অন্যান্য সরঞ্জাম ব্যবহার করে; মেট্রিক্স সংগ্রহ করার আগে সম্ভবত বিশুদ্ধ জাভাস্ক্রিপ্ট (কোনও DOM) এ হ্রাস করা এবং তারপরে বাধাগুলি সনাক্ত করতে এবং গুরুত্বপূর্ণগুলি দূর করতে সেই মেট্রিকগুলি ব্যবহার করুন৷ আশা করি ড্যানিয়েলের আলোচনা (এবং এই নিবন্ধ) আপনাকে আরও ভালভাবে বুঝতে সাহায্য করবে কিভাবে V8 জাভাস্ক্রিপ্ট চালায় - তবে আপনার নিজের অ্যালগরিদমগুলিকে অপ্টিমাইজ করার দিকেও মনোযোগ দিতে ভুলবেন না!