paint-brush
جاوا اسکرپٹ بینچ مارکنگ کیوں گڑبڑ ہے؟کی طرف سے@asyncbanana
نئی تاریخ

جاوا اسکرپٹ بینچ مارکنگ کیوں گڑبڑ ہے؟

کی طرف سے AsyncBanana7m2025/01/04
Read on Terminal Reader

بہت لمبا؛ پڑھنے کے لئے

JavaScript بینچ مارکنگ اب بھی ضروری ہے، خاص طور پر چونکہ JavaScript زیادہ کارکردگی کے لیے حساس ایپلی کیشنز میں استعمال ہوتا ہے۔ JavaScript کے انجنوں نے وقت کے حملوں کو کم کرنے کے لیے اپنی پوری کوشش کی ہے، اس کے ساتھ [Do Not Track] جاوا اسکرپٹ انجن جان بوجھ کر وقت کی پیمائش کو غلط بناتے ہیں۔
featured image - جاوا اسکرپٹ بینچ مارکنگ کیوں گڑبڑ ہے؟
AsyncBanana HackerNoon profile picture
0-item
1-item

مجھے بینچ مارکنگ کوڈ سے نفرت ہے، بالکل کسی انسان کی طرح (جو، اس وقت، اس کے زیادہ تر ناظرین شاید ¯\ (ツ) /¯ نہیں ہیں)۔ یہ دکھاوا کرنے میں زیادہ مزہ آتا ہے کہ آپ کی قدر کی کیشنگ نے کارکردگی میں 1000% اضافہ کیا ہے بجائے اس کے کہ اس نے کیا کیا۔ افسوس، JavaScript میں بینچ مارکنگ اب بھی ضروری ہے، خاص طور پر جیسا کہ JavaScript کا استعمال زیادہ کارکردگی کے لیے حساس ایپلی کیشنز میں ہوتا ہے ( جب اسے نہیں ہونا چاہیے؟ )۔ بدقسمتی سے، اس کے بہت سے بنیادی تعمیراتی فیصلوں کی وجہ سے، JavaScript بینچ مارکنگ کو آسان نہیں بناتا ہے۔

جاوا اسکرپٹ کے ساتھ کیا غلط ہے؟

جے آئی ٹی کمپائلر درستگی کو کم کرتا ہے (؟)

جاوا اسکرپٹ جیسی جدید اسکرپٹ زبانوں کے جادوگروں سے ناواقف لوگوں کے لیے، ان کا فن تعمیر کافی پیچیدہ ہوسکتا ہے۔ کسی مترجم کے ذریعے صرف کوڈ چلانے کے بجائے جو فوری طور پر ہدایات کو تھوکا دیتا ہے، زیادہ تر JavaScript انجن ایک آرکیٹیکچر کو استعمال کرتے ہیں جو کہ C جیسی مرتب شدہ زبان سے ملتا جلتا ہے ۔


ان میں سے ہر ایک کمپائلر تالیف کے وقت اور رن ٹائم پرفارمنس کے درمیان ایک مختلف ٹریڈ آف پیش کرتا ہے، اس لیے صارف کو کمپیوٹ آپٹیمائزنگ کوڈ خرچ کرنے کی ضرورت نہیں ہے جو شاذ و نادر ہی چلایا جاتا ہے جبکہ اکثر چلائے جانے والے کوڈ کے لیے زیادہ جدید کمپائلر کی کارکردگی کے فوائد سے فائدہ اٹھاتے ہوئے ( "گرم راستے")۔ کچھ دوسری پیچیدگیاں بھی ہیں جو آپٹمائزنگ کمپائلرز کا استعمال کرتے وقت پیدا ہوتی ہیں جن میں " فنکشن مونومورفزم " جیسے فینسی پروگرامنگ الفاظ شامل ہوتے ہیں، لیکن میں آپ کو چھوڑ دوں گا اور یہاں اس کے بارے میں بات کرنے سے گریز کروں گا۔


تو… یہ بینچ مارکنگ کے لیے کیوں اہمیت رکھتا ہے؟ ٹھیک ہے، جیسا کہ آپ نے اندازہ لگایا ہوگا، کیونکہ بینچ مارکنگ کوڈ کی کارکردگی کی پیمائش کر رہی ہے، اس لیے جے آئی ٹی کمپائلر کا بہت بڑا اثر ہو سکتا ہے۔ کوڈ کے چھوٹے ٹکڑے، جب بینچ مارک کیے جاتے ہیں، اکثر مکمل اصلاح کے بعد 10x+ کارکردگی میں بہتری دیکھ سکتے ہیں، جس سے نتائج میں بہت زیادہ خرابی آتی ہے۔


مثال کے طور پر، آپ کے سب سے بنیادی بینچ مارکنگ سیٹ اپ میں (متعدد وجوہات کی بنا پر نیچے کی طرح کچھ بھی استعمال نہ کریں):

 for (int i = 0; i<1000; i++) { console.time() // do some expensive work console.timeEnd() }

(فکر نہ کریں، ہم console.time کے بارے میں بھی بات کریں گے)


آپ کے بہت سے کوڈ کو چند ٹرائلز کے بعد محفوظ کر لیا جائے گا، جس سے فی آپریشن کے وقت میں نمایاں کمی واقع ہو گی۔ بینچ مارک پروگرام اکثر اس کیشنگ/آپٹیمائزیشن کو ختم کرنے کی پوری کوشش کرتے ہیں، کیونکہ یہ بعد میں بینچ مارک کے عمل میں جانچے جانے والے پروگراموں کو نسبتاً تیز تر ظاہر کر سکتا ہے۔ تاہم، آپ کو بالآخر یہ پوچھنا ہوگا کہ کیا اصلاح کے بغیر بینچ مارکس حقیقی دنیا میں کارکردگی سے مماثل ہیں۔


یقینی طور پر، بعض صورتوں میں، جیسے کبھی کبھار رسائی حاصل کیے جانے والے ویب صفحات، اصلاح کا امکان نہیں ہے، لیکن سرور جیسے ماحول میں، جہاں کارکردگی سب سے اہم ہے، اصلاح کی توقع کی جانی چاہیے۔ اگر آپ ایک سیکنڈ میں ہزاروں درخواستوں کے لیے کوڈ کے ایک ٹکڑے کو مڈل ویئر کے طور پر چلا رہے ہیں، تو آپ کو بہتر امید ہے کہ V8 اسے بہتر بنا رہا ہے۔


لہذا بنیادی طور پر، یہاں تک کہ ایک انجن کے اندر، کارکردگی کی مختلف سطحوں کے ساتھ آپ کے کوڈ کو چلانے کے 2-4 مختلف طریقے ہیں۔ اوہ، یہ بھی، بعض صورتوں میں یہ یقینی بنانا ناقابل یقین حد تک مشکل ہے کہ بعض اصلاحی سطحوں کو فعال کیا جائے۔ مزے کریں :)۔

انجن آپ کو درست وقت سے روکنے کی پوری کوشش کرتے ہیں۔

کیا آپ فنگر پرنٹنگ جانتے ہیں؟ وہ تکنیک جس نے ڈو ٹریک کو ٹریکنگ میں مدد کے لیے استعمال کرنے کی اجازت دی؟ ہاں، جاوا اسکرپٹ انجن اس کو کم کرنے کے لیے اپنی پوری کوشش کر رہے ہیں۔ یہ کوشش، وقت کے حملوں کو روکنے کے لیے ایک اقدام کے ساتھ، جاوا اسکرپٹ انجنوں کو جان بوجھ کر ٹائمنگ کو غلط بنانے کا باعث بنا، اس لیے ہیکرز موجودہ کمپیوٹرز کی کارکردگی یا ایک مخصوص آپریشن کتنا مہنگا ہے کی درست پیمائش نہیں کر سکتے۔


بدقسمتی سے، اس کا مطلب ہے کہ چیزوں کو موافقت کیے بغیر، بینچ مارکس میں ایک ہی مسئلہ ہے۔


پچھلے حصے میں دی گئی مثال غلط ہوگی، کیونکہ یہ صرف ملی سیکنڈ کے حساب سے پیمائش کرتی ہے۔ اب، performance.now() کے لیے اسے سوئچ آؤٹ کریں۔ بہت اچھا


اب، ہمارے پاس مائیکرو سیکنڈز میں ٹائم اسٹیمپ ہیں!

 // Bad console.time(); // work console.timeEnd(); // Better? const t = performance.now(); // work console.log(performance.now() - t);

سوائے… وہ سب 100μs کے اضافے میں ہیں۔ اب، وقت کے حملوں کے خطرے کو کم کرنے کے لیے کچھ ہیڈر شامل کرتے ہیں ۔ افوہ، ہم اب بھی صرف 5μs اضافہ کر سکتے ہیں۔ 5μs شاید بہت سے استعمال کے معاملات کے لیے کافی درستگی ہے، لیکن آپ کو کسی بھی ایسی چیز کے لیے کہیں اور تلاش کرنا پڑے گا جس کے لیے زیادہ گرانولریٹی کی ضرورت ہو۔ جہاں تک میں جانتا ہوں، کوئی براؤزر زیادہ دانے دار ٹائمرز کی اجازت نہیں دیتا۔ Node.js کرتا ہے، لیکن یقیناً اس کے اپنے مسائل ہیں۔


یہاں تک کہ اگر آپ براؤزر کے ذریعے اپنا کوڈ چلانے کا فیصلہ کرتے ہیں اور مرتب کرنے والے کو اپنا کام کرنے دیتے ہیں، تو واضح طور پر، اگر آپ درست وقت چاہتے ہیں تو آپ کو مزید سر درد کا سامنا کرنا پڑے گا۔ اوہ ہاں، اور تمام براؤزر برابر نہیں بنائے جاتے ہیں۔

ہر ماحول مختلف ہے۔

مجھے بن پسند ہے کہ اس نے سرور سائیڈ جاوا اسکرپٹ کو آگے بڑھانے کے لیے کیا کیا ہے، لیکن، یہ سرورز کے لیے جاوا اسکرپٹ کو بینچ مارک کرنا بہت مشکل بنا دیتا ہے۔ کچھ سال پہلے، صرف سرور سائیڈ JavaScript ماحول جن کی لوگ پرواہ کرتے تھے Node.js اور Deno تھے، دونوں نے V8 JavaScript انجن (کروم میں ایک ہی) استعمال کیا تھا۔ بن اس کے بجائے JavaScriptCore کا استعمال کرتا ہے، سفاری میں انجن، جس کی کارکردگی کی خصوصیات بالکل مختلف ہیں۔


متعدد جاوا اسکرپٹ ماحول کا یہ مسئلہ ان کی اپنی کارکردگی کی خصوصیات کے ساتھ سرور سائیڈ جاوا اسکرپٹ میں نسبتاً نیا ہے لیکن اس نے کلائنٹس کو طویل عرصے سے پریشان کر رکھا ہے۔ 3 مختلف عام طور پر استعمال ہونے والے JavaScript انجن، V8، JSC، اور SpiderMonkey برائے Chrome، Safari، اور Firefox، بالترتیب، سبھی کوڈ کے مساوی حصے پر نمایاں طور پر تیز یا سست کارکردگی کا مظاہرہ کر سکتے ہیں۔


ان اختلافات کی ایک مثال ٹیل کال آپٹیمائزیشن (TCO) میں ہے۔ TCO ان افعال کو بہتر بناتا ہے جو ان کے جسم کے آخر میں دہراتے ہیں، اس طرح:

 function factorial(i, num = 1) { if (i == 1) return num; num *= i; i--; return factorial(i, num); }


بنچ مارکنگ factorial(100000) بن میں آزمائیں۔ اب، اسی چیز کو Node.js یا Deno میں آزمائیں۔ آپ کو اس سے ملتی جلتی ایک خرابی ملنی چاہئے:

 function factorial(i, num = 1) { ^ RangeError: Maximum call stack size exceeded


V8 میں (اور ایکسٹینشن Node.js اور Deno کے ذریعے)، ہر بار جب factorial() آخر میں خود کو کال کرتا ہے، انجن نیسٹڈ فنکشن کو چلانے کے لیے ایک بالکل نیا فنکشن سیاق و سباق بناتا ہے، جو آخر کار کال اسٹیک کے ذریعے محدود ہوتا ہے۔ لیکن بن میں ایسا کیوں نہیں ہوتا؟ JavaScriptCore، جسے Bun استعمال کرتا ہے، TCO کو لاگو کرتا ہے، جو اس قسم کے فنکشنز کو ایک فار لوپ میں تبدیل کر کے بہتر بناتا ہے:

 function factorial(i, num = 1) { while (i != 1) { num *= i; i--; } return i; }

نہ صرف مندرجہ بالا ڈیزائن کال اسٹیک کی حدوں سے بچتا ہے، بلکہ یہ بہت تیز بھی ہے کیونکہ اسے کسی نئے فنکشن سیاق و سباق کی ضرورت نہیں ہے، یعنی اوپر والے جیسے فنکشن مختلف انجنوں کے تحت بہت مختلف طریقے سے بینچ مارک کریں گے۔


بنیادی طور پر، ان اختلافات کا مطلب صرف یہ ہے کہ آپ کو ان تمام انجنوں پر بینچ مارک کرنا چاہیے جن سے آپ اپنے کوڈ کو چلانے کی توقع کرتے ہیں تاکہ یہ یقینی بنایا جا سکے کہ ایک میں تیز رفتار کوڈ دوسرے میں سست نہیں ہے۔ اس کے علاوہ، اگر آپ ایک ایسی لائبریری تیار کر رہے ہیں جس کے استعمال کی آپ کو توقع ہے کہ بہت سے پلیٹ فارمز پر استعمال کیا جائے گا، تو یقینی بنائیں کہ مزید باطنی انجن شامل ہوں جیسے Hermes ؛ وہ کافی مختلف کارکردگی کی خصوصیات ہیں.

معزز تذکرہ

  • کوڑا اٹھانے والا اور ہر چیز کو بے ترتیب طور پر روکنے کا رجحان۔


  • جے آئی ٹی کمپائلر کی آپ کے تمام کوڈ کو حذف کرنے کی صلاحیت کیونکہ یہ "ضروری نہیں ہے۔"


  • زیادہ تر JavaScript دیو ٹولز میں خوفناک حد تک وسیع شعلہ گراف۔


  • میرے خیال میں آپ کو بات سمجھ میں آئی۔

تو… حل کیا ہے؟

میری خواہش ہے کہ میں ایک این پی ایم پیکیج کی طرف اشارہ کروں جو ان تمام مسائل کو حل کرتا ہے، لیکن واقعی ایک بھی نہیں ہے۔


سرور پر، آپ کے پاس قدرے آسان وقت ہے۔ آپ اصلاح کی سطح کو دستی طور پر کنٹرول کرنے، کوڑا اٹھانے والے کو کنٹرول کرنے اور درست وقت حاصل کرنے کے لیے d8 استعمال کر سکتے ہیں۔ یقیناً، آپ کو اس کے لیے ایک اچھی طرح سے ڈیزائن کردہ بینچ مارک پائپ لائن قائم کرنے کے لیے کچھ Bash-fu کی ضرورت ہوگی، کیونکہ بدقسمتی سے، d8 Node.js کے ساتھ اچھی طرح سے مربوط (یا بالکل مربوط) نہیں ہے۔


آپ اسی طرح کے نتائج حاصل کرنے کے لیے Node.js میں مخصوص جھنڈوں کو بھی فعال کر سکتے ہیں، لیکن آپ مخصوص اصلاحی درجات کو فعال کرنے جیسی خصوصیات سے محروم رہیں گے۔

 v8 --sparkplug --always-sparkplug --no-opt [file]

D8 کی ایک مثال جس میں ایک مخصوص کمپلیشن ٹائر (sparkplug) فعال ہے۔ D8، بذریعہ ڈیفالٹ، GC کا زیادہ کنٹرول اور عمومی طور پر مزید ڈیبگ معلومات شامل کرتا ہے۔


آپ JavaScriptCore پر کچھ ایسی ہی خصوصیات حاصل کر سکتے ہیں؟ سچ میں، میں نے JavaScriptCore کا CLI زیادہ استعمال نہیں کیا ہے، اور یہ بہت زیادہ غیر دستاویزی ہے۔ آپ ان کے کمانڈ لائن جھنڈوں کا استعمال کرتے ہوئے مخصوص درجات کو فعال کرسکتے ہیں، لیکن مجھے یقین نہیں ہے کہ آپ کتنی ڈیبگ معلومات بازیافت کرسکتے ہیں۔ بن میں کچھ مددگار بینچ مارکنگ یوٹیلیٹیز بھی شامل ہیں، لیکن وہ اسی طرح Node.js تک محدود ہیں۔


بدقسمتی سے، ان سب کے لیے انجن کے بیس انجن/ٹیسٹ ورژن کی ضرورت ہوتی ہے، جسے حاصل کرنا کافی مشکل ہو سکتا ہے۔ میں نے محسوس کیا ہے کہ انجنوں کو منظم کرنے کا سب سے آسان طریقہ esvu کو eshost-cli کے ساتھ جوڑنا ہے، کیونکہ وہ مل کر انجنوں کا نظم و نسق اور ان پر چلنے والے کوڈ کو کافی آسان بناتے ہیں۔ بلاشبہ، ابھی بھی بہت سارے دستی کام کی ضرورت ہے، کیونکہ یہ ٹولز صرف مختلف انجنوں میں چلنے والے کوڈ کو منظم کرتے ہیں- آپ کو اب بھی بینچ مارکنگ کوڈ خود لکھنا ہوگا۔


اگر آپ صرف سرور پر پہلے سے طے شدہ اختیارات کے ساتھ کسی انجن کو بینچ مارک کرنے کی کوشش کر رہے ہیں، تو mitata جیسے آف دی شیلف Node.js ٹولز موجود ہیں جو وقت کی درستگی اور GC سے متعلق غلطیوں کو بہتر بنانے میں مدد کرتے ہیں۔ ان میں سے بہت سے اوزار، جیسے Mitata، بہت سے انجنوں میں بھی استعمال کیے جا سکتے ہیں۔ یقیناً، آپ کو اب بھی اوپر کی طرح ایک پائپ لائن لگانی ہوگی۔


براؤزر پر، سب کچھ بہت زیادہ مشکل ہے. مجھے زیادہ درست وقت کے لیے کوئی حل نہیں معلوم، اور انجن کا کنٹرول کہیں زیادہ محدود ہے۔ براؤزر میں رن ٹائم JavaScript کی کارکردگی سے متعلق آپ کو زیادہ سے زیادہ معلومات Chrome devtools سے حاصل ہوں گی، جو بنیادی شعلہ گراف اور CPU سست روی کی نقلی افادیت پیش کرتے ہیں۔

نتیجہ

اسی طرح کے ڈیزائن کے بہت سے فیصلے جنہوں نے جاوا اسکرپٹ کو (نسبتاً) پرفارمنس اور پورٹیبل بنایا، بینچ مارکنگ کو دوسری زبانوں کے مقابلے میں نمایاں طور پر زیادہ مشکل بنا دیتا ہے۔ بینچ مارک کے لیے اور بھی بہت سے اہداف ہیں، اور آپ کا ہر ہدف پر بہت کم کنٹرول ہے۔


امید ہے، ایک حل کسی دن ان میں سے بہت سے مسائل کو آسان کر دے گا۔ میں آخر کار کراس انجن اور کمپائلیشن ٹائر بینچ مارکنگ کو آسان بنانے کے لیے ایک ٹول بنا سکتا ہوں، لیکن ابھی کے لیے، ان تمام مسائل کو حل کرنے کے لیے ایک پائپ لائن بنانے میں کافی کام لگتا ہے۔ یقیناً، یہ یاد رکھنا ضروری ہے کہ یہ مسائل ہر ایک پر لاگو نہیں ہوتے — اگر آپ کا کوڈ صرف ایک ماحول میں چل رہا ہے، تو دوسرے ماحول کو بینچ مارک کرنے میں اپنا وقت ضائع نہ کریں۔


تاہم آپ بینچ مارک کا انتخاب کرتے ہیں، مجھے امید ہے کہ اس مضمون نے آپ کو JavaScript بینچ مارکنگ میں موجود کچھ مسائل دکھائے ہیں۔ مجھے بتائیں کہ اگر میں اوپر بیان کردہ کچھ چیزوں کو لاگو کرنے کے بارے میں ٹیوٹوریل مددگار ثابت ہوگا۔