আমরা কীভাবে Chrome DevTools স্ট্যাক ট্রেসকে 10x বৃদ্ধি করেছি

বেনেডিক্ট মিউর
Benedikt Meurer

ওয়েব ডেভেলপাররা তাদের কোড ডিবাগ করার সময় পারফরম্যান্সের প্রভাব খুব কম আশা করে। যাইহোক, এই প্রত্যাশা কোনভাবেই সর্বজনীন নয়। একজন C++ ডেভেলপার কখনই তাদের অ্যাপ্লিকেশনের ডিবাগ বিল্ড উৎপাদনের কার্যক্ষমতায় পৌঁছানোর আশা করেন না এবং Chrome-এর প্রাথমিক বছরগুলিতে, শুধুমাত্র DevTools খোলার ফলে পৃষ্ঠার কর্মক্ষমতা উল্লেখযোগ্যভাবে প্রভাবিত হয়।

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

তবে অবশ্যই DevTools-এর ওভারহেড - যেকোনো ডিবাগারের মতো - যুক্তিসঙ্গত হওয়া উচিত। সম্প্রতি আমরা রিপোর্টের সংখ্যায় উল্লেখযোগ্য বৃদ্ধি দেখেছি যে নির্দিষ্ট কিছু ক্ষেত্রে, DevTools অ্যাপ্লিকেশনটিকে এমন মাত্রায় কমিয়ে দেবে যে এটি আর ব্যবহারযোগ্য নয়। নীচে আপনি chromium:1069425 রিপোর্ট থেকে পাশাপাশি একটি তুলনা দেখতে পারেন, আক্ষরিক অর্থে শুধুমাত্র DevTools খোলা থাকার পারফরম্যান্স ওভারহেডকে চিত্রিত করে৷

আপনি ভিডিও থেকে দেখতে পাচ্ছেন যে স্লোডাউনটি 5-10x এর ক্রমে, যা স্পষ্টতই গ্রহণযোগ্য নয়। DevTools খোলা থাকার সময় সব সময় কোথায় যায় এবং এই বিশাল ধীরগতির কারণ কী তা বোঝা ছিল প্রথম ধাপ। ক্রোম রেন্ডারার প্রক্রিয়ায় লিনাক্স পারফ ব্যবহার করে সামগ্রিক রেন্ডারার এক্সিকিউশন সময়ের নিম্নলিখিত বন্টন প্রকাশ করেছে:

ক্রোম রেন্ডারার কার্যকর করার সময়

যদিও আমরা কিছুটা স্ট্যাক ট্রেস সংগ্রহের সাথে সম্পর্কিত কিছু দেখার আশা করেছিলাম, আমরা আশা করিনি যে সামগ্রিক নির্বাহের সময় প্রায় 90% স্ট্যাক ফ্রেমের প্রতীকে যায়। এখানে সিম্বোলাইজেশন বলতে বোঝায় ফাংশনের নাম এবং কংক্রিট সোর্স পজিশন - রেখা এবং স্ক্রিপ্টে কলাম সংখ্যা - কাঁচা স্ট্যাক ফ্রেম থেকে সমাধান করার কাজ।

পদ্ধতির নামের অনুমান

আরও আশ্চর্যের বিষয় হল যে প্রায় সব সময় V8-এ JSStackFrame::GetMethodName() ফাংশনে যায় - যদিও আমরা পূর্ববর্তী তদন্ত থেকে জানতাম যে JSStackFrame::GetMethodName() পারফরম্যান্স সমস্যার দেশে কোন অপরিচিত নয়। এই ফাংশনটি ফ্রেমের জন্য পদ্ধতির নাম গণনা করার চেষ্টা করে যেগুলিকে মেথড ইনভোকেশন হিসাবে বিবেচনা করা হয় (যে ফ্রেমগুলি func obj.func() func() ) ফর্মের ফাংশন ইনভোকেশনগুলিকে প্রতিনিধিত্ব করে। কোডের একটি দ্রুত নজরে দেখা গেছে যে এটি বস্তু এবং এর প্রোটোটাইপ চেইনটির সম্পূর্ণ ট্রাভার্সাল সম্পাদন করে এবং অনুসন্ধান করে

  1. ডেটা বৈশিষ্ট্য যার value হল func বন্ধ, বা
  2. অ্যাক্সেসর বৈশিষ্ট্য যেখানে হয় get বা set func বন্ধের সমান।

এখন নিজে থেকে এটি বিশেষভাবে সস্তা শোনাচ্ছে না, এটি এই ভয়ঙ্কর মন্থরতাকে ব্যাখ্যা করার মতও শোনাচ্ছে না। তাই আমরা chromium:1069425 এ রিপোর্ট করা উদাহরণে খনন করা শুরু করেছি, এবং আমরা দেখতে পেয়েছি যে স্ট্যাক ট্রেসগুলি অ্যাসিঙ্ক কাজগুলির পাশাপাশি classes.js - একটি 10MiB JavaScript ফাইল থেকে উদ্ভূত লগ বার্তাগুলির জন্য সংগ্রহ করা হয়েছিল৷ একটি ঘনিষ্ঠ দৃষ্টিতে প্রকাশ যে এটি মূলত একটি জাভা রানটাইম প্লাস অ্যাপ্লিকেশন কোড জাভাস্ক্রিপ্টে সংকলিত। স্ট্যাক ট্রেসে বেশ কয়েকটি ফ্রেম রয়েছে যার সাথে একটি অবজেক্ট A তে পদ্ধতিগুলি চালু করা হয়েছে তাই আমরা ভেবেছিলাম যে আমরা কী ধরণের অবজেক্ট নিয়ে কাজ করছি তা বোঝার মূল্য হতে পারে।

একটি বস্তুর স্ট্যাক ট্রেস

স্পষ্টতই জাভা থেকে জাভাস্ক্রিপ্ট কম্পাইলার একটি একক বস্তু তৈরি করেছে যাতে এটিতে 82,203টি ফাংশন রয়েছে - এটি স্পষ্টতই আকর্ষণীয় হয়ে উঠতে শুরু করেছিল। এরপরে আমরা V8 এর JSStackFrame::GetMethodName() এ ফিরে গেলাম যাতে বোঝার জন্য সেখানে কিছু কম ঝুলন্ত ফল আছে যা আমরা সেখানে নিতে পারি।

  1. এটি প্রথমে বস্তুর একটি সম্পত্তি হিসাবে ফাংশনের "name" সন্ধান করে কাজ করে এবং যদি এটি পাওয়া যায় তবে বৈশিষ্ট্যের মান ফাংশনের সাথে মেলে কিনা তা পরীক্ষা করে।
  2. যদি ফাংশনের কোনো নাম না থাকে বা বস্তুটির কোনো মিলিত বৈশিষ্ট্য না থাকে, তাহলে এটি বস্তুর সমস্ত বৈশিষ্ট্য এবং এর প্রোটোটাইপগুলি অতিক্রম করে একটি বিপরীত লুকআপে ফিরে আসে।

আমাদের উদাহরণে, সমস্ত ফাংশন বেনামী এবং খালি "name" বৈশিষ্ট্য রয়েছে।

A.SDV = function() {
   // ...
};

প্রথম অনুসন্ধানটি ছিল যে বিপরীত লুকআপটি দুটি ধাপে বিভক্ত ছিল (বস্তু নিজেই এবং প্রতিটি বস্তুর প্রোটোটাইপ চেইনের জন্য সম্পাদিত):

  1. সমস্ত গণনাযোগ্য বৈশিষ্ট্যের নাম বের করুন এবং
  2. প্রতিটি নামের জন্য একটি জেনেরিক প্রপার্টি লুকআপ করুন, ফলাফলের প্রপার্টির মান আমরা যা খুঁজছিলাম তার সাথে মেলে কিনা তা পরীক্ষা করুন।

এটি একটি মোটামুটি কম ঝুলন্ত ফলের মতো দেখাচ্ছিল, যেহেতু নামগুলি বের করার জন্য ইতিমধ্যে সমস্ত বৈশিষ্ট্যের মধ্য দিয়ে হাঁটা প্রয়োজন৷ দুটি পাস করার পরিবর্তে - নাম নিষ্কাশনের জন্য O(N) এবং পরীক্ষার জন্য O(N লগ(N)) - আমরা একটি একক পাসে সবকিছু করতে পারি এবং সরাসরি সম্পত্তির মান পরীক্ষা করতে পারি। এটি পুরো ফাংশনটিকে প্রায় 2-10x দ্রুত করে তুলেছে।

দ্বিতীয় আবিষ্কারটি আরও আকর্ষণীয় ছিল। যদিও ফাংশনগুলি প্রযুক্তিগতভাবে বেনামী ফাংশন ছিল, তবুও V8 ইঞ্জিন রেকর্ড করেছিল যা আমরা তাদের জন্য একটি অনুমানকৃত নাম বলি। obj.foo = function() {...} ফর্মে অ্যাসাইনমেন্টের ডানদিকে প্রদর্শিত ফাংশন লিটারেলগুলির জন্য V8 পার্সার "obj.foo" ফাংশন লিটারালের অনুমানকৃত নাম হিসাবে মুখস্থ করে। সুতরাং আমাদের ক্ষেত্রে এর অর্থ হল, যদিও আমাদের সঠিক নাম ছিল না যা আমরা শুধু দেখতে পারি, আমাদের কাছে যথেষ্ট কাছাকাছি কিছু ছিল: উপরের A.SDV = function() {...} উদাহরণের জন্য, আমাদের ছিল "A.SDV" অনুমানকৃত নাম হিসাবে, এবং আমরা শেষ বিন্দুটি সন্ধান করে অনুমানকৃত নাম থেকে সম্পত্তির নামটি বের করতে পারি এবং তারপর বস্তুতে "SDV" বৈশিষ্ট্যের সন্ধান করতে পারি। এটি প্রায় সব ক্ষেত্রেই কৌশলটি করেছে, একটি একক সম্পত্তি লুকআপের সাথে একটি ব্যয়বহুল ফুল ট্রাভার্সাল প্রতিস্থাপন করেছে। এই দুটি উন্নতি এই CL এর অংশ হিসাবে অবতরণ করেছে, এবং ক্রোমিয়াম:1069425- এ রিপোর্ট করা উদাহরণের জন্য মন্থরতা উল্লেখযোগ্যভাবে হ্রাস করেছে।

Error.stack

আমরা এটা এখানে একটি দিন বলা হতে পারে. কিন্তু সেখানে কিছু মন্দ চলছিল, যেহেতু DevTools কখনও স্ট্যাক ফ্রেমের জন্য পদ্ধতির নাম ব্যবহার করে না। প্রকৃতপক্ষে C++ API-এর v8::StackFrame ক্লাস পদ্ধতির নামে যাওয়ার কোনো উপায়ও প্রকাশ করে না। তাই এটা ভুল বলে মনে হচ্ছে যে আমরা প্রথমে JSStackFrame::GetMethodName() কে কল করব। পরিবর্তে একমাত্র জায়গা যেখানে আমরা পদ্ধতির নাম ব্যবহার করি (এবং প্রকাশ করি) জাভাস্ক্রিপ্ট স্ট্যাক ট্রেস এপিআই । এই ব্যবহার বোঝার জন্য, নিম্নলিখিত সহজ উদাহরণ error-methodname.js বিবেচনা করুন:

function foo() {
    console.log((new Error).stack);
}

var object = {bar: foo};
object.bar();

এখানে আমাদের একটি ফাংশন foo আছে যা object "bar" নামে ইনস্টল করা আছে। Chromium-এ এই স্নিপেট চালানোর ফলে নিম্নলিখিত আউটপুট পাওয়া যায়:

Error
    at Object.foo [as bar] (error-methodname.js:2)
    at error-methodname.js:6

এখানে আমরা প্লে এ মেথড নেম লুকআপ দেখতে পাচ্ছি: শীর্ষস্থানীয় স্ট্যাক ফ্রেমটি bar নামের মেথডের মাধ্যমে Object একটি ইনস্ট্যান্সে ফাংশন foo কল করার জন্য দেখানো হয়েছে। সুতরাং নন-স্ট্যান্ডার্ড error.stack প্রপার্টি JSStackFrame::GetMethodName() এর ব্যাপক ব্যবহার করে এবং প্রকৃতপক্ষে আমাদের কর্মক্ষমতা পরীক্ষাগুলিও ইঙ্গিত করে যে আমাদের পরিবর্তনগুলি জিনিসগুলিকে উল্লেখযোগ্যভাবে দ্রুততর করেছে।

স্ট্যাকট্রেস মাইক্রো বেঞ্চমার্কে গতি বাড়ানো

কিন্তু Chrome DevTools-এর বিষয়ে ফিরে আসি, যে পদ্ধতির নাম গণনা করা হয় যদিও error.stack ব্যবহার করা হয় না তা সঠিক বলে মনে হচ্ছে না। এখানে কিছু ইতিহাস আছে যা আমাদের সাহায্য করে: ঐতিহ্যগতভাবে V8-এ উপরে বর্ণিত দুটি ভিন্ন API (C++ v8::StackFrame API এবং JavaScript স্ট্যাক ট্রেস API) এর জন্য স্ট্যাক ট্রেস সংগ্রহ ও প্রতিনিধিত্ব করার জন্য দুটি স্বতন্ত্র প্রক্রিয়া ছিল। (মোটামুটিভাবে) করার দুটি ভিন্ন উপায় থাকা একই ত্রুটি-প্রবণ ছিল এবং প্রায়শই অসঙ্গতি এবং বাগগুলির দিকে পরিচালিত করে, তাই 2018 সালের শেষের দিকে আমরা স্ট্যাক ট্রেস ক্যাপচারিংয়ের জন্য একটি একক বাধার সমাধান করার জন্য একটি প্রকল্প চালু করেছি।

এই প্রকল্পটি একটি দুর্দান্ত সাফল্য ছিল এবং স্ট্যাক ট্রেস সংগ্রহের সাথে সম্পর্কিত সমস্যার সংখ্যা ব্যাপকভাবে হ্রাস করেছে। অ-মানক error.stack সম্পত্তির মাধ্যমে প্রদত্ত বেশিরভাগ তথ্য অলসভাবে গণনা করা হয়েছিল এবং শুধুমাত্র যখন এটি সত্যিই প্রয়োজন ছিল, কিন্তু রিফ্যাক্টরিংয়ের অংশ হিসাবে আমরা একই কৌশলটি v8::StackFrame অবজেক্টগুলিতে প্রয়োগ করেছি। স্ট্যাক ফ্রেম সম্পর্কে সমস্ত তথ্য গণনা করা হয় যখন এটিতে কোনও পদ্ধতি চালু করা হয়েছিল।

এটি সাধারণত কর্মক্ষমতা উন্নত করে, কিন্তু দুর্ভাগ্যবশত এটি C++ API অবজেক্টগুলি Chromium এবং DevTools-এ কীভাবে ব্যবহার করা হয় তার কিছুটা বিপরীতে পরিণত হয়েছে। বিশেষ করে যেহেতু আমরা একটি নতুন v8::internal::StackFrameInfo ক্লাস প্রবর্তন করেছি, যেখানে একটি স্ট্যাক ফ্রেমের সমস্ত তথ্য রয়েছে যা হয় v8::StackFrame বা error.stack এর মাধ্যমে প্রকাশ করা হয়েছিল, আমরা সর্বদা সুপার-সেট গণনা করব। উভয় API দ্বারা প্রদত্ত তথ্যের, যার অর্থ v8::StackFrame (এবং বিশেষ করে DevTools-এর জন্য) ব্যবহারের জন্য আমরা পদ্ধতির নামও গণনা করব, যত তাড়াতাড়ি একটি স্ট্যাক ফ্রেমের বিষয়ে কোনো তথ্য অনুরোধ করা হবে। দেখা যাচ্ছে যে DevTools সর্বদা অবিলম্বে উত্স এবং স্ক্রিপ্ট তথ্যের জন্য অনুরোধ করে।

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

ফাংশনের নাম

উপরে উল্লিখিত রিফ্যাক্টরিংগুলি পথের বাইরে থাকায়, প্রতীকীকরণের ওভারহেড ( v8_inspector::V8Debugger::symbolize এ ব্যয় করা সময়) সামগ্রিক কার্যকরী সময়ের প্রায় 15% কমিয়ে দেওয়া হয়েছিল এবং আমরা আরও স্পষ্টভাবে দেখতে পাচ্ছি যে V8 কোথায় সময় কাটাচ্ছে (সংগ্রহ করা এবং) DevTools-এ ব্যবহারের জন্য স্ট্যাক ফ্রেমের প্রতীক।

প্রতীকীকরণ খরচ

প্রথম জিনিস যা দাঁড়িয়েছিল তা হল কম্পিউটিং লাইন এবং কলাম নম্বরের জন্য ক্রমবর্ধমান খরচ। এখানে ব্যয়বহুল অংশটি আসলে স্ক্রিপ্টের মধ্যে অক্ষর অফসেট গণনা করা (আমরা V8 থেকে পাওয়া বাইটকোড অফসেটের উপর ভিত্তি করে) এবং দেখা গেল যে উপরে আমাদের রিফ্যাক্টরিংয়ের কারণে আমরা এটি দুবার করেছি, একবার লাইন নম্বর গণনা করার সময় এবং অন্যবার। কলাম নম্বর গণনা করার সময়। v8::internal::StackFrameInfo দৃষ্টান্তে সোর্স পজিশন ক্যাশ করা এটিকে দ্রুত সমাধান করতে সাহায্য করেছে এবং v8::internal::StackFrameInfo::GetColumnNumber যেকোন প্রোফাইল থেকে সম্পূর্ণভাবে বাদ দিয়েছে।

আমাদের জন্য আরও আকর্ষণীয় অনুসন্ধান ছিল v8::StackFrame::GetFunctionName আমরা যে সমস্ত প্রোফাইলগুলি দেখেছি তাতে আশ্চর্যজনকভাবে উচ্চ ছিল। এখানে আরও গভীরে খনন করে আমরা বুঝতে পেরেছি যে DevTools-এ স্ট্যাক ফ্রেমে ফাংশনের জন্য আমরা যে নামটি দেখাব তা গণনা করা অপ্রয়োজনীয়ভাবে ব্যয়বহুল ছিল,

  1. প্রথমে নন-স্ট্যান্ডার্ড "displayName" প্রপার্টি খুঁজছি এবং যদি এটি একটি স্ট্রিং মান সহ একটি ডেটা প্রপার্টি দেয়, আমরা সেটি ব্যবহার করব,
  2. অন্যথায় স্ট্যান্ডার্ড "name" প্রপার্টি খুঁজতে ফিরে যাওয়া এবং আবার পরীক্ষা করা যে এটি একটি ডেটা প্রপার্টি দেয় কিনা যার মান একটি স্ট্রিং,
  3. এবং অবশেষে একটি অভ্যন্তরীণ ডিবাগ নামে ফিরে আসা যা V8 পার্সার দ্বারা অনুমান করা হয়েছে এবং আক্ষরিক ফাংশনে সংরক্ষণ করা হয়েছে।

"displayName" প্রপার্টিটি জাভাস্ক্রিপ্টে শুধুমাত্র পঠনযোগ্য এবং কনফিগারযোগ্য নয় এমন Function দৃষ্টান্তগুলিতে "name" বৈশিষ্ট্যের জন্য একটি কাজ হিসাবে যুক্ত করা হয়েছিল, কিন্তু ব্রাউজার বিকাশকারীর কারণে এটি কখনই প্রমিত ছিল না এবং ব্যাপকভাবে ব্যবহার দেখা যায়নি। টুল ফাংশন নামের অনুমান যোগ করেছে যা 99.9% ক্ষেত্রে কাজ করে। এর উপরে ES2015 Function দৃষ্টান্তগুলিতে "name" বৈশিষ্ট্যটিকে কনফিগারযোগ্য করে তুলেছে, একটি বিশেষ "displayName" সম্পত্তির প্রয়োজনীয়তা সম্পূর্ণভাবে সরিয়ে দিয়েছে৷ যেহেতু "displayName" এর জন্য নেতিবাচক লুকআপ বেশ ব্যয়বহুল এবং সত্যিই প্রয়োজনীয় নয় (ES2015 পাঁচ বছর আগে প্রকাশিত হয়েছিল), তাই আমরা V8 (এবং DevTools) থেকে অ-মানক fn.displayName সম্পত্তির জন্য সমর্থন সরানোর সিদ্ধান্ত নিয়েছি।

"displayName" এর নেতিবাচক সন্ধানের সাথে সাথে, v8::StackFrame::GetFunctionName এর অর্ধেক খরচ সরিয়ে ফেলা হয়েছে। বাকি অর্ধেক জেনেরিক "name" সম্পত্তি লুকআপে যায়। সৌভাগ্যবশতঃ (অস্পর্শ) Function দৃষ্টান্তে "name" সম্পত্তির ব্যয়বহুল লুকআপ এড়াতে আমাদের কাছে ইতিমধ্যে কিছু যুক্তি ছিল, যা আমরা কিছুক্ষণ আগে V8 এ চালু করেছি যাতে Function.prototype.bind() নিজেই দ্রুততর হয়। আমরা প্রয়োজনীয় চেকগুলি পোর্ট করেছি যা আমাদেরকে প্রথমে ব্যয়বহুল জেনেরিক লুকআপ এড়িয়ে যেতে দেয়, যার ফলে v8::StackFrame::GetFunctionName আমাদের আর বিবেচনা করা কোনো প্রোফাইলে দেখা যায় না।

উপসংহার

উপরের উন্নতিগুলির সাথে, আমরা স্ট্যাক ট্রেসের পরিপ্রেক্ষিতে DevTools-এর ওভারহেড উল্লেখযোগ্যভাবে হ্রাস করেছি।

আমরা জানি যে এখনও বিভিন্ন সম্ভাব্য উন্নতি রয়েছে - উদাহরণস্বরূপ MutationObserver s ব্যবহার করার সময় ওভারহেড এখনও লক্ষণীয়, যেমন chromium:1077657- এ রিপোর্ট করা হয়েছে - তবে আপাতত, আমরা প্রধান ব্যথার পয়েন্টগুলিকে সম্বোধন করেছি, এবং আমরা ফিরে আসতে পারি ডিবাগিং কর্মক্ষমতা আরও স্ট্রীমলাইন করার জন্য ভবিষ্যতে।

প্রিভিউ চ্যানেল ডাউনলোড করুন

আপনার ডিফল্ট ডেভেলপমেন্ট ব্রাউজার হিসেবে Chrome Canary , Dev বা Beta ব্যবহার করার কথা বিবেচনা করুন। এই পূর্বরূপ চ্যানেলগুলি আপনাকে সর্বশেষ DevTools বৈশিষ্ট্যগুলিতে অ্যাক্সেস দেয়, অত্যাধুনিক ওয়েব প্ল্যাটফর্ম API পরীক্ষা করে এবং আপনার ব্যবহারকারীদের আগে আপনার সাইটে সমস্যাগুলি খুঁজে পায়!

Chrome DevTools টিমের সাথে যোগাযোগ করা হচ্ছে

পোস্টের নতুন বৈশিষ্ট্য এবং পরিবর্তনগুলি বা DevTools সম্পর্কিত অন্য কিছু নিয়ে আলোচনা করতে নিম্নলিখিত বিকল্পগুলি ব্যবহার করুন৷

  • crbug.com এর মাধ্যমে আমাদের কাছে একটি পরামর্শ বা প্রতিক্রিয়া জমা দিন।
  • আরও বিকল্প ব্যবহার করে একটি DevTools সমস্যা রিপোর্ট করুনআরও > সাহায্য > DevTools-এ একটি DevTools সমস্যা রিপোর্ট করুন
  • @ChromeDevTools- এ টুইট করুন।
  • আমাদের DevTools YouTube ভিডিও বা DevTools টিপস YouTube ভিডিওগুলিতে নতুন কী আছে সে সম্পর্কে মন্তব্য করুন৷