এটা ধারাবাহিকভাবে দ্রুত, ইয়ো
আমার পূর্ববর্তী নিবন্ধগুলিতে আমি কীভাবে WebAssembly আপনাকে C/C++ এর লাইব্রেরি ইকোসিস্টেম ওয়েবে আনতে অনুমতি দেয় সে সম্পর্কে কথা বলেছিলাম। একটি অ্যাপ যা C/C++ লাইব্রেরির ব্যাপক ব্যবহার করে তা হল squosh , আমাদের ওয়েব অ্যাপ যা আপনাকে C++ থেকে WebAssembly-তে সংকলিত বিভিন্ন কোডেক দিয়ে ছবি কম্প্রেস করতে দেয়।
WebAssembly হল একটি নিম্ন-স্তরের ভার্চুয়াল মেশিন যা .wasm
ফাইলে সংরক্ষিত বাইটকোড চালায়। এই বাইট কোড দৃঢ়ভাবে টাইপ করা হয়েছে এবং এমনভাবে গঠন করা হয়েছে যে এটি জাভাস্ক্রিপ্টের চেয়ে অনেক দ্রুত হোস্ট সিস্টেমের জন্য কম্পাইল এবং অপ্টিমাইজ করা যায়। WebAssembly কোড চালানোর জন্য একটি পরিবেশ প্রদান করে যেটিতে স্যান্ডবক্সিং এবং এমবেডিং ছিল শুরু থেকেই।
আমার অভিজ্ঞতায়, ওয়েবে বেশিরভাগ পারফরম্যান্স সমস্যা বাধ্যতামূলক লেআউট এবং অত্যধিক পেইন্টের কারণে সৃষ্ট হয় তবে প্রতিবার এবং তারপরে একটি অ্যাপকে একটি গণনামূলকভাবে ব্যয়বহুল কাজ করতে হবে যা অনেক সময় নেয়। WebAssembly এখানে সাহায্য করতে পারেন.
গরম পথ
স্কুশ-এ আমরা একটি জাভাস্ক্রিপ্ট ফাংশন লিখেছি যা একটি ইমেজ বাফারকে 90 ডিগ্রির গুণিতক দ্বারা ঘোরায়। যদিও অফস্ক্রিন ক্যানভাস এর জন্য আদর্শ হবে, আমরা যে ব্রাউজারগুলিকে টার্গেট করছিলাম সেগুলি জুড়ে এটি সমর্থিত নয় এবং Chrome-এ একটু বগি ।
এই ফাংশনটি একটি ইনপুট চিত্রের প্রতিটি পিক্সেলের উপর পুনরাবৃত্তি করে এবং এটিকে আউটপুট চিত্রের একটি ভিন্ন অবস্থানে অনুলিপি করে ঘূর্ণন অর্জন করতে। একটি 4094px বাই 4096px চিত্রের জন্য (16 মেগাপিক্সেল) এর ভিতরের কোড ব্লকের 16 মিলিয়ন পুনরাবৃত্তির প্রয়োজন হবে, যাকে আমরা "হট পাথ" বলি। এত বড় সংখ্যক পুনরাবৃত্তি সত্ত্বেও, আমরা পরীক্ষিত তিনটি ব্রাউজারের মধ্যে দুটি 2 সেকেন্ড বা তারও কম সময়ে কাজটি শেষ করি। এই ধরনের মিথস্ক্রিয়া জন্য একটি গ্রহণযোগ্য সময়কাল.
for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
const in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
outBuffer[i] = inBuffer[in_idx];
i += 1;
}
}
তবে একটি ব্রাউজার 8 সেকেন্ডের বেশি সময় নেয়। ব্রাউজারগুলি যেভাবে জাভাস্ক্রিপ্ট অপ্টিমাইজ করে তা সত্যিই জটিল এবং বিভিন্ন ইঞ্জিন বিভিন্ন জিনিসের জন্য অপ্টিমাইজ করে৷ কিছু কাঁচা সম্পাদনের জন্য অপ্টিমাইজ করে, কিছু DOM এর সাথে ইন্টারঅ্যাকশনের জন্য অপ্টিমাইজ করে৷ এই ক্ষেত্রে, আমরা একটি ব্রাউজারে একটি অপ্টিমাইজড পাথ হিট করেছি৷
অন্যদিকে WebAssembly সম্পূর্ণরূপে কাঁচা এক্সিকিউশন গতির চারপাশে নির্মিত। তাই যদি আমরা এই ধরনের কোডের জন্য ব্রাউজার জুড়ে দ্রুত, অনুমানযোগ্য পারফরম্যান্স চাই, WebAssembly সাহায্য করতে পারে।
অনুমানযোগ্য কর্মক্ষমতা জন্য WebAssembly
সাধারণভাবে, JavaScript এবং WebAssembly একই শীর্ষ কর্মক্ষমতা অর্জন করতে পারে। যাইহোক, জাভাস্ক্রিপ্টের জন্য এই কর্মক্ষমতা শুধুমাত্র "দ্রুত পথ" এ পৌঁছানো যেতে পারে এবং সেই "দ্রুত পথে" থাকা প্রায়ই কঠিন। WebAssembly অফার করে এমন একটি মূল সুবিধা হল অনুমানযোগ্য কর্মক্ষমতা, এমনকি ব্রাউজার জুড়ে। কঠোর টাইপিং এবং নিম্ন-স্তরের আর্কিটেকচার কম্পাইলারকে শক্তিশালী গ্যারান্টি দেওয়ার অনুমতি দেয় যাতে WebAssembly কোড শুধুমাত্র একবার অপ্টিমাইজ করতে হয় এবং সর্বদা "দ্রুত পথ" ব্যবহার করবে।
WebAssembly জন্য লেখা
পূর্বে আমরা C/C++ লাইব্রেরি নিয়েছিলাম এবং ওয়েবে তাদের কার্যকারিতা ব্যবহার করার জন্য WebAssembly-এ কম্পাইল করেছি। আমরা সত্যিই লাইব্রেরির কোড স্পর্শ করিনি, আমরা ব্রাউজার এবং লাইব্রেরির মধ্যে সেতু তৈরি করতে অল্প পরিমাণে C/C++ কোড লিখেছি। এবার আমাদের অনুপ্রেরণা ভিন্ন: আমরা WebAssembly কে মাথায় রেখে স্ক্র্যাচ থেকে কিছু লিখতে চাই যাতে আমরা WebAssembly এর সুবিধাগুলো ব্যবহার করতে পারি।
ওয়েব অ্যাসেম্বলি আর্কিটেকচার
WebAssembly-এর জন্য লেখার সময়, WebAssembly আসলে কী তা সম্পর্কে আরও কিছুটা বোঝা উপকারী।
WebAssembly.org উদ্ধৃত করতে:
যখন আপনি WebAssembly-এ C বা রাস্ট কোডের একটি অংশ কম্পাইল করেন, আপনি একটি .wasm
ফাইল পাবেন যাতে একটি মডিউল ঘোষণা রয়েছে। এই ঘোষণায় মডিউলটি তার পরিবেশ থেকে প্রত্যাশিত "আমদানি" এর একটি তালিকা, রপ্তানির একটি তালিকা যা এই মডিউল হোস্টের কাছে উপলব্ধ করে (ফাংশন, ধ্রুবক, মেমরির অংশ) এবং অবশ্যই এর মধ্যে থাকা ফাংশনগুলির জন্য প্রকৃত বাইনারি নির্দেশাবলী। .
এমন কিছু যা আমি এটির দিকে নজর না দেওয়া পর্যন্ত বুঝতে পারিনি: যে স্ট্যাকটি WebAssembly কে একটি "স্ট্যাক-ভিত্তিক ভার্চুয়াল মেশিন" করে তোলে সেটি মেমরির অংশে সংরক্ষণ করা হয় না যা WebAssembly মডিউল ব্যবহার করে। স্ট্যাকটি সম্পূর্ণভাবে VM-অভ্যন্তরীণ এবং ওয়েব ডেভেলপারদের কাছে অ্যাক্সেসযোগ্য নয় (DevTools ব্যতীত)। এইভাবে WebAssembly মডিউলগুলি লেখা সম্ভব যেগুলির জন্য কোনও অতিরিক্ত মেমরির প্রয়োজন নেই এবং শুধুমাত্র VM-অভ্যন্তরীণ স্ট্যাক ব্যবহার করুন।
আমাদের ক্ষেত্রে আমাদের চিত্রের পিক্সেলগুলিতে নির্বিচারে অ্যাক্সেসের অনুমতি দেওয়ার জন্য এবং সেই চিত্রের একটি ঘোরানো সংস্করণ তৈরি করতে আমাদের কিছু অতিরিক্ত মেমরি ব্যবহার করতে হবে। এটি WebAssembly.Memory
এর জন্য।
মেমরি ব্যবস্থাপনা
সাধারণত, আপনি একবার অতিরিক্ত মেমরি ব্যবহার করলে আপনি সেই মেমরিটিকে কোনো না কোনোভাবে পরিচালনা করার প্রয়োজন খুঁজে পাবেন। মেমরির কোন অংশ ব্যবহার করা হয়? কোনটি বিনামূল্যে? C-তে, উদাহরণস্বরূপ, আপনার malloc(n)
ফাংশন রয়েছে যা n
পরপর বাইটের মেমরি স্পেস খুঁজে পায়। এই ধরনের ফাংশনকে "বরাদ্দকারী"ও বলা হয়। অবশ্যই ব্যবহৃত বরাদ্দকারীর বাস্তবায়ন আপনার WebAssembly মডিউলে অন্তর্ভুক্ত করা আবশ্যক এবং আপনার ফাইলের আকার বৃদ্ধি করবে। এই মেমরি ম্যানেজমেন্ট ফাংশনগুলির এই আকার এবং কার্যকারিতা ব্যবহৃত অ্যালগরিদমের উপর নির্ভর করে বেশ উল্লেখযোগ্যভাবে পরিবর্তিত হতে পারে, যে কারণে অনেক ভাষা ("dmalloc", "emmalloc", "wee_alloc", ইত্যাদি) থেকে বেছে নেওয়ার জন্য একাধিক বাস্তবায়নের প্রস্তাব দেয়।
আমাদের ক্ষেত্রে আমরা WebAssembly মডিউল চালানোর আগে ইনপুট ইমেজের মাত্রা (এবং আউটপুট ইমেজের মাত্রা) জানি। এখানে আমরা একটি সুযোগ দেখেছি: ঐতিহ্যগতভাবে, আমরা একটি WebAssembly ফাংশনে একটি প্যারামিটার হিসাবে ইনপুট চিত্রের RGBA বাফারটি পাস করব এবং একটি রিটার্ন মান হিসাবে ঘোরানো চিত্রটি ফিরিয়ে দেব। সেই রিটার্ন মান তৈরি করতে আমাদের বরাদ্দকারী ব্যবহার করতে হবে। কিন্তু যেহেতু আমরা জানি মোট মেমরির পরিমাণ (ইনপুট ইমেজের আকারের দ্বিগুণ, একবার ইনপুটের জন্য এবং একবার আউটপুটের জন্য), আমরা JavaScript ব্যবহার করে ইনপুট ইমেজটিকে WebAssembly মেমরিতে রাখতে পারি, 2nd তৈরি করতে WebAssembly মডিউল চালান, ঘোরানো চিত্র এবং তারপর ফলাফলটি পড়ার জন্য জাভাস্ক্রিপ্ট ব্যবহার করুন। আমরা কোনো মেমরি ব্যবস্থাপনা ব্যবহার না করেই পার পেয়ে যেতে পারি!
পছন্দের জন্য নষ্ট হয়ে গেছে
আপনি যদি আসল JavaScript ফাংশনটি দেখেন যা আমরা WebAssembly-fy করতে চাই, আপনি দেখতে পাবেন যে এটি একটি সম্পূর্ণরূপে গণনামূলক কোড যার কোনো জাভাস্ক্রিপ্ট-নির্দিষ্ট API নেই। যেমন এই কোডটি যেকোনো ভাষায় পোর্ট করার জন্য এটি মোটামুটি সোজা হওয়া উচিত। আমরা WebAssembly-এ কম্পাইল করা 3টি ভিন্ন ভাষা মূল্যায়ন করেছি: C/C++, Rust এবং AssemblyScript। প্রতিটি ভাষার জন্য আমাদের একমাত্র প্রশ্নের উত্তর দিতে হবে: মেমরি ম্যানেজমেন্ট ফাংশন ব্যবহার না করে আমরা কীভাবে কাঁচা মেমরি অ্যাক্সেস করব?
সি এবং এমস্ক্রিপ্টেন
Emscripten হল WebAssembly টার্গেটের জন্য একটি C কম্পাইলার। Emscripten-এর লক্ষ্য হল GCC বা ক্ল্যাং-এর মতো সুপরিচিত C কম্পাইলারগুলির জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবে কাজ করা এবং বেশিরভাগই ফ্ল্যাগ সামঞ্জস্যপূর্ণ। এটি এমস্ক্রিপ্টেন-এর মিশনের একটি মূল অংশ কারণ এটি বিদ্যমান C এবং C++ কোডগুলিকে WebAssembly-এ সংকলন করা যতটা সম্ভব সহজ করতে চায়।
কাঁচা মেমরি অ্যাক্সেস করা C এর প্রকৃতির মধ্যে রয়েছে এবং সেই কারণেই পয়েন্টার বিদ্যমান:
uint8_t* ptr = (uint8_t*)0x124;
ptr[0] = 0xFF;
এখানে আমরা 0x124
নম্বরটিকে সাইনবিহীন, 8-বিট পূর্ণসংখ্যা (বা বাইট) এ একটি পয়েন্টারে পরিণত করছি। এটি কার্যকরভাবে ptr
ভেরিয়েবলকে মেমরি অ্যাড্রেস 0x124
থেকে শুরু করে একটি অ্যারেতে পরিণত করে, যা আমরা অন্য যেকোনো অ্যারের মতো ব্যবহার করতে পারি, যা আমাদের পড়ার এবং লেখার জন্য পৃথক বাইট অ্যাক্সেস করতে দেয়। আমাদের ক্ষেত্রে আমরা একটি চিত্রের একটি RGBA বাফার দেখছি যা আমরা ঘূর্ণন অর্জনের জন্য পুনরায় অর্ডার করতে চাই। একটি পিক্সেল সরানোর জন্য আমাদের আসলে একবারে পরপর 4 বাইট সরাতে হবে (প্রতিটি চ্যানেলের জন্য একটি বাইট: R, G, B এবং A)। এটি সহজ করার জন্য আমরা স্বাক্ষরবিহীন, 32-বিট পূর্ণসংখ্যার একটি অ্যারে তৈরি করতে পারি। নিয়ম অনুসারে, আমাদের ইনপুট চিত্রটি ঠিকানা 4 এ শুরু হবে এবং আমাদের আউটপুট চিত্রটি ইনপুট চিত্র শেষ হওয়ার পরে সরাসরি শুরু হবে:
int bpp = 4;
int imageSize = inputWidth * inputHeight * bpp;
uint32_t* inBuffer = (uint32_t*) 4;
uint32_t* outBuffer = (uint32_t*) (inBuffer + imageSize);
for (int d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (int d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
int in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
outBuffer[i] = inBuffer[in_idx];
i += 1;
}
}
সম্পূর্ণ জাভাস্ক্রিপ্ট ফাংশনটি সি-তে পোর্ট করার পরে, আমরা emcc
দিয়ে C ফাইলটি কম্পাইল করতে পারি:
$ emcc -O3 -s ALLOW_MEMORY_GROWTH=1 -o c.js rotate.c
বরাবরের মতো, emscripten c.js
নামে একটি আঠালো কোড ফাইল এবং c.wasm
নামে একটি wasm মডিউল তৈরি করে। লক্ষ্য করুন যে wsm মডিউলটি শুধুমাত্র ~260 বাইট পর্যন্ত জিজিপ করে, যখন gzip-এর পরে আঠালো কোড প্রায় 3.5KB হয়। কিছু নাড়াচাড়া করার পরে, আমরা আঠালো কোডটি ছিঁড়ে ফেলতে এবং ভ্যানিলা এপিআইগুলির সাথে WebAssembly মডিউলগুলিকে ইনস্ট্যান্টিয়েট করতে সক্ষম হয়েছি। যতক্ষণ না আপনি C স্ট্যান্ডার্ড লাইব্রেরি থেকে কিছু ব্যবহার করছেন না ততক্ষণ পর্যন্ত এমস্ক্রিপ্টেনের সাথে এটি প্রায়ই সম্ভব।
মরিচা
মরিচা হল একটি নতুন, আধুনিক প্রোগ্রামিং ভাষা যার একটি সমৃদ্ধ টাইপ সিস্টেম, কোন রানটাইম নেই এবং একটি মালিকানা মডেল যা মেমরি-নিরাপত্তা এবং থ্রেড-নিরাপত্তার নিশ্চয়তা দেয়। জং একটি মূল বৈশিষ্ট্য হিসাবে WebAssembly সমর্থন করে এবং রাস্ট টিম WebAssembly ইকোসিস্টেমে অনেক চমৎকার টুলিং অবদান রেখেছে।
এই সরঞ্জামগুলির মধ্যে একটি হল wasm-pack
, রাস্টওয়াসম ওয়ার্কিং গ্রুপ দ্বারা। wasm-pack
আপনার কোড নেয় এবং এটিকে একটি ওয়েব-বন্ধুত্বপূর্ণ মডিউলে পরিণত করে যা ওয়েবপ্যাকের মতো বান্ডলারের সাথে বাক্সের বাইরে কাজ করে। wasm-pack
একটি অত্যন্ত সুবিধাজনক অভিজ্ঞতা, কিন্তু বর্তমানে শুধুমাত্র মরিচা-এর জন্য কাজ করে। গ্রুপটি অন্যান্য WebAssembly-টার্গেটিং ভাষার জন্য সমর্থন যোগ করার কথা বিবেচনা করছে।
মরিচা-এ, স্লাইসগুলি হল অ্যারেগুলি যা সি-তে থাকে। এবং সি-তে যেমন, আমাদের স্লাইস তৈরি করতে হবে যা আমাদের শুরুর ঠিকানাগুলি ব্যবহার করে। এটি মেমরি সুরক্ষা মডেলের বিরুদ্ধে যায় যা রাস্ট প্রয়োগ করে, তাই আমাদের পথ পেতে আমাদের unsafe
কীওয়ার্ড ব্যবহার করতে হবে, আমাদের কোড লিখতে অনুমতি দেয় যা সেই মডেলের সাথে মেনে চলে না।
let imageSize = (inputWidth * inputHeight) as usize;
let inBuffer: &mut [u32];
let outBuffer: &mut [u32];
unsafe {
inBuffer = slice::from_raw_parts_mut::<u32>(4 as *mut u32, imageSize);
outBuffer = slice::from_raw_parts_mut::<u32>((imageSize * 4 + 4) as *mut u32, imageSize);
}
for d2 in 0..d2Limit {
for d1 in 0..d1Limit {
let in_idx = (d1Start + d1 * d1Advance) * d1Multiplier + (d2Start + d2 * d2Advance) * d2Multiplier;
outBuffer[i as usize] = inBuffer[in_idx as usize];
i += 1;
}
}
ব্যবহার করে মরিচা ফাইল কম্পাইল করা হচ্ছে
$ wasm-pack build
আঠালো কোডের প্রায় 100 বাইট সহ একটি 7.6KB wasm মডিউল দেয় (উভয় জিজিপের পরে)।
সমাবেশ স্ক্রিপ্ট
এসেম্বলিস্ক্রিপ্ট একটি মোটামুটি তরুণ প্রজেক্ট যার লক্ষ্য হল একটি টাইপস্ক্রিপ্ট-টু-ওয়েবঅ্যাসেম্বলি কম্পাইলার। এটা মনে রাখা গুরুত্বপূর্ণ, যাইহোক, এটি শুধুমাত্র কোনো TypeScript ব্যবহার করবে না। অ্যাসেম্বলিস্ক্রিপ্ট টাইপস্ক্রিপ্টের মতো একই সিনট্যাক্স ব্যবহার করে কিন্তু তাদের নিজস্ব জন্য স্ট্যান্ডার্ড লাইব্রেরি স্যুইচ করে। তাদের স্ট্যান্ডার্ড লাইব্রেরি WebAssembly এর ক্ষমতার মডেল করে। তার মানে আপনি WebAssembly-এর কাছাকাছি থাকা কোনো TypeScript কম্পাইল করতে পারবেন না, কিন্তু এর মানে এই যে WebAssembly লিখতে আপনাকে একটি নতুন প্রোগ্রামিং ভাষা শিখতে হবে না!
for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
let in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
store<u32>(offset + i * 4 + 4, load<u32>(in_idx * 4 + 4));
i += 1;
}
}
আমাদের rotate()
ফাংশনের ছোট ধরনের সারফেস বিবেচনা করে, এই কোডটি অ্যাসেম্বলিস্ক্রিপ্টে পোর্ট করা মোটামুটি সহজ ছিল। ফাংশন load<T>(ptr: usize)
এবং store<T>(ptr: usize, value: T)
কাঁচা মেমরি অ্যাক্সেস করতে এসেম্বলিস্ক্রিপ্ট দ্বারা প্রদান করা হয়। আমাদের অ্যাসেম্বলিস্ক্রিপ্ট ফাইল কম্পাইল করতে, আমাদের শুধুমাত্র AssemblyScript/assemblyscript
এনপিএম প্যাকেজ ইনস্টল করতে হবে এবং চালাতে হবে
$ asc rotate.ts -b assemblyscript.wasm --validate -O3
এসেম্বলিস্ক্রিপ্ট আমাদের একটি ~300 বাইট ওয়াএসএম মডিউল এবং কোন আঠালো কোড প্রদান করবে। মডিউলটি শুধু ভ্যানিলা WebAssembly API-এর সাথে কাজ করে।
WebAssembly ফরেনসিক
2টি অন্যান্য ভাষার তুলনায় রাস্টের 7.6KB আশ্চর্যজনকভাবে বড়। WebAssembly ইকোসিস্টেমে কয়েকটি টুল রয়েছে যা আপনাকে আপনার WebAssembly ফাইলগুলিকে বিশ্লেষণ করতে সাহায্য করতে পারে (যে ভাষা দিয়েই তৈরি করা হয়েছে তা নির্বিশেষে) এবং কী চলছে তা আপনাকে জানাতে এবং আপনার পরিস্থিতির উন্নতি করতে সাহায্য করতে পারে৷
টুইগি
Twiggy হল Rust এর WebAssembly টিমের আরেকটি টুল যা একটি WebAssembly মডিউল থেকে একগুচ্ছ অন্তর্দৃষ্টিপূর্ণ ডেটা বের করে। টুলটি মরিচা-নির্দিষ্ট নয় এবং আপনাকে মডিউলের কল গ্রাফের মতো জিনিসগুলি পরিদর্শন করতে, অব্যবহৃত বা অপ্রয়োজনীয় বিভাগগুলি নির্ধারণ করতে এবং আপনার মডিউলের মোট ফাইলের আকারে কোন বিভাগগুলি অবদান রাখছে তা নির্ধারণ করতে দেয়৷ পরবর্তীটি টুইগির top
কমান্ড দিয়ে করা যেতে পারে:
$ twiggy top rotate_bg.wasm
এই ক্ষেত্রে আমরা দেখতে পাচ্ছি যে আমাদের ফাইলের আকারের বেশিরভাগই বরাদ্দকারী থেকে আসে। এটি আশ্চর্যজনক ছিল যেহেতু আমাদের কোড গতিশীল বরাদ্দ ব্যবহার করছে না। আরেকটি বড় অবদানকারী ফ্যাক্টর হল একটি "ফাংশন নাম" উপধারা।
wasm-ফালা
wasm-strip
হল WebAssembly Binary Toolkit বা সংক্ষেপে wabt-এর একটি টুল। এটিতে কয়েকটি সরঞ্জাম রয়েছে যা আপনাকে WebAssembly মডিউলগুলি পরিদর্শন এবং ম্যানিপুলেট করার অনুমতি দেয়। wasm2wat
হল একটি disassembler যা একটি বাইনারি wasm মডিউলকে মানব-পাঠযোগ্য বিন্যাসে পরিণত করে। Wabt-এ wat2wasm
ও রয়েছে যা আপনাকে সেই মানব-পাঠযোগ্য বিন্যাসটিকে একটি বাইনারি wasm মডিউলে ফিরিয়ে আনতে দেয়। যদিও আমরা আমাদের WebAssembly ফাইলগুলি পরিদর্শন করার জন্য এই দুটি পরিপূরক সরঞ্জাম ব্যবহার করেছি, আমরা wasm-strip
সবচেয়ে দরকারী বলে মনে করেছি। wasm-strip
একটি WebAssembly মডিউল থেকে অপ্রয়োজনীয় বিভাগ এবং মেটাডেটা সরিয়ে দেয়:
$ wasm-strip rotate_bg.wasm
এটি মরিচা মডিউলের ফাইলের আকার 7.5KB থেকে 6.6KB (gzip-এর পরে) কমিয়ে দেয়।
wasm-অপ্ট
wasm-opt
হল Binaryen থেকে একটি টুল। এটি একটি WebAssembly মডিউল নেয় এবং এটি শুধুমাত্র বাইটকোডের উপর ভিত্তি করে আকার এবং কর্মক্ষমতা উভয়ের জন্য অপ্টিমাইজ করার চেষ্টা করে। Emscripten এর মত কিছু টুল ইতিমধ্যেই এই টুলটি চালায়, কিছু অন্যরা করে না। এই টুলগুলি ব্যবহার করে কিছু অতিরিক্ত বাইট চেষ্টা করা এবং সংরক্ষণ করা সাধারণত একটি ভাল ধারণা।
wasm-opt -O3 -o rotate_bg_opt.wasm rotate_bg.wasm
wasm-opt
সাহায্যে আমরা gzip-এর পরে মোট 6.2KB ছাড়তে আরও মুষ্টিমেয় বাইট শেভ করতে পারি।
#![no_std]
কিছু পরামর্শ এবং গবেষণার পর, আমরা #![no_std]
বৈশিষ্ট্যটি ব্যবহার করে, রাস্টের স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার না করে আমাদের রাস্ট কোডটি পুনরায় লিখেছি। এটি আমাদের মডিউল থেকে বরাদ্দকারী কোডটি সরিয়ে, গতিশীল মেমরি বরাদ্দ সম্পূর্ণরূপে অক্ষম করে। এই মরিচা ফাইলের সাথে কম্পাইল করা হচ্ছে
$ rustc --target=wasm32-unknown-unknown -C opt-level=3 -o rust.wasm rotate.rs
wasm-opt
, wasm-strip
এবং gzip-এর পরে একটি 1.6KB wasm মডিউল দিয়েছে৷ যদিও এটি এখনও সি এবং অ্যাসেম্বলিস্ক্রিপ্ট দ্বারা উত্পন্ন মডিউলগুলির চেয়ে বড়, এটি হালকা ওজন হিসাবে বিবেচিত হওয়ার মতো যথেষ্ট ছোট।
কর্মক্ষমতা
আমরা একা ফাইলের আকারের উপর ভিত্তি করে সিদ্ধান্তে যাওয়ার আগে — আমরা ফাইলের আকার নয়, কর্মক্ষমতা অপ্টিমাইজ করার জন্য এই যাত্রায় গিয়েছিলাম। তাহলে কিভাবে আমরা কর্মক্ষমতা পরিমাপ করেছি এবং ফলাফল কি ছিল?
বেঞ্চমার্ক কিভাবে
WebAssembly একটি নিম্ন-স্তরের বাইটকোড ফর্ম্যাট হওয়া সত্ত্বেও, হোস্ট-নির্দিষ্ট মেশিন কোড তৈরি করার জন্য এটি এখনও একটি কম্পাইলারের মাধ্যমে পাঠাতে হবে। জাভাস্ক্রিপ্টের মতই, কম্পাইলার একাধিক পর্যায়ে কাজ করে। সহজভাবে বলা হয়েছে: প্রথম পর্যায়টি কম্পাইল করার ক্ষেত্রে অনেক দ্রুত কিন্তু ধীর কোড তৈরি করে। একবার মডিউলটি চলতে শুরু করলে, ব্রাউজার কোন অংশগুলি প্রায়শই ব্যবহার করা হয় তা পর্যবেক্ষণ করে এবং সেগুলিকে আরও অপ্টিমাইজিং কিন্তু ধীর কম্পাইলারের মাধ্যমে পাঠায়।
আমাদের ব্যবহারের ক্ষেত্রে আকর্ষণীয় যে একটি চিত্র ঘোরানোর জন্য কোডটি একবার ব্যবহার করা হবে, সম্ভবত দুবার। তাই বেশিরভাগ ক্ষেত্রেই আমরা কখনই অপ্টিমাইজিং কম্পাইলারের সুবিধা পাব না। বেঞ্চমার্ক করার সময় এটি মনে রাখা গুরুত্বপূর্ণ। আমাদের WebAssembly মডিউলগুলি 10,000 বার একটি লুপে চালানো অবাস্তব ফলাফল দেবে৷ বাস্তবসম্মত সংখ্যা পেতে, আমাদের একবার মডিউলটি চালানো উচিত এবং সেই একক রানের সংখ্যার উপর ভিত্তি করে সিদ্ধান্ত নেওয়া উচিত।
কর্মক্ষমতা তুলনা
এই দুটি গ্রাফ একই ডেটাতে ভিন্ন দৃষ্টিভঙ্গি। প্রথম গ্রাফে আমরা প্রতি ব্রাউজারে তুলনা করি, দ্বিতীয় গ্রাফে আমরা ব্যবহৃত ভাষা প্রতি তুলনা করি। দয়া করে মনে রাখবেন যে আমি একটি লগারিদমিক টাইমস্কেল বেছে নিয়েছি। এটিও গুরুত্বপূর্ণ যে সমস্ত বেঞ্চমার্ক একই 16 মেগাপিক্সেল পরীক্ষার চিত্র এবং একই হোস্ট মেশিন ব্যবহার করছে, একটি ব্রাউজার ছাড়া, যা একই মেশিনে চালানো যাবে না।
এই গ্রাফগুলিকে খুব বেশি বিশ্লেষণ না করেই, এটা স্পষ্ট যে আমরা আমাদের মূল কার্যক্ষমতা সমস্যার সমাধান করেছি: সমস্ত WebAssembly মডিউল ~500ms বা তার কম সময়ে চলে৷ এটি নিশ্চিত করে যে আমরা শুরুতে কী রেখেছি: WebAssembly আপনাকে অনুমানযোগ্য কার্যক্ষমতা দেয়। আমরা কোন ভাষা বেছে নিই না কেন, ব্রাউজার এবং ভাষার মধ্যে পার্থক্য ন্যূনতম। সঠিকভাবে বলতে গেলে: সমস্ত ব্রাউজার জুড়ে জাভাস্ক্রিপ্টের স্ট্যান্ডার্ড বিচ্যুতি হল ~400ms, যখন সমস্ত ব্রাউজার জুড়ে আমাদের সমস্ত WebAssembly মডিউলের স্ট্যান্ডার্ড বিচ্যুতি হল ~80ms৷
প্রচেষ্টা
আরেকটি মেট্রিক হল আমাদের WebAssembly মডিউল তৈরি এবং squosh-এ সংহত করার জন্য আমাদের যে পরিমাণ প্রচেষ্টা করতে হয়েছিল। প্রচেষ্টার জন্য একটি সাংখ্যিক মান নির্ধারণ করা কঠিন, তাই আমি কোনও গ্রাফ তৈরি করব না তবে কয়েকটি জিনিস রয়েছে যা আমি উল্লেখ করতে চাই:
সমাবেশ স্ক্রিপ্ট ঘর্ষণহীন ছিল. এটি শুধু আপনাকে WebAssembly লেখার জন্য TypeScript ব্যবহার করার অনুমতি দেয় না, যা আমার সহকর্মীদের জন্য কোড-রিভিউকে খুব সহজ করে তোলে, কিন্তু এটি আঠালো-মুক্ত WebAssembly মডিউলও তৈরি করে যা শালীন কর্মক্ষমতা সহ খুব ছোট। TypeScript ইকোসিস্টেমের টুলিং, যেমন সুন্দর এবং tslint, সম্ভবত কাজ করবে।
wasm-pack
এর সাথে সংমিশ্রণে মরিচাও অত্যন্ত সুবিধাজনক, তবে বড় WebAssembly প্রকল্পগুলিতে আরও বেশি করে বাইন্ডিং এবং মেমরি পরিচালনার প্রয়োজন। একটি প্রতিযোগিতামূলক ফাইলের আকার অর্জনের জন্য আমাদের সুখী-পথ থেকে কিছুটা বিচ্যুত হতে হয়েছিল।
C এবং Emscripten বাক্সের বাইরে একটি খুব ছোট এবং অত্যন্ত পারফরম্যান্সযুক্ত WebAssembly মডিউল তৈরি করেছে, কিন্তু আঠালো কোডে ঝাঁপিয়ে পড়ার সাহস ছাড়াই এবং এটিকে খালি প্রয়োজনে কমিয়ে আনার মোট আকার (WebAssembly মডিউল + আঠালো কোড) বেশ বড় হয়ে যায়।
উপসংহার
সুতরাং আপনার যদি একটি JS হট পাথ থাকে এবং আপনি WebAssembly এর সাথে দ্রুত বা আরও বেশি সামঞ্জস্যপূর্ণ করতে চান তবে আপনার কোন ভাষা ব্যবহার করা উচিত। পারফরম্যান্স প্রশ্নগুলির সাথে সর্বদা হিসাবে, উত্তর হল: এটি নির্ভর করে। তাই আমরা কি জাহাজ?
আমরা ব্যবহৃত বিভিন্ন ভাষার মডিউল আকার/পারফরম্যান্স ট্রেডঅফের সাথে তুলনা করে, সেরা পছন্দটি হয় C বা এসেম্বলিস্ক্রিপ্ট বলে মনে হয়। আমরা মরিচা শিপিং করার সিদ্ধান্ত নিয়েছে . এই সিদ্ধান্তের একাধিক কারণ রয়েছে: এখন পর্যন্ত Squosh-এ পাঠানো সমস্ত কোডেক Emscripten ব্যবহার করে সংকলিত হয়েছে। আমরা WebAssembly ইকোসিস্টেম সম্পর্কে আমাদের জ্ঞানকে প্রসারিত করতে এবং উৎপাদনে একটি ভিন্ন ভাষা ব্যবহার করতে চেয়েছিলাম। এসেম্বলিস্ক্রিপ্ট একটি শক্তিশালী বিকল্প, কিন্তু প্রকল্পটি তুলনামূলকভাবে তরুণ এবং কম্পাইলারটি রাস্ট কম্পাইলারের মতো পরিপক্ক নয়।
যদিও রাস্ট এবং অন্যান্য ভাষার আকারের মধ্যে ফাইলের আকারের পার্থক্যটি স্ক্যাটার গ্রাফে বেশ কঠোর দেখায়, বাস্তবে এটি এত বড় ব্যাপার নয়: 500B বা 1.6KB এমনকি 2G এর উপরে লোড করতে সেকেন্ডের 1/10তমেরও কম সময় লাগে। এবং মরিচা আশা করি শীঘ্রই মডিউল আকারের পরিপ্রেক্ষিতে ফাঁকটি বন্ধ করবে।
রানটাইম পারফরম্যান্সের পরিপ্রেক্ষিতে, এসেম্বলিস্ক্রিপ্টের তুলনায় ব্রাউজার জুড়ে রাস্টের দ্রুত গড় রয়েছে। বিশেষ করে বড় প্রকল্পগুলিতে ম্যানুয়াল কোড অপ্টিমাইজেশনের প্রয়োজন ছাড়াই মরিচা দ্রুত কোড তৈরি করতে পারে। কিন্তু এটি আপনাকে ব্যবহার করা থেকে বিরত রাখা উচিত নয় যা আপনি সবচেয়ে আরামদায়ক।
যে সব বলা হচ্ছে: এসেম্বলিস্ক্রিপ্ট একটি মহান আবিষ্কার হয়েছে. এটি ওয়েব ডেভেলপারদের একটি নতুন ভাষা শেখার ছাড়াই WebAssembly মডিউল তৈরি করতে দেয়। এসেম্বলিস্ক্রিপ্ট টিম অত্যন্ত প্রতিক্রিয়াশীল এবং সক্রিয়ভাবে তাদের টুলচেন উন্নত করার জন্য কাজ করছে। আমরা অবশ্যই ভবিষ্যতে অ্যাসেম্বলিস্ক্রিপ্টের উপর নজর রাখব।
আপডেট: মরিচা
এই নিবন্ধটি প্রকাশ করার পরে, রাস্ট দলের নিক ফিটজেরাল্ড আমাদেরকে তাদের চমৎকার রাস্ট ওয়াসম বইয়ের দিকে নির্দেশ করেছেন, যাতে ফাইলের আকার অপ্টিমাইজ করার একটি বিভাগ রয়েছে। সেখানে নির্দেশাবলী অনুসরণ করে (সবচেয়ে উল্লেখযোগ্যভাবে লিঙ্ক টাইম অপ্টিমাইজেশান এবং ম্যানুয়াল প্যানিক হ্যান্ডলিং সক্ষম করা) আমাদেরকে "স্বাভাবিক" মরিচা কোড লিখতে এবং ফাইলের আকার ফুলিয়ে না দিয়ে Cargo
(মরিচা-এর npm
) ব্যবহারে ফিরে যেতে দেয়। মরিচা মডিউল জিজিপের পরে 370B দিয়ে শেষ হয়। বিশদ বিবরণের জন্য, অনুগ্রহ করে স্কুশ-এ আমি যে PR খুলেছিলাম তা একবার দেখুন।
অ্যাশলে উইলিয়ামস , স্টিভ ক্ল্যাবনিক , নিক ফিটজেরাল্ড এবং ম্যাক্স গ্রেকে এই যাত্রায় তাদের সমস্ত সাহায্যের জন্য বিশেষ ধন্যবাদ৷
,এটা ধারাবাহিকভাবে দ্রুত, ইয়ো
আমার পূর্ববর্তী নিবন্ধগুলিতে আমি কীভাবে WebAssembly আপনাকে C/C++ এর লাইব্রেরি ইকোসিস্টেম ওয়েবে আনতে অনুমতি দেয় সে সম্পর্কে কথা বলেছিলাম। একটি অ্যাপ যা C/C++ লাইব্রেরির ব্যাপক ব্যবহার করে তা হল squosh , আমাদের ওয়েব অ্যাপ যা আপনাকে C++ থেকে WebAssembly-তে সংকলিত বিভিন্ন কোডেক দিয়ে ছবি কম্প্রেস করতে দেয়।
WebAssembly হল একটি নিম্ন-স্তরের ভার্চুয়াল মেশিন যা .wasm
ফাইলে সংরক্ষিত বাইটকোড চালায়। এই বাইট কোড দৃঢ়ভাবে টাইপ করা হয়েছে এবং এমনভাবে গঠন করা হয়েছে যে এটি জাভাস্ক্রিপ্টের চেয়ে অনেক দ্রুত হোস্ট সিস্টেমের জন্য কম্পাইল এবং অপ্টিমাইজ করা যায়। WebAssembly কোড চালানোর জন্য একটি পরিবেশ প্রদান করে যেটিতে স্যান্ডবক্সিং এবং এমবেডিং ছিল শুরু থেকেই।
আমার অভিজ্ঞতায়, ওয়েবে বেশিরভাগ পারফরম্যান্স সমস্যা বাধ্যতামূলক লেআউট এবং অত্যধিক পেইন্টের কারণে সৃষ্ট হয় তবে প্রতিবার এবং তারপরে একটি অ্যাপকে একটি গণনামূলকভাবে ব্যয়বহুল কাজ করতে হবে যা অনেক সময় নেয়। WebAssembly এখানে সাহায্য করতে পারেন.
গরম পথ
স্কুশ-এ আমরা একটি জাভাস্ক্রিপ্ট ফাংশন লিখেছি যা একটি ইমেজ বাফারকে 90 ডিগ্রির গুণিতক দ্বারা ঘোরায়। যদিও অফস্ক্রিন ক্যানভাস এর জন্য আদর্শ হবে, আমরা যে ব্রাউজারগুলিকে টার্গেট করছিলাম সেগুলি জুড়ে এটি সমর্থিত নয় এবং Chrome-এ একটু বগি ।
এই ফাংশনটি একটি ইনপুট চিত্রের প্রতিটি পিক্সেলের উপর পুনরাবৃত্তি করে এবং এটিকে আউটপুট চিত্রের একটি ভিন্ন অবস্থানে অনুলিপি করে ঘূর্ণন অর্জন করতে। একটি 4094px বাই 4096px চিত্রের জন্য (16 মেগাপিক্সেল) এর ভিতরের কোড ব্লকের 16 মিলিয়ন পুনরাবৃত্তির প্রয়োজন হবে, যাকে আমরা "হট পাথ" বলি। এত বড় সংখ্যক পুনরাবৃত্তি সত্ত্বেও, আমরা পরীক্ষিত তিনটি ব্রাউজারের মধ্যে দুটি 2 সেকেন্ড বা তারও কম সময়ে কাজটি শেষ করি। এই ধরনের মিথস্ক্রিয়া জন্য একটি গ্রহণযোগ্য সময়কাল.
for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
const in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
outBuffer[i] = inBuffer[in_idx];
i += 1;
}
}
তবে একটি ব্রাউজার 8 সেকেন্ডের বেশি সময় নেয়। ব্রাউজারগুলি যেভাবে জাভাস্ক্রিপ্ট অপ্টিমাইজ করে তা সত্যিই জটিল এবং বিভিন্ন ইঞ্জিন বিভিন্ন জিনিসের জন্য অপ্টিমাইজ করে৷ কিছু কাঁচা সম্পাদনের জন্য অপ্টিমাইজ করে, কিছু DOM এর সাথে ইন্টারঅ্যাকশনের জন্য অপ্টিমাইজ করে৷ এই ক্ষেত্রে, আমরা একটি ব্রাউজারে একটি অপ্টিমাইজড পাথ হিট করেছি৷
অন্যদিকে WebAssembly সম্পূর্ণরূপে কাঁচা এক্সিকিউশন গতির চারপাশে নির্মিত। তাই যদি আমরা এই ধরনের কোডের জন্য ব্রাউজার জুড়ে দ্রুত, অনুমানযোগ্য পারফরম্যান্স চাই, WebAssembly সাহায্য করতে পারে।
অনুমানযোগ্য কর্মক্ষমতা জন্য WebAssembly
সাধারণভাবে, JavaScript এবং WebAssembly একই শীর্ষ কর্মক্ষমতা অর্জন করতে পারে। যাইহোক, জাভাস্ক্রিপ্টের জন্য এই কর্মক্ষমতা শুধুমাত্র "দ্রুত পথ" এ পৌঁছানো যেতে পারে এবং সেই "দ্রুত পথে" থাকা প্রায়ই কঠিন। WebAssembly অফার করে এমন একটি মূল সুবিধা হল অনুমানযোগ্য কর্মক্ষমতা, এমনকি ব্রাউজার জুড়ে। কঠোর টাইপিং এবং নিম্ন-স্তরের আর্কিটেকচার কম্পাইলারকে শক্তিশালী গ্যারান্টি দেওয়ার অনুমতি দেয় যাতে WebAssembly কোড শুধুমাত্র একবার অপ্টিমাইজ করতে হয় এবং সর্বদা "দ্রুত পথ" ব্যবহার করবে।
WebAssembly জন্য লেখা
পূর্বে আমরা C/C++ লাইব্রেরি নিয়েছিলাম এবং ওয়েবে তাদের কার্যকারিতা ব্যবহার করার জন্য WebAssembly-এ কম্পাইল করেছি। আমরা সত্যিই লাইব্রেরির কোড স্পর্শ করিনি, আমরা ব্রাউজার এবং লাইব্রেরির মধ্যে সেতু তৈরি করতে অল্প পরিমাণে C/C++ কোড লিখেছি। এবার আমাদের অনুপ্রেরণা ভিন্ন: আমরা WebAssembly কে মাথায় রেখে স্ক্র্যাচ থেকে কিছু লিখতে চাই যাতে আমরা WebAssembly এর সুবিধাগুলো ব্যবহার করতে পারি।
ওয়েব অ্যাসেম্বলি আর্কিটেকচার
WebAssembly-এর জন্য লেখার সময়, WebAssembly আসলে কী তা সম্পর্কে আরও কিছুটা বোঝা উপকারী।
WebAssembly.org উদ্ধৃত করতে:
যখন আপনি WebAssembly-এ C বা রাস্ট কোডের একটি অংশ কম্পাইল করেন, আপনি একটি .wasm
ফাইল পাবেন যাতে একটি মডিউল ঘোষণা রয়েছে। এই ঘোষণায় মডিউলটি তার পরিবেশ থেকে প্রত্যাশিত "আমদানি" এর একটি তালিকা, রপ্তানির একটি তালিকা যা এই মডিউল হোস্টের কাছে উপলব্ধ করে (ফাংশন, ধ্রুবক, মেমরির অংশ) এবং অবশ্যই এর মধ্যে থাকা ফাংশনগুলির জন্য প্রকৃত বাইনারি নির্দেশাবলী। .
এমন কিছু যা আমি এটির দিকে নজর না দেওয়া পর্যন্ত বুঝতে পারিনি: যে স্ট্যাকটি WebAssembly কে একটি "স্ট্যাক-ভিত্তিক ভার্চুয়াল মেশিন" করে তোলে সেটি মেমরির অংশে সংরক্ষণ করা হয় না যা WebAssembly মডিউল ব্যবহার করে। স্ট্যাকটি সম্পূর্ণভাবে VM-অভ্যন্তরীণ এবং ওয়েব ডেভেলপারদের কাছে অ্যাক্সেসযোগ্য নয় (DevTools ব্যতীত)। এইভাবে WebAssembly মডিউলগুলি লেখা সম্ভব যেগুলির জন্য কোনও অতিরিক্ত মেমরির প্রয়োজন নেই এবং শুধুমাত্র VM-অভ্যন্তরীণ স্ট্যাক ব্যবহার করুন।
আমাদের ক্ষেত্রে আমাদের চিত্রের পিক্সেলগুলিতে নির্বিচারে অ্যাক্সেসের অনুমতি দেওয়ার জন্য এবং সেই চিত্রের একটি ঘোরানো সংস্করণ তৈরি করতে আমাদের কিছু অতিরিক্ত মেমরি ব্যবহার করতে হবে। এটি WebAssembly.Memory
এর জন্য।
মেমরি ব্যবস্থাপনা
সাধারণত, আপনি একবার অতিরিক্ত মেমরি ব্যবহার করলে আপনি সেই মেমরিটিকে কোনো না কোনোভাবে পরিচালনা করার প্রয়োজন খুঁজে পাবেন। মেমরির কোন অংশ ব্যবহার করা হয়? কোনটি বিনামূল্যে? C-তে, উদাহরণস্বরূপ, আপনার malloc(n)
ফাংশন রয়েছে যা n
পরপর বাইটের মেমরি স্পেস খুঁজে পায়। এই ধরনের ফাংশনকে "বরাদ্দকারী"ও বলা হয়। অবশ্যই ব্যবহৃত বরাদ্দকারীর বাস্তবায়ন আপনার WebAssembly মডিউলে অন্তর্ভুক্ত করা আবশ্যক এবং আপনার ফাইলের আকার বৃদ্ধি করবে। এই মেমরি ম্যানেজমেন্ট ফাংশনগুলির এই আকার এবং কার্যকারিতা ব্যবহৃত অ্যালগরিদমের উপর নির্ভর করে বেশ উল্লেখযোগ্যভাবে পরিবর্তিত হতে পারে, যে কারণে অনেক ভাষা ("dmalloc", "emmalloc", "wee_alloc", ইত্যাদি) থেকে বেছে নেওয়ার জন্য একাধিক বাস্তবায়নের প্রস্তাব দেয়।
আমাদের ক্ষেত্রে আমরা WebAssembly মডিউল চালানোর আগে ইনপুট চিত্রের মাত্রা (এবং আউটপুট চিত্রের মাত্রা) জানি। এখানে আমরা একটি সুযোগ দেখেছি: ঐতিহ্যগতভাবে, আমরা একটি WebAssembly ফাংশনে একটি প্যারামিটার হিসাবে ইনপুট চিত্রের RGBA বাফারটি পাস করব এবং একটি রিটার্ন মান হিসাবে ঘোরানো চিত্রটি ফিরিয়ে দেব। সেই রিটার্ন মান তৈরি করতে আমাদের বরাদ্দকারী ব্যবহার করতে হবে। কিন্তু যেহেতু আমরা জানি মোট মেমরির পরিমাণ (ইনপুট ইমেজের আকারের দ্বিগুণ, একবার ইনপুটের জন্য এবং একবার আউটপুটের জন্য), আমরা JavaScript ব্যবহার করে ইনপুট ইমেজটিকে WebAssembly মেমরিতে রাখতে পারি, 2nd তৈরি করতে WebAssembly মডিউল চালান, ঘোরানো চিত্র এবং তারপর ফলাফলটি পড়ার জন্য জাভাস্ক্রিপ্ট ব্যবহার করুন। আমরা কোনো মেমরি ব্যবস্থাপনা ব্যবহার না করেই পার পেয়ে যেতে পারি!
পছন্দের জন্য নষ্ট হয়ে গেছে
আপনি যদি আসল JavaScript ফাংশনটি দেখেন যা আমরা WebAssembly-fy করতে চাই, আপনি দেখতে পাবেন যে এটি একটি সম্পূর্ণরূপে গণনামূলক কোড যার কোনো জাভাস্ক্রিপ্ট-নির্দিষ্ট API নেই। যেমন এই কোডটি যেকোনো ভাষায় পোর্ট করার জন্য এটি মোটামুটি সোজা হওয়া উচিত। আমরা WebAssembly-এ কম্পাইল করা 3টি ভিন্ন ভাষা মূল্যায়ন করেছি: C/C++, Rust এবং AssemblyScript। প্রতিটি ভাষার জন্য আমাদের একমাত্র প্রশ্নের উত্তর দিতে হবে: মেমরি ম্যানেজমেন্ট ফাংশন ব্যবহার না করে আমরা কীভাবে কাঁচা মেমরি অ্যাক্সেস করব?
সি এবং এমস্ক্রিপ্টেন
Emscripten হল WebAssembly টার্গেটের জন্য একটি C কম্পাইলার। Emscripten-এর লক্ষ্য হল GCC বা ক্ল্যাং-এর মতো সুপরিচিত C কম্পাইলারগুলির জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবে কাজ করা এবং বেশিরভাগই ফ্ল্যাগ সামঞ্জস্যপূর্ণ। এটি এমস্ক্রিপ্টেন-এর মিশনের একটি মূল অংশ কারণ এটি বিদ্যমান C এবং C++ কোডগুলিকে WebAssembly-এ সংকলন করা যতটা সম্ভব সহজ করতে চায়।
কাঁচা মেমরি অ্যাক্সেস করা C এর প্রকৃতির মধ্যে রয়েছে এবং সেই কারণেই পয়েন্টার বিদ্যমান:
uint8_t* ptr = (uint8_t*)0x124;
ptr[0] = 0xFF;
এখানে আমরা 0x124
নম্বরটিকে সাইনবিহীন, 8-বিট পূর্ণসংখ্যা (বা বাইট) এ একটি পয়েন্টারে পরিণত করছি। এটি কার্যকরভাবে ptr
ভেরিয়েবলকে মেমরি অ্যাড্রেস 0x124
থেকে শুরু করে একটি অ্যারেতে পরিণত করে, যা আমরা অন্য যেকোনো অ্যারের মতো ব্যবহার করতে পারি, যা আমাদের পড়ার এবং লেখার জন্য পৃথক বাইট অ্যাক্সেস করতে দেয়। আমাদের ক্ষেত্রে আমরা একটি চিত্রের একটি RGBA বাফার দেখছি যা আমরা ঘূর্ণন অর্জনের জন্য পুনরায় অর্ডার করতে চাই। একটি পিক্সেল সরানোর জন্য আমাদের আসলে একবারে পরপর 4 বাইট সরাতে হবে (প্রতিটি চ্যানেলের জন্য একটি বাইট: R, G, B এবং A)। এটি সহজ করার জন্য আমরা স্বাক্ষরবিহীন, 32-বিট পূর্ণসংখ্যার একটি অ্যারে তৈরি করতে পারি। নিয়ম অনুসারে, আমাদের ইনপুট চিত্রটি ঠিকানা 4 এ শুরু হবে এবং আমাদের আউটপুট চিত্রটি ইনপুট চিত্র শেষ হওয়ার পরে সরাসরি শুরু হবে:
int bpp = 4;
int imageSize = inputWidth * inputHeight * bpp;
uint32_t* inBuffer = (uint32_t*) 4;
uint32_t* outBuffer = (uint32_t*) (inBuffer + imageSize);
for (int d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (int d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
int in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
outBuffer[i] = inBuffer[in_idx];
i += 1;
}
}
সম্পূর্ণ জাভাস্ক্রিপ্ট ফাংশনটি সি-তে পোর্ট করার পরে, আমরা emcc
দিয়ে C ফাইলটি কম্পাইল করতে পারি:
$ emcc -O3 -s ALLOW_MEMORY_GROWTH=1 -o c.js rotate.c
বরাবরের মতো, emscripten c.js
নামে একটি আঠালো কোড ফাইল এবং c.wasm
নামে একটি wasm মডিউল তৈরি করে। লক্ষ্য করুন যে wsm মডিউলটি শুধুমাত্র ~260 বাইট পর্যন্ত জিজিপ করে, যখন gzip-এর পরে আঠালো কোড প্রায় 3.5KB হয়। কিছু নাড়াচাড়া করার পরে, আমরা আঠালো কোডটি ছিঁড়ে ফেলতে এবং ভ্যানিলা এপিআইগুলির সাথে WebAssembly মডিউলগুলিকে ইনস্ট্যান্টিয়েট করতে সক্ষম হয়েছি। যতক্ষণ না আপনি C স্ট্যান্ডার্ড লাইব্রেরি থেকে কিছু ব্যবহার করছেন না ততক্ষণ পর্যন্ত এমস্ক্রিপ্টেনের সাথে এটি প্রায়ই সম্ভব।
মরিচা
মরিচা হল একটি নতুন, আধুনিক প্রোগ্রামিং ভাষা যার একটি সমৃদ্ধ টাইপ সিস্টেম, কোন রানটাইম নেই এবং একটি মালিকানা মডেল যা মেমরি-নিরাপত্তা এবং থ্রেড-নিরাপত্তার নিশ্চয়তা দেয়। জং একটি মূল বৈশিষ্ট্য হিসাবে WebAssembly সমর্থন করে এবং রাস্ট টিম WebAssembly ইকোসিস্টেমে অনেক চমৎকার টুলিং অবদান রেখেছে।
এই সরঞ্জামগুলির মধ্যে একটি হল wasm-pack
, রাস্টওয়াসম ওয়ার্কিং গ্রুপ দ্বারা। wasm-pack
আপনার কোড নেয় এবং এটিকে একটি ওয়েব-বন্ধুত্বপূর্ণ মডিউলে পরিণত করে যা ওয়েবপ্যাকের মতো বান্ডলারের সাথে বাক্সের বাইরে কাজ করে। wasm-pack
একটি অত্যন্ত সুবিধাজনক অভিজ্ঞতা, কিন্তু বর্তমানে শুধুমাত্র মরিচা-এর জন্য কাজ করে। গ্রুপটি অন্যান্য WebAssembly-টার্গেটিং ভাষার জন্য সমর্থন যোগ করার কথা বিবেচনা করছে।
মরিচা-এ, স্লাইসগুলি হল অ্যারেগুলি যা সি-তে থাকে। এবং সি-তে যেমন, আমাদের স্লাইস তৈরি করতে হবে যা আমাদের শুরুর ঠিকানাগুলি ব্যবহার করে। এটি মেমরি সুরক্ষা মডেলের বিরুদ্ধে যায় যা রাস্ট প্রয়োগ করে, তাই আমাদের পথ পেতে আমাদের unsafe
কীওয়ার্ড ব্যবহার করতে হবে, আমাদের কোড লিখতে অনুমতি দেয় যা সেই মডেলের সাথে মেনে চলে না।
let imageSize = (inputWidth * inputHeight) as usize;
let inBuffer: &mut [u32];
let outBuffer: &mut [u32];
unsafe {
inBuffer = slice::from_raw_parts_mut::<u32>(4 as *mut u32, imageSize);
outBuffer = slice::from_raw_parts_mut::<u32>((imageSize * 4 + 4) as *mut u32, imageSize);
}
for d2 in 0..d2Limit {
for d1 in 0..d1Limit {
let in_idx = (d1Start + d1 * d1Advance) * d1Multiplier + (d2Start + d2 * d2Advance) * d2Multiplier;
outBuffer[i as usize] = inBuffer[in_idx as usize];
i += 1;
}
}
ব্যবহার করে মরিচা ফাইল কম্পাইল করা হচ্ছে
$ wasm-pack build
আঠালো কোডের প্রায় 100 বাইট সহ একটি 7.6KB wasm মডিউল দেয় (উভয় জিজিপের পরে)।
সমাবেশ স্ক্রিপ্ট
এসেম্বলিস্ক্রিপ্ট একটি মোটামুটি তরুণ প্রজেক্ট যার লক্ষ্য হল একটি টাইপস্ক্রিপ্ট-টু-ওয়েবঅ্যাসেম্বলি কম্পাইলার। এটা মনে রাখা গুরুত্বপূর্ণ, যাইহোক, এটি শুধুমাত্র কোনো TypeScript ব্যবহার করবে না। অ্যাসেম্বলিস্ক্রিপ্ট টাইপস্ক্রিপ্টের মতো একই সিনট্যাক্স ব্যবহার করে কিন্তু তাদের নিজস্ব জন্য স্ট্যান্ডার্ড লাইব্রেরি স্যুইচ করে। তাদের স্ট্যান্ডার্ড লাইব্রেরি WebAssembly এর ক্ষমতার মডেল করে। এর অর্থ আপনি কেবল ওয়েবসেম্বলিতে পড়ে থাকা কোনও টাইপস্ক্রিপ্ট সংকলন করতে পারবেন না, তবে এর অর্থ এই যে ওয়েবসেমি লিখতে আপনাকে কোনও নতুন প্রোগ্রামিং ভাষা শিখতে হবে না!
for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
let in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
store<u32>(offset + i * 4 + 4, load<u32>(in_idx * 4 + 4));
i += 1;
}
}
আমাদের rotate()
ফাংশনটি যে ছোট ধরণের পৃষ্ঠটি রয়েছে তা বিবেচনা করে, এই কোডটি এসেম্বলিস্ক্রিপ্টে পোর্ট করা মোটামুটি সহজ ছিল। ফাংশনগুলি load<T>(ptr: usize)
এবং store<T>(ptr: usize, value: T)
কাঁচা মেমরি অ্যাক্সেসের জন্য অ্যাসেমব্লিস্ক্রিপ্ট দ্বারা সরবরাহ করা হয়। আমাদের অ্যাসেমব্লিস্ক্রিপ্ট ফাইলটি সংকলন করতে, আমাদের কেবল AssemblyScript/assemblyscript
এনপিএম প্যাকেজ ইনস্টল করতে হবে এবং চালাতে হবে
$ asc rotate.ts -b assemblyscript.wasm --validate -O3
অ্যাসেমব্লিস্ক্রিপ্ট আমাদের একটি ~ 300 বাইট ওয়াসম মডিউল এবং কোনও আঠালো কোড সরবরাহ করবে। মডিউলটি কেবল ভ্যানিলা ওয়েবসেম্বলি এপিআইগুলির সাথে কাজ করে।
ওয়েবসেম্বলি ফরেনসিক
অন্য 2 টি ভাষার সাথে তুলনা করার সময় রাস্টের 7.6 কেবি আশ্চর্যজনকভাবে বড়। ওয়েবসেম্বল ইকোসিস্টেমে বেশ কয়েকটি সরঞ্জাম রয়েছে যা আপনাকে আপনার ওয়েবসেম্বল ফাইলগুলি বিশ্লেষণ করতে সহায়তা করতে পারে (যে ভাষাটি তৈরি করা হয়েছে তা নির্বিশেষে) এবং আপনাকে কী চলছে তা বলতে এবং আপনার পরিস্থিতি উন্নত করতে আপনাকে সহায়তা করতে পারে।
টুইগি
টুইগি হ'ল রাস্টের ওয়েবসেম্বলি টিমের আরেকটি সরঞ্জাম যা একটি ওয়েবসাম্বলি মডিউল থেকে একগুচ্ছ অন্তর্দৃষ্টিপূর্ণ ডেটা বের করে। সরঞ্জামটি মরিচা-নির্দিষ্ট নয় এবং আপনাকে মডিউলটির কল গ্রাফের মতো জিনিসগুলি পরিদর্শন করতে, অব্যবহৃত বা অতিমাত্রায় বিভাগগুলি নির্ধারণ করতে এবং কোন বিভাগগুলি আপনার মডিউলটির মোট ফাইল আকারে অবদান রাখছে তা নির্ধারণ করতে দেয়। দ্বিতীয়টি টুইগির top
কমান্ড দিয়ে করা যেতে পারে:
$ twiggy top rotate_bg.wasm
এই ক্ষেত্রে আমরা দেখতে পাচ্ছি যে আমাদের ফাইলের আকারের বেশিরভাগ অংশ বরাদ্দকারী থেকে আসে। এটি অবাক করার মতো ছিল যেহেতু আমাদের কোডটি গতিশীল বরাদ্দ ব্যবহার করছে না। আর একটি বড় অবদানকারী ফ্যাক্টর হ'ল একটি "ফাংশন নাম" উপ -ধারা।
ওয়াসম-স্ট্রিপ
wasm-strip
হ'ল ওয়েবসেম্বলি বাইনারি টুলকিট বা সংক্ষেপে WABT এর একটি সরঞ্জাম। এটিতে বেশ কয়েকটি সরঞ্জাম রয়েছে যা আপনাকে ওয়েবসেম্বলি মডিউলগুলি পরিদর্শন ও পরিচালনা করতে দেয়। wasm2wat
হ'ল একটি বিচ্ছেদ যা একটি বাইনারি ওয়াসম মডিউলটিকে একটি মানব-পঠনযোগ্য ফর্ম্যাটে পরিণত করে। WABT এ wat2wasm
রয়েছে যা আপনাকে সেই মানব-পঠনযোগ্য ফর্ম্যাটটিকে বাইনারি ওয়াসম মডিউলে ফিরিয়ে আনতে দেয়। যদিও আমরা আমাদের ওয়েবসেম্বলি ফাইলগুলি পরিদর্শন করতে এই দুটি পরিপূরক সরঞ্জাম ব্যবহার করেছি, আমরা wasm-strip
সবচেয়ে কার্যকর বলে মনে করেছি। wasm-strip
অপ্রয়োজনীয় বিভাগগুলি এবং মেটাডেটা একটি ওয়েবসেম্বল মডিউল থেকে সরিয়ে দেয়:
$ wasm-strip rotate_bg.wasm
এটি মরিচা মডিউলটির ফাইলের আকার 7.5 কেবি থেকে 6.6 কেবি (জিজেডিপের পরে) হ্রাস করে।
ওয়াসম-অপ্ট
wasm-opt
বাইনারেনের একটি সরঞ্জাম। এটি একটি ওয়েবসেম্বলি মডিউল নেয় এবং এটি কেবল বাইটকোডের উপর ভিত্তি করে আকার এবং পারফরম্যান্স উভয়ের জন্য এটি অনুকূল করার চেষ্টা করে। এমস্ক্রিপ্টেনের মতো কিছু সরঞ্জাম ইতিমধ্যে এই সরঞ্জামটি চালায়, অন্য কেউ কেউ তা করেন না। এই সরঞ্জামগুলি ব্যবহার করে কিছু অতিরিক্ত বাইট চেষ্টা করা এবং সংরক্ষণ করা সাধারণত একটি ভাল ধারণা।
wasm-opt -O3 -o rotate_bg_opt.wasm rotate_bg.wasm
wasm-opt
সহ আমরা জিজিপির পরে মোট 6.2 কেবি ছাড়তে আরও একটি মুঠো বাইট শেভ করতে পারি।
#! [no_std]
কিছু পরামর্শ এবং গবেষণার পরে, আমরা #![no_std]
বৈশিষ্ট্যটি ব্যবহার করে রাস্টের স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার না করেই আমাদের মরিচা কোডটি পুনরায় লিখেছি। এটি আমাদের মডিউল থেকে বরাদ্দকারী কোডটি সরিয়ে পুরোপুরি গতিশীল মেমরি বরাদ্দকে অক্ষম করে। এই মরিচা ফাইল সংকলন
$ rustc --target=wasm32-unknown-unknown -C opt-level=3 -o rust.wasm rotate.rs
wasm-opt
, wasm-strip
এবং জিজিপিপের পরে একটি 1.6 কেবি ওয়াসম মডিউল পেয়েছে। যদিও এটি এখনও সি এবং অ্যাসেমব্লিস্ক্রিপ্ট দ্বারা উত্পাদিত মডিউলগুলির চেয়ে বড়, তবে এটি হালকা ওজনের হিসাবে বিবেচিত হওয়ার পক্ষে যথেষ্ট ছোট।
কর্মক্ষমতা
আমরা একা ফাইলের আকারের উপর ভিত্তি করে সিদ্ধান্তে ঝাঁপ দেওয়ার আগে - আমরা ফাইলের আকার নয়, পারফরম্যান্সের অনুকূলকরণের জন্য এই যাত্রায় গিয়েছিলাম। তাহলে আমরা কীভাবে পারফরম্যান্স পরিমাপ করেছি এবং ফলাফলগুলি কী ছিল?
বেঞ্চমার্ক কিভাবে
ওয়েবসেম্বলিটি একটি নিম্ন-স্তরের বাইটকোড ফর্ম্যাট হওয়া সত্ত্বেও, হোস্ট-নির্দিষ্ট মেশিন কোড উত্পন্ন করতে এটি একটি সংকলকের মাধ্যমে প্রেরণ করা দরকার। জাভাস্ক্রিপ্টের মতোই সংকলক একাধিক পর্যায়ে কাজ করে। সহজভাবে বলেছিলেন: প্রথম পর্যায়ে সংকলনে অনেক দ্রুত তবে ধীর কোড উত্পন্ন করতে ঝোঁক। মডিউলটি চলতে শুরু করার পরে, ব্রাউজারটি পর্যবেক্ষণ করে যে কোন অংশগুলি ঘন ঘন ব্যবহৃত হয় এবং সেগুলি আরও অনুকূল তবে ধীর সংকলকের মাধ্যমে প্রেরণ করে।
আমাদের ব্যবহার-কেসটি আকর্ষণীয় যে কোনও চিত্র ঘোরানোর কোডটি একবার ব্যবহার করা হবে, সম্ভবত দু'বার ব্যবহার করা হবে। সুতরাং বেশিরভাগ ক্ষেত্রে আমরা কখনই অপ্টিমাইজিং সংকলকের সুবিধাগুলি পাব না। বেঞ্চমার্কিং করার সময় এটি মনে রাখা গুরুত্বপূর্ণ। একটি লুপে 10,000 বার আমাদের ওয়েবসেম্বলি মডিউলগুলি চালানো অবাস্তব ফলাফল দেয়। বাস্তবসম্মত সংখ্যা পেতে, আমাদের একবার মডিউলটি চালানো উচিত এবং সেই একক রান থেকে সংখ্যার ভিত্তিতে সিদ্ধান্ত নেওয়া উচিত।
কর্মক্ষমতা তুলনা
এই দুটি গ্রাফ একই ডেটাতে বিভিন্ন দর্শন। প্রথম গ্রাফে আমরা প্রতি ব্রাউজারের সাথে তুলনা করি, দ্বিতীয় গ্রাফে আমরা ব্যবহৃত ভাষার প্রতি তুলনা করি। দয়া করে মনে রাখবেন যে আমি একটি লোগারিদমিক টাইমস্কেল বেছে নিয়েছি। এটিও গুরুত্বপূর্ণ যে সমস্ত বেঞ্চমার্ক একই 16 মেগাপিক্সেল পরীক্ষার চিত্র এবং একই হোস্ট মেশিন ব্যবহার করছিল, একটি ব্রাউজার ব্যতীত, যা একই মেশিনে চালানো যায়নি।
এই গ্রাফগুলি খুব বেশি বিশ্লেষণ না করে, এটি স্পষ্ট যে আমরা আমাদের মূল পারফরম্যান্স সমস্যার সমাধান করেছি: সমস্ত ওয়েবসেমি মডিউলগুলি 500 মিমি বা তারও কম সময়ে চালিত হয়। এটি শুরুতে আমরা যা রেখেছি তা নিশ্চিত করে: ওয়েবসেম্বলিটি আপনাকে অনুমানযোগ্য পারফরম্যান্স দেয়। আমরা কোন ভাষাটি বেছে নিই না কেন, ব্রাউজার এবং ভাষার মধ্যে ভিন্নতা ন্যূনতম। হুবহু হতে: সমস্ত ব্রাউজার জুড়ে জাভাস্ক্রিপ্টের স্ট্যান্ডার্ড বিচ্যুতি ~ 400 মিমি, যখন সমস্ত ব্রাউজার জুড়ে আমাদের সমস্ত ওয়েবসাম্বলি মডিউলগুলির স্ট্যান্ডার্ড বিচ্যুতি ~ 80ms।
প্রচেষ্টা
আরেকটি মেট্রিক হ'ল আমাদের ওয়েবসেম্বলি মডিউলটি স্কুওশে তৈরি এবং সংহত করার জন্য আমাদের যে পরিমাণ প্রচেষ্টা রাখতে হয়েছিল। প্রচেষ্টার জন্য একটি সংখ্যাসূচক মান নির্ধারণ করা শক্ত, তাই আমি কোনও গ্রাফ তৈরি করব না তবে কয়েকটি জিনিস রয়েছে যা আমি উল্লেখ করতে চাই:
অ্যাসেমব্লিস্ক্রিপ্টটি ঘর্ষণহীন ছিল। এটি কেবল আপনাকে ওয়েবসেমি লিখতে টাইপস্ক্রিপ্ট ব্যবহার করার অনুমতি দেয় না, আমার সহকর্মীদের জন্য কোড-রিভিউকে খুব সহজ করে তোলে, তবে এটি আঠালো-মুক্ত ওয়েবসেম্বলি মডিউলগুলিও তৈরি করে যা শালীন পারফরম্যান্সের সাথে খুব ছোট। প্রিটিয়ার এবং টিএসলিন্টের মতো টাইপস্ক্রিপ্ট ইকোসিস্টেমের সরঞ্জামগুলি সম্ভবত কাজ করবে।
wasm-pack
সাথে সংমিশ্রণে মরিচাও অত্যন্ত সুবিধাজনক, তবে বড় ওয়েবসাম্বলি প্রকল্পগুলিতে আরও বেশি ছাড়িয়ে যাওয়া ছিল বাইন্ডিং এবং মেমরি ম্যানেজমেন্টের প্রয়োজন। প্রতিযোগিতামূলক ফাইলের আকার অর্জনের জন্য আমাদের সুখী-পথ থেকে কিছুটা বিচ্যুত করতে হয়েছিল।
সি এবং এমস্ক্রিপ্টেন বাক্সের বাইরে একটি খুব ছোট এবং অত্যন্ত পারফরম্যান্ট ওয়েবসেম্বলি মডিউল তৈরি করেছে, তবে আঠালো কোডে ঝাঁপিয়ে পড়ার সাহস ছাড়াই এবং এটিকে খালি প্রয়োজনীয় সামগ্রীতে হ্রাস করার মোট আকারের (ওয়েবসেম্বলি মডিউল + আঠালো কোড) বেশ বড় হয়ে শেষ হয়।
উপসংহার
সুতরাং আপনার যদি জেএস হট পাথ থাকে এবং এটি ওয়েবসেম্ব্লিউজের সাথে আরও দ্রুত বা আরও সামঞ্জস্যপূর্ণ করতে চান তবে আপনার কোন ভাষাটি ব্যবহার করা উচিত। পারফরম্যান্স প্রশ্নগুলির সাথে সর্বদা হিসাবে, উত্তরটি হ'ল: এটি নির্ভর করে। তাহলে আমরা কী শিপ করেছি?
আমরা যে বিভিন্ন ভাষার ব্যবহার করেছি তার মডিউল আকার / পারফরম্যান্স ট্রেড অফের সাথে তুলনা করা, সেরা পছন্দটি সি বা অ্যাসেমব্লিস্ক্রিপ্ট বলে মনে হয়। আমরা মরিচা চালানোর সিদ্ধান্ত নিয়েছি । এই সিদ্ধান্তের একাধিক কারণ রয়েছে: স্কুউশে প্রেরণ করা সমস্ত কোডেকগুলি এমএসক্রিপ্টেন ব্যবহার করে সংকলিত হয়েছে। আমরা ওয়েবসেম্বল ইকোসিস্টেম সম্পর্কে আমাদের জ্ঞানকে আরও প্রশস্ত করতে এবং উত্পাদনে একটি ভিন্ন ভাষা ব্যবহার করতে চেয়েছিলাম। অ্যাসেমব্লিস্ক্রিপ্ট একটি শক্তিশালী বিকল্প, তবে প্রকল্পটি তুলনামূলকভাবে তরুণ এবং সংকলকটি মরিচা সংকলক হিসাবে পরিপক্ক নয়।
যদিও মরিচা এবং অন্যান্য ভাষার আকারের মধ্যে ফাইলের আকারের পার্থক্যটি স্ক্যাটার গ্রাফে বেশ কঠোর দেখায়, এটি বাস্তবে এত বড় চুক্তি নয়: 500 বি বা 1.6 কেবি লোড করা এমনকি 2 জি -র চেয়েও সেকেন্ডের 1/10 এর চেয়ে কম সময় নেয়। এবং মরিচা আশাবাদী শীঘ্রই মডিউল আকারের দিক থেকে ফাঁকটি বন্ধ করে দেবে।
রানটাইম পারফরম্যান্সের ক্ষেত্রে, মরিচাগুলি অ্যাসেমব্লিস্ক্রিপ্টের চেয়ে ব্রাউজারগুলিতে দ্রুত গড় রয়েছে। বিশেষত বড় প্রকল্পগুলিতে মরিচা ম্যানুয়াল কোড অপ্টিমাইজেশনের প্রয়োজন ছাড়াই দ্রুত কোড উত্পাদন করার সম্ভাবনা বেশি। তবে এটি আপনাকে সবচেয়ে বেশি স্বাচ্ছন্দ্যযুক্ত যা ব্যবহার করা থেকে বিরত রাখা উচিত নয়।
সবই বলা হচ্ছে: অ্যাসেমব্লিস্ক্রিপ্ট একটি দুর্দান্ত আবিষ্কার হয়েছে। এটি ওয়েব বিকাশকারীদের কোনও নতুন ভাষা না শিখিয়ে ওয়েবসেম্বলি মডিউলগুলি উত্পাদন করতে দেয়। অ্যাসেমব্লিস্ক্রিপ্ট দলটি খুব প্রতিক্রিয়াশীল এবং তাদের সরঞ্জামচেন উন্নত করার জন্য সক্রিয়ভাবে কাজ করছে। আমরা অবশ্যই ভবিষ্যতে অ্যাসেমব্লিস্ক্রিপ্টে নজর রাখব।
আপডেট: মরিচা
এই নিবন্ধটি প্রকাশের পরে, মরিচা দল থেকে নিক ফিৎসগেরাল্ড আমাদের তাদের দুর্দান্ত মরিচা বর্জ্য বইয়ের দিকে ইঙ্গিত করেছেন, এতে ফাইলের আকার অনুকূলকরণের একটি বিভাগ রয়েছে। সেখানে নির্দেশাবলী অনুসরণ করে (সর্বাধিক উল্লেখযোগ্যভাবে লিঙ্ক টাইম অপ্টিমাইজেশন এবং ম্যানুয়াল প্যানিক হ্যান্ডলিং সক্ষম করা) আমাদের "সাধারণ" মরিচা কোড লিখতে এবং ফাইলের আকারটি ফুলে না ফেলে Cargo
(মরিচাটির npm
) ব্যবহার করতে ফিরে যেতে দেয়। মরিচা মডিউলটি জিজিআইপি -র পরে 370 বি দিয়ে শেষ হয়। বিশদগুলির জন্য, দয়া করে স্কুওশে আমি যে পিআরটি খুললাম তা একবার দেখুন।
এই যাত্রায় তাদের সমস্ত সহায়তার জন্য অ্যাশলে উইলিয়ামস , স্টিভ ক্লাবনিক , নিক ফিৎসগেরাল্ড এবং ম্যাক্স গ্রেয়কে বিশেষ ধন্যবাদ।
,এটি ধারাবাহিকভাবে দ্রুত, আপনি
আমার পূর্ববর্তী নিবন্ধগুলিতে আমি কীভাবে ওয়েবসেম্বলিটি আপনাকে সি/সি ++ এর লাইব্রেরি ইকোসিস্টেমটি ওয়েবে আনতে দেয় সে সম্পর্কে কথা বললাম। একটি অ্যাপ্লিকেশন যা সি/সি ++ লাইব্রেরির ব্যাপক ব্যবহার করে তা হ'ল স্কুওশ , আমাদের ওয়েব অ্যাপ্লিকেশন যা আপনাকে বিভিন্ন কোডেক দিয়ে চিত্রগুলি সংকুচিত করতে দেয় যা সি ++ থেকে ওয়েবসেম্ব্লাতে সংকলিত করা হয়েছে।
ওয়েবসেম্বলি হ'ল একটি নিম্ন-স্তরের ভার্চুয়াল মেশিন যা বাইটকোড চালায় যা .wasm
ফাইলগুলিতে সঞ্চিত থাকে। এই বাইট কোডটি দৃ strongly ়ভাবে টাইপ করা এবং এমনভাবে কাঠামোগত করা হয়েছে যাতে এটি জাভাস্ক্রিপ্টের চেয়ে আরও দ্রুত হোস্ট সিস্টেমের জন্য সংকলিত এবং অনুকূলিত করা যায়। ওয়েবসেম্বলি এমন কোড চালানোর জন্য একটি পরিবেশ সরবরাহ করে যা খুব শুরু থেকেই স্যান্ডবক্সিং এবং এম্বেড করে থাকে।
আমার অভিজ্ঞতায়, ওয়েবে বেশিরভাগ পারফরম্যান্স সমস্যাগুলি জোর করে লেআউট এবং অতিরিক্ত পেইন্টের কারণে ঘটে তবে প্রতিটি এখন এবং পরে একটি অ্যাপ্লিকেশনকে একটি গণনামূলক ব্যয়বহুল টাস্ক করা দরকার যা অনেক সময় নেয়। ওয়েবসেম্বলি এখানে সহায়তা করতে পারে।
গরম পথ
স্কুওশে আমরা একটি জাভাস্ক্রিপ্ট ফাংশন লিখেছিলাম যা 90 ডিগ্রি গুণিত করে একটি চিত্র বাফারকে ঘোরান। যদিও অফস্ক্রিনাকানভাস এটির জন্য আদর্শ হবে, তবে এটি আমরা যে ব্রাউজারগুলি লক্ষ্য করছিলাম সেগুলি জুড়ে সমর্থন করা হয় না এবং ক্রোমে কিছুটা বগি ।
এই ফাংশনটি একটি ইনপুট চিত্রের প্রতিটি পিক্সেলের উপরে পুনরাবৃত্তি করে এবং ঘূর্ণন অর্জনের জন্য এটি আউটপুট চিত্রের একটি পৃথক অবস্থানে অনুলিপি করে। 4096px দ্বারা 4094px এর জন্য (16 মেগাপিক্সেল) এর জন্য এটি অভ্যন্তরীণ কোড ব্লকের 16 মিলিয়নেরও বেশি পুনরাবৃত্তি প্রয়োজন, যা আমরা "হট পাথ" বলি। এর পরিবর্তে বড় সংখ্যক পুনরাবৃত্তি সত্ত্বেও, আমরা পরীক্ষা করা তিনটি ব্রাউজারের মধ্যে দুটি 2 সেকেন্ড বা তারও কম সময়ে কাজটি শেষ করে। এই ধরণের মিথস্ক্রিয়াটির জন্য একটি গ্রহণযোগ্য সময়কাল।
for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
const in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
outBuffer[i] = inBuffer[in_idx];
i += 1;
}
}
একটি ব্রাউজারটি অবশ্য 8 সেকেন্ডেরও বেশি সময় নেয়। জাভাস্ক্রিপ্টটি যেভাবে ব্রাউজারগুলি অনুকূলিত করে তা সত্যই জটিল এবং বিভিন্ন ইঞ্জিন বিভিন্ন জিনিসের জন্য অনুকূলিত করে। কিছু কাঁচা মৃত্যুদন্ডের জন্য অনুকূলিত করে, কিছু ডোমের সাথে মিথস্ক্রিয়াটির জন্য অনুকূলিত করে। এই ক্ষেত্রে, আমরা একটি ব্রাউজারে একটি অপ্রচলিত পথে আঘাত করেছি।
অন্যদিকে ওয়েবসেম্বলিটি পুরোপুরি কাঁচা এক্সিকিউশন গতির চারপাশে নির্মিত। সুতরাং আমরা যদি এই জাতীয় কোডের জন্য ব্রাউজারগুলিতে দ্রুত, অনুমানযোগ্য পারফরম্যান্স চাই তবে ওয়েবসেম্বলিটি সহায়তা করতে পারে।
অনুমানযোগ্য পারফরম্যান্সের জন্য ওয়েবসেম্বলি
সাধারণভাবে, জাভাস্ক্রিপ্ট এবং ওয়েবসেম্বলি একই শিখর কর্মক্ষমতা অর্জন করতে পারে। তবে, জাভাস্ক্রিপ্টের জন্য এই পারফরম্যান্সটি কেবল "দ্রুত পথ" এ পৌঁছাতে পারে এবং সেই "দ্রুত পথে" থাকা প্রায়শই জটিল। একটি মূল সুবিধা যা ওয়েবসেম্বলি অফার করে তা হ'ল ব্রাউজার জুড়েও অনুমানযোগ্য পারফরম্যান্স। কঠোর টাইপিং এবং নিম্ন-স্তরের আর্কিটেকচার সংকলকটিকে শক্তিশালী গ্যারান্টি তৈরি করতে দেয় যাতে ওয়েবসেমি কোডটি কেবল একবারে অনুকূলিত করতে হয় এবং সর্বদা "দ্রুত পথ" ব্যবহার করে।
ওয়েবসেম্বলির জন্য লেখা
পূর্বে আমরা সি/সি ++ লাইব্রেরি নিয়েছিলাম এবং ওয়েবে তাদের কার্যকারিতাটি ব্যবহার করতে তাদের ওয়েবসেম্বিতে সংকলন করেছি। আমরা সত্যিই লাইব্রেরির কোডটি স্পর্শ করি নি, আমরা ব্রাউজার এবং লাইব্রেরির মধ্যে সেতু গঠনের জন্য স্বল্প পরিমাণে সি/সি ++ কোড লিখেছি। এবার আমাদের অনুপ্রেরণাটি আলাদা: আমরা ওয়েবসেম্বলিটি মাথায় রেখে স্ক্র্যাচ থেকে কিছু লিখতে চাই যাতে আমরা ওয়েবসেম্বলির যে সুবিধাগুলি ব্যবহার করতে পারি তা ব্যবহার করতে পারি।
ওয়েবসেম্বলি আর্কিটেকচার
ওয়েবসেম্বলির জন্য লেখার সময়, ওয়েবসেম্বলিটি আসলে কী তা সম্পর্কে আরও কিছুটা বোঝা উপকারী।
Webassembly.org উদ্ধৃত করতে:
আপনি যখন ওয়েবসেম্ব্লাতে সি বা মরিচা কোডের একটি টুকরো সংকলন করেন, আপনি একটি .wasm
ফাইল পাবেন যাতে একটি মডিউল ঘোষণা থাকে। এই ঘোষণায় মডিউলটি তার পরিবেশ থেকে প্রত্যাশা করে "আমদানি" এর একটি তালিকা রয়েছে, এই মডিউলটি হোস্টের (ফাংশন, ধ্রুবক, মেমরির খণ্ডগুলি) এবং অবশ্যই এর মধ্যে থাকা ফাংশনগুলির জন্য প্রকৃত বাইনারি নির্দেশাবলীর জন্য উপলব্ধ করে এমন রফতানির একটি তালিকা রয়েছে .
এমন কিছু যা আমি বুঝতে পারি নি যতক্ষণ না আমি এটি সন্ধান করি না: যে স্ট্যাকটি ওয়েবসেম্বলিকে একটি "স্ট্যাক-ভিত্তিক ভার্চুয়াল মেশিন" করে তোলে তা মেমরির অংশে সংরক্ষণ করা হয় না যা ওয়েবসেমি মডিউলগুলি ব্যবহার করে। স্ট্যাকটি সম্পূর্ণ ভিএম-অভ্যন্তরীণ এবং ওয়েব বিকাশকারীদের কাছে অ্যাক্সেসযোগ্য (ডেভটুলগুলি বাদে)। যেমনটি ওয়েবসেম্বলি মডিউলগুলি লিখতে পারে যা কোনও অতিরিক্ত মেমরির প্রয়োজন হয় না এবং কেবল ভিএম-অভ্যন্তরীণ স্ট্যাক ব্যবহার করে।
আমাদের ক্ষেত্রে আমাদের চিত্রের পিক্সেলগুলিতে স্বেচ্ছাসেবী অ্যাক্সেসের অনুমতি দিতে এবং সেই চিত্রের একটি ঘোরানো সংস্করণ তৈরি করতে আমাদের কিছু অতিরিক্ত মেমরি ব্যবহার করতে হবে। এটিই WebAssembly.Memory
এর জন্য।
মেমরি ব্যবস্থাপনা
সাধারণত, একবার আপনি অতিরিক্ত মেমরি ব্যবহার করার পরে আপনি কোনওভাবে সেই মেমরিটি পরিচালনা করার প্রয়োজনীয়তা পাবেন। স্মৃতির কোন অংশগুলি ব্যবহৃত হয়? কোনটি বিনামূল্যে? সি তে, উদাহরণস্বরূপ, আপনার কাছে malloc(n)
ফাংশন রয়েছে যা ধারাবাহিক n
মেমরির স্থান খুঁজে পায়। এই ধরণের ফাংশনগুলিকে "বরাদ্দকারী" ও বলা হয়। অবশ্যই ব্যবহৃত বরাদ্দকারী বাস্তবায়ন অবশ্যই আপনার ওয়েবসেম্বলি মডিউলটিতে অন্তর্ভুক্ত থাকতে হবে এবং আপনার ফাইলের আকার বাড়িয়ে তুলবে। এই মেমরি ম্যানেজমেন্ট ফাংশনগুলির এই আকার এবং পারফরম্যান্স ব্যবহৃত অ্যালগরিদমের উপর নির্ভর করে বেশ উল্লেখযোগ্যভাবে পরিবর্তিত হতে পারে, এ কারণেই অনেক ভাষা ("ডেমালোক", "এম্মলোক", "ওয়ে_লোক" ইত্যাদি) থেকে বেছে নেওয়ার জন্য একাধিক বাস্তবায়ন সরবরাহ করে।
আমাদের ক্ষেত্রে আমরা ওয়েবসেম্বলি মডিউলটি চালানোর আগে ইনপুট চিত্রের মাত্রাগুলি (এবং তাই আউটপুট চিত্রের মাত্রা) জানি। এখানে আমরা একটি সুযোগ দেখেছি: tradition তিহ্যগতভাবে, আমরা ইনপুট চিত্রের আরজিবিএ বাফারটিকে একটি ওয়েবসেম্বল ফাংশনের প্যারামিটার হিসাবে পাস করব এবং ঘোরানো চিত্রটিকে রিটার্ন মান হিসাবে ফিরিয়ে দেব। সেই রিটার্ন মানটি তৈরি করতে আমাদের বরাদ্দকারীকে ব্যবহার করতে হবে। তবে যেহেতু আমরা প্রয়োজনীয় মেমরির মোট পরিমাণ (ইনপুট চিত্রের দ্বিগুণ, একবার ইনপুটটির জন্য এবং একবার আউটপুটের জন্য) জানি, তাই আমরা জাভাস্ক্রিপ্ট ব্যবহার করে ওয়েবসেম্বলি মেমরির মধ্যে ইনপুট চিত্রটি রাখতে পারি, একটি 2 য় উত্পন্ন করতে ওয়েবসেম্বলি মডিউলটি চালান, ঘোরানো চিত্র এবং তারপরে ফলাফলটি পড়তে জাভাস্ক্রিপ্ট ব্যবহার করুন। আমরা কোনও মেমরি ম্যানেজমেন্ট ব্যবহার না করেই পালাতে পারি!
পছন্দের জন্য নষ্ট হয়ে গেছে
আপনি যদি মূল জাভাস্ক্রিপ্ট ফাংশনটি দেখেন যা আমরা ওয়েবসেম্বলি-ফাই করতে চাই তবে আপনি দেখতে পাচ্ছেন যে এটি কোনও জাভাস্ক্রিপ্ট-নির্দিষ্ট এপিআই ছাড়াই একটি খাঁটি কম্পিউটেশনাল কোড। যেমন এটি কোনও ভাষায় এই কোডটি পোর্ট করার জন্য মোটামুটি সোজা এগিয়ে থাকা উচিত। আমরা 3 টি বিভিন্ন ভাষা মূল্যায়ন করেছি যা ওয়েবসেম্ব্লিউজে সংকলন করে: সি/সি ++, মরিচা এবং অ্যাসেমব্লিস্ক্রিপ্ট। প্রতিটি ভাষার জন্য আমাদের উত্তর দেওয়ার একমাত্র প্রশ্নের হ'ল: মেমরি ম্যানেজমেন্ট ফাংশনগুলি ব্যবহার না করে আমরা কীভাবে কাঁচা মেমরি অ্যাক্সেস করব?
সি এবং এমস্ক্রিপ্টেন
এমস্ক্রিপ্টেন ওয়েবসেম্বলি টার্গেটের জন্য একটি সি সংকলক। এমস্ক্রিপ্টের লক্ষ্য হ'ল জিসিসি বা ক্ল্যাংয়ের মতো সুপরিচিত সি সংকলকগুলির জন্য ড্রপ-ইন প্রতিস্থাপন হিসাবে কাজ করা এবং বেশিরভাগ পতাকা সামঞ্জস্যপূর্ণ। এটি এমস্ক্রিপ্টের মিশনের একটি মূল অংশ কারণ এটি বিদ্যমান সি এবং সি ++ কোডটি যতটা সম্ভব সহজে ওয়েবসেম্ব্লে সংকলন করতে চায়।
কাঁচা মেমরি অ্যাক্সেস সি এর প্রকৃতিতে রয়েছে এবং পয়েন্টারগুলি সেই কারণেই বিদ্যমান:
uint8_t* ptr = (uint8_t*)0x124;
ptr[0] = 0xFF;
এখানে আমরা 0x124
নম্বরটি স্বাক্ষরবিহীন, 8-বিট পূর্ণসংখ্যার (বা বাইটস) এ একটি পয়েন্টারে পরিণত করছি। এটি কার্যকরভাবে ptr
ভেরিয়েবলটিকে মেমরি ঠিকানা 0x124
থেকে শুরু করে একটি অ্যারেতে রূপান্তরিত করে, যা আমরা অন্য কোনও অ্যারের মতো ব্যবহার করতে পারি, যা আমাদের পড়া এবং লেখার জন্য পৃথক বাইট অ্যাক্সেস করতে দেয়। আমাদের ক্ষেত্রে আমরা এমন একটি চিত্রের একটি আরজিবিএ বাফারের দিকে তাকিয়ে আছি যা আমরা ঘূর্ণন অর্জনের জন্য পুনরায় অর্ডার করতে চাই। একটি পিক্সেল সরানোর জন্য আমাদের আসলে একবারে টানা 4 টি বাইট স্থানান্তর করতে হবে (প্রতিটি চ্যানেলের জন্য একটি বাইট: আর, জি, বি এবং এ)। এটিকে আরও সহজ করার জন্য আমরা স্বাক্ষরবিহীন, 32-বিট পূর্ণসংখ্যার একটি অ্যারে তৈরি করতে পারি। কনভেনশন দ্বারা, আমাদের ইনপুট চিত্রটি ঠিকানা 4 এ শুরু হবে এবং ইনপুট চিত্রটি শেষ হওয়ার পরে আমাদের আউটপুট চিত্রটি সরাসরি শুরু হবে:
int bpp = 4;
int imageSize = inputWidth * inputHeight * bpp;
uint32_t* inBuffer = (uint32_t*) 4;
uint32_t* outBuffer = (uint32_t*) (inBuffer + imageSize);
for (int d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (int d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
int in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
outBuffer[i] = inBuffer[in_idx];
i += 1;
}
}
পুরো জাভাস্ক্রিপ্ট ফাংশনটি সি -তে পোর্ট করার পরে, আমরা emcc
সাথে সি ফাইলটি সংকলন করতে পারি:
$ emcc -O3 -s ALLOW_MEMORY_GROWTH=1 -o c.js rotate.c
সর্বদা হিসাবে, এমস্ক্রিপ্টেন c.js
নামে একটি আঠালো কোড ফাইল এবং c.wasm
নামে একটি ডাব্লুএএসএম মডিউল তৈরি করে। নোট করুন যে ওয়াসম মডিউলটি কেবল ~ 260 বাইটে জিজিপস, যখন আঠালো কোডটি জিজিআইপি -র পরে প্রায় 3.5 কেবি। কিছুটা ফিডিংয়ের পরে, আমরা আঠালো কোডটি খনন করতে এবং ভ্যানিলা এপিআইগুলির সাথে ওয়েবসেম্বলি মডিউলগুলি ইনস্ট্যান্ট করতে সক্ষম হয়েছি। যতক্ষণ না আপনি সি স্ট্যান্ডার্ড লাইব্রেরি থেকে কিছু ব্যবহার করছেন না ততক্ষণ এমস্ক্রিপ্টেন দিয়ে এটি প্রায়শই সম্ভব।
মরিচা
মরিচা একটি নতুন, আধুনিক প্রোগ্রামিং ভাষা যা একটি সমৃদ্ধ টাইপ সিস্টেম সহ, কোনও রানটাইম এবং কোনও মালিকানা মডেল যা মেমরি-সুরক্ষা এবং থ্রেড-সুরক্ষার গ্যারান্টি দেয়। মরিচাও একটি মূল বৈশিষ্ট্য হিসাবে ওয়েবসেম্বলিকে সমর্থন করে এবং মরিচা দলটি ওয়েবসেম্বল ইকোসিস্টেমটিতে প্রচুর দুর্দান্ত সরঞ্জামকে অবদান রেখেছে।
এই সরঞ্জামগুলির মধ্যে একটি হ'ল রুস্টওয়াসম ওয়ার্কিং গ্রুপের wasm-pack
। wasm-pack
আপনার কোড নেয় এবং এটিকে একটি ওয়েব-বান্ধব মডিউলে পরিণত করে যা ওয়েবপ্যাকের মতো বান্ডলারগুলির সাথে বাক্সের বাইরে কাজ করে। wasm-pack
একটি অত্যন্ত সুবিধাজনক অভিজ্ঞতা, তবে বর্তমানে কেবল মরিচা জন্য কাজ করে। গোষ্ঠীটি অন্যান্য ওয়েবসেমি-টার্গেটিং ভাষার জন্য সমর্থন যুক্ত করার বিষয়ে বিবেচনা করছে।
মরিচাগুলিতে, স্লাইসগুলি সি -তে অ্যারেগুলি কী এবং ঠিক সি এর মতো, আমাদের এমন স্লাইস তৈরি করতে হবে যা আমাদের শুরু ঠিকানাগুলি ব্যবহার করে। এটি মেমরি সুরক্ষা মডেলের বিরুদ্ধে যায় যা মরিচা প্রয়োগ করে, তাই আমাদের পথটি পেতে আমাদের unsafe
কীওয়ার্ডটি ব্যবহার করতে হবে, আমাদের সেই মডেলটি লিখতে দেয় যা সেই মডেলটির সাথে মেনে চলে না।
let imageSize = (inputWidth * inputHeight) as usize;
let inBuffer: &mut [u32];
let outBuffer: &mut [u32];
unsafe {
inBuffer = slice::from_raw_parts_mut::<u32>(4 as *mut u32, imageSize);
outBuffer = slice::from_raw_parts_mut::<u32>((imageSize * 4 + 4) as *mut u32, imageSize);
}
for d2 in 0..d2Limit {
for d1 in 0..d1Limit {
let in_idx = (d1Start + d1 * d1Advance) * d1Multiplier + (d2Start + d2 * d2Advance) * d2Multiplier;
outBuffer[i as usize] = inBuffer[in_idx as usize];
i += 1;
}
}
ব্যবহার করে মরিচা ফাইল সংকলন
$ wasm-pack build
প্রায় 100 বাইট আঠালো কোড (জিজেডআইপি পরে উভয়) সহ একটি 7.6 কেবি ওয়াসম মডিউল দেয়।
অ্যাসেমব্লিস্ক্রিপ্ট
অ্যাসেমব্লিস্ক্রিপ্ট একটি মোটামুটি তরুণ প্রকল্প যা লক্ষ্য করে একটি টাইপস্ক্রিপ্ট-টু-ওয়েবসেম্পল সংকলক হতে। তবে এটি লক্ষণীয় গুরুত্বপূর্ণ যে এটি কেবল কোনও টাইপস্ক্রিপ্ট গ্রাস করবে না। অ্যাসেমব্লিস্ক্রিপ্ট টাইপস্ক্রিপ্ট হিসাবে একই সিনট্যাক্স ব্যবহার করে তবে তাদের নিজস্ব জন্য স্ট্যান্ডার্ড লাইব্রেরিটি স্যুইচ আউট করে। তাদের স্ট্যান্ডার্ড লাইব্রেরি ওয়েবসেম্বলির সক্ষমতা মডেল করে। এর অর্থ আপনি কেবল ওয়েবসেম্বলিতে পড়ে থাকা কোনও টাইপস্ক্রিপ্ট সংকলন করতে পারবেন না, তবে এর অর্থ এই যে ওয়েবসেমি লিখতে আপনাকে কোনও নতুন প্রোগ্রামিং ভাষা শিখতে হবে না!
for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
let in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
store<u32>(offset + i * 4 + 4, load<u32>(in_idx * 4 + 4));
i += 1;
}
}
আমাদের rotate()
ফাংশনটি যে ছোট ধরণের পৃষ্ঠটি রয়েছে তা বিবেচনা করে, এই কোডটি এসেম্বলিস্ক্রিপ্টে পোর্ট করা মোটামুটি সহজ ছিল। ফাংশনগুলি load<T>(ptr: usize)
এবং store<T>(ptr: usize, value: T)
কাঁচা মেমরি অ্যাক্সেসের জন্য অ্যাসেমব্লিস্ক্রিপ্ট দ্বারা সরবরাহ করা হয়। আমাদের অ্যাসেমব্লিস্ক্রিপ্ট ফাইলটি সংকলন করতে, আমাদের কেবল AssemblyScript/assemblyscript
এনপিএম প্যাকেজ ইনস্টল করতে হবে এবং চালাতে হবে
$ asc rotate.ts -b assemblyscript.wasm --validate -O3
অ্যাসেমব্লিস্ক্রিপ্ট আমাদের একটি ~ 300 বাইট ওয়াসম মডিউল এবং কোনও আঠালো কোড সরবরাহ করবে। মডিউলটি কেবল ভ্যানিলা ওয়েবসেম্বলি এপিআইগুলির সাথে কাজ করে।
ওয়েবসেম্বলি ফরেনসিক
অন্য 2 টি ভাষার সাথে তুলনা করার সময় রাস্টের 7.6 কেবি আশ্চর্যজনকভাবে বড়। ওয়েবসেম্বল ইকোসিস্টেমে বেশ কয়েকটি সরঞ্জাম রয়েছে যা আপনাকে আপনার ওয়েবসেম্বল ফাইলগুলি বিশ্লেষণ করতে সহায়তা করতে পারে (যে ভাষাটি তৈরি করা হয়েছে তা নির্বিশেষে) এবং আপনাকে কী চলছে তা বলতে এবং আপনার পরিস্থিতি উন্নত করতে আপনাকে সহায়তা করতে পারে।
টুইগি
টুইগি হ'ল রাস্টের ওয়েবসেম্বলি টিমের আরেকটি সরঞ্জাম যা একটি ওয়েবসাম্বলি মডিউল থেকে একগুচ্ছ অন্তর্দৃষ্টিপূর্ণ ডেটা বের করে। সরঞ্জামটি মরিচা-নির্দিষ্ট নয় এবং আপনাকে মডিউলটির কল গ্রাফের মতো জিনিসগুলি পরিদর্শন করতে, অব্যবহৃত বা অতিমাত্রায় বিভাগগুলি নির্ধারণ করতে এবং কোন বিভাগগুলি আপনার মডিউলটির মোট ফাইল আকারে অবদান রাখছে তা নির্ধারণ করতে দেয়। দ্বিতীয়টি টুইগির top
কমান্ড দিয়ে করা যেতে পারে:
$ twiggy top rotate_bg.wasm
এই ক্ষেত্রে আমরা দেখতে পাচ্ছি যে আমাদের ফাইলের আকারের বেশিরভাগ অংশ বরাদ্দকারী থেকে আসে। এটি অবাক করার মতো ছিল যেহেতু আমাদের কোডটি গতিশীল বরাদ্দ ব্যবহার করছে না। আর একটি বড় অবদানকারী ফ্যাক্টর হ'ল একটি "ফাংশন নাম" উপ -ধারা।
ওয়াসম-স্ট্রিপ
wasm-strip
হ'ল ওয়েবসেম্বলি বাইনারি টুলকিট বা সংক্ষেপে WABT এর একটি সরঞ্জাম। এটিতে বেশ কয়েকটি সরঞ্জাম রয়েছে যা আপনাকে ওয়েবসেম্বলি মডিউলগুলি পরিদর্শন ও পরিচালনা করতে দেয়। wasm2wat
হ'ল একটি বিচ্ছেদ যা একটি বাইনারি ওয়াসম মডিউলটিকে একটি মানব-পঠনযোগ্য ফর্ম্যাটে পরিণত করে। WABT এ wat2wasm
রয়েছে যা আপনাকে সেই মানব-পঠনযোগ্য ফর্ম্যাটটিকে বাইনারি ওয়াসম মডিউলে ফিরিয়ে আনতে দেয়। যদিও আমরা আমাদের ওয়েবসেম্বলি ফাইলগুলি পরিদর্শন করতে এই দুটি পরিপূরক সরঞ্জাম ব্যবহার করেছি, আমরা wasm-strip
সবচেয়ে কার্যকর বলে মনে করেছি। wasm-strip
অপ্রয়োজনীয় বিভাগগুলি এবং মেটাডেটা একটি ওয়েবসেম্বল মডিউল থেকে সরিয়ে দেয়:
$ wasm-strip rotate_bg.wasm
এটি মরিচা মডিউলটির ফাইলের আকার 7.5 কেবি থেকে 6.6 কেবি (জিজেডিপের পরে) হ্রাস করে।
ওয়াসম-অপ্ট
wasm-opt
বাইনারেনের একটি সরঞ্জাম। এটি একটি ওয়েবসেম্বলি মডিউল নেয় এবং এটি কেবল বাইটকোডের উপর ভিত্তি করে আকার এবং পারফরম্যান্স উভয়ের জন্য এটি অনুকূল করার চেষ্টা করে। এমস্ক্রিপ্টেনের মতো কিছু সরঞ্জাম ইতিমধ্যে এই সরঞ্জামটি চালায়, অন্য কেউ কেউ তা করেন না। এই সরঞ্জামগুলি ব্যবহার করে কিছু অতিরিক্ত বাইট চেষ্টা করা এবং সংরক্ষণ করা সাধারণত একটি ভাল ধারণা।
wasm-opt -O3 -o rotate_bg_opt.wasm rotate_bg.wasm
wasm-opt
সহ আমরা জিজিপির পরে মোট 6.2 কেবি ছাড়তে আরও একটি মুঠো বাইট শেভ করতে পারি।
#! [no_std]
কিছু পরামর্শ এবং গবেষণার পরে, আমরা #![no_std]
বৈশিষ্ট্যটি ব্যবহার করে রাস্টের স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার না করেই আমাদের মরিচা কোডটি পুনরায় লিখেছি। এটি আমাদের মডিউল থেকে বরাদ্দকারী কোডটি সরিয়ে পুরোপুরি গতিশীল মেমরি বরাদ্দকে অক্ষম করে। এই মরিচা ফাইল সংকলন
$ rustc --target=wasm32-unknown-unknown -C opt-level=3 -o rust.wasm rotate.rs
wasm-opt
, wasm-strip
এবং জিজিপিপের পরে একটি 1.6 কেবি ওয়াসম মডিউল পেয়েছে। যদিও এটি এখনও সি এবং অ্যাসেমব্লিস্ক্রিপ্ট দ্বারা উত্পাদিত মডিউলগুলির চেয়ে বড়, তবে এটি হালকা ওজনের হিসাবে বিবেচিত হওয়ার পক্ষে যথেষ্ট ছোট।
কর্মক্ষমতা
আমরা একা ফাইলের আকারের উপর ভিত্তি করে সিদ্ধান্তে ঝাঁপ দেওয়ার আগে - আমরা ফাইলের আকার নয়, পারফরম্যান্সের অনুকূলকরণের জন্য এই যাত্রায় গিয়েছিলাম। তাহলে আমরা কীভাবে পারফরম্যান্স পরিমাপ করেছি এবং ফলাফলগুলি কী ছিল?
বেঞ্চমার্ক কিভাবে
ওয়েবসেম্বলিটি একটি নিম্ন-স্তরের বাইটকোড ফর্ম্যাট হওয়া সত্ত্বেও, হোস্ট-নির্দিষ্ট মেশিন কোড উত্পন্ন করতে এটি একটি সংকলকের মাধ্যমে প্রেরণ করা দরকার। জাভাস্ক্রিপ্টের মতোই সংকলক একাধিক পর্যায়ে কাজ করে। সহজভাবে বলেছিলেন: প্রথম পর্যায়ে সংকলনে অনেক দ্রুত তবে ধীর কোড উত্পন্ন করতে ঝোঁক। মডিউলটি চলতে শুরু করার পরে, ব্রাউজারটি পর্যবেক্ষণ করে যে কোন অংশগুলি ঘন ঘন ব্যবহৃত হয় এবং সেগুলি আরও অনুকূল তবে ধীর সংকলকের মাধ্যমে প্রেরণ করে।
আমাদের ব্যবহার-কেসটি আকর্ষণীয় যে কোনও চিত্র ঘোরানোর কোডটি একবার ব্যবহার করা হবে, সম্ভবত দু'বার ব্যবহার করা হবে। সুতরাং বেশিরভাগ ক্ষেত্রে আমরা কখনই অপ্টিমাইজিং সংকলকের সুবিধাগুলি পাব না। বেঞ্চমার্কিং করার সময় এটি মনে রাখা গুরুত্বপূর্ণ। একটি লুপে 10,000 বার আমাদের ওয়েবসেম্বলি মডিউলগুলি চালানো অবাস্তব ফলাফল দেয়। বাস্তবসম্মত সংখ্যা পেতে, আমাদের একবার মডিউলটি চালানো উচিত এবং সেই একক রান থেকে সংখ্যার ভিত্তিতে সিদ্ধান্ত নেওয়া উচিত।
কর্মক্ষমতা তুলনা
এই দুটি গ্রাফ একই ডেটাতে বিভিন্ন দর্শন। প্রথম গ্রাফে আমরা প্রতি ব্রাউজারের সাথে তুলনা করি, দ্বিতীয় গ্রাফে আমরা ব্যবহৃত ভাষার প্রতি তুলনা করি। দয়া করে মনে রাখবেন যে আমি একটি লোগারিদমিক টাইমস্কেল বেছে নিয়েছি। এটিও গুরুত্বপূর্ণ যে সমস্ত বেঞ্চমার্ক একই 16 মেগাপিক্সেল পরীক্ষার চিত্র এবং একই হোস্ট মেশিন ব্যবহার করছিল, একটি ব্রাউজার ব্যতীত, যা একই মেশিনে চালানো যায়নি।
এই গ্রাফগুলি খুব বেশি বিশ্লেষণ না করে, এটি স্পষ্ট যে আমরা আমাদের মূল পারফরম্যান্স সমস্যার সমাধান করেছি: সমস্ত ওয়েবসেমি মডিউলগুলি 500 মিমি বা তারও কম সময়ে চালিত হয়। এটি শুরুতে আমরা যা রেখেছি তা নিশ্চিত করে: ওয়েবসেম্বলিটি আপনাকে অনুমানযোগ্য পারফরম্যান্স দেয়। আমরা কোন ভাষাটি বেছে নিই না কেন, ব্রাউজার এবং ভাষার মধ্যে ভিন্নতা ন্যূনতম। হুবহু হতে: সমস্ত ব্রাউজার জুড়ে জাভাস্ক্রিপ্টের স্ট্যান্ডার্ড বিচ্যুতি ~ 400 মিমি, যখন সমস্ত ব্রাউজার জুড়ে আমাদের সমস্ত ওয়েবসাম্বলি মডিউলগুলির স্ট্যান্ডার্ড বিচ্যুতি ~ 80ms।
প্রচেষ্টা
আরেকটি মেট্রিক হ'ল আমাদের ওয়েবসেম্বলি মডিউলটি স্কুওশে তৈরি এবং সংহত করার জন্য আমাদের যে পরিমাণ প্রচেষ্টা রাখতে হয়েছিল। প্রচেষ্টার জন্য একটি সংখ্যাসূচক মান নির্ধারণ করা শক্ত, তাই আমি কোনও গ্রাফ তৈরি করব না তবে কয়েকটি জিনিস রয়েছে যা আমি উল্লেখ করতে চাই:
অ্যাসেমব্লিস্ক্রিপ্টটি ঘর্ষণহীন ছিল। এটি কেবল আপনাকে ওয়েবসেমি লিখতে টাইপস্ক্রিপ্ট ব্যবহার করার অনুমতি দেয় না, আমার সহকর্মীদের জন্য কোড-রিভিউকে খুব সহজ করে তোলে, তবে এটি আঠালো-মুক্ত ওয়েবসেম্বলি মডিউলগুলিও তৈরি করে যা শালীন পারফরম্যান্সের সাথে খুব ছোট। প্রিটিয়ার এবং টিএসলিন্টের মতো টাইপস্ক্রিপ্ট ইকোসিস্টেমের সরঞ্জামগুলি সম্ভবত কাজ করবে।
wasm-pack
সাথে সংমিশ্রণে মরিচাও অত্যন্ত সুবিধাজনক, তবে বড় ওয়েবসাম্বলি প্রকল্পগুলিতে আরও বেশি ছাড়িয়ে যাওয়া ছিল বাইন্ডিং এবং মেমরি ম্যানেজমেন্টের প্রয়োজন। প্রতিযোগিতামূলক ফাইলের আকার অর্জনের জন্য আমাদের সুখী-পথ থেকে কিছুটা বিচ্যুত করতে হয়েছিল।
সি এবং এমস্ক্রিপ্টেন বাক্সের বাইরে একটি খুব ছোট এবং অত্যন্ত পারফরম্যান্ট ওয়েবসেম্বলি মডিউল তৈরি করেছে, তবে আঠালো কোডে ঝাঁপিয়ে পড়ার সাহস ছাড়াই এবং এটিকে খালি প্রয়োজনীয় সামগ্রীতে হ্রাস করার মোট আকারের (ওয়েবসেম্বলি মডিউল + আঠালো কোড) বেশ বড় হয়ে শেষ হয়।
উপসংহার
সুতরাং আপনার যদি জেএস হট পাথ থাকে এবং এটি ওয়েবসেম্ব্লিউজের সাথে আরও দ্রুত বা আরও সামঞ্জস্যপূর্ণ করতে চান তবে আপনার কোন ভাষাটি ব্যবহার করা উচিত। পারফরম্যান্স প্রশ্নগুলির সাথে সর্বদা হিসাবে, উত্তরটি হ'ল: এটি নির্ভর করে। তাহলে আমরা কী শিপ করেছি?
আমরা যে বিভিন্ন ভাষার ব্যবহার করেছি তার মডিউল আকার / পারফরম্যান্স ট্রেড অফের সাথে তুলনা করা, সেরা পছন্দটি সি বা অ্যাসেমব্লিস্ক্রিপ্ট বলে মনে হয়। আমরা মরিচা চালানোর সিদ্ধান্ত নিয়েছি । এই সিদ্ধান্তের একাধিক কারণ রয়েছে: স্কুউশে প্রেরণ করা সমস্ত কোডেকগুলি এমএসক্রিপ্টেন ব্যবহার করে সংকলিত হয়েছে। আমরা ওয়েবসেম্বল ইকোসিস্টেম সম্পর্কে আমাদের জ্ঞানকে আরও প্রশস্ত করতে এবং উত্পাদনে একটি ভিন্ন ভাষা ব্যবহার করতে চেয়েছিলাম। অ্যাসেমব্লিস্ক্রিপ্ট একটি শক্তিশালী বিকল্প, তবে প্রকল্পটি তুলনামূলকভাবে তরুণ এবং সংকলকটি মরিচা সংকলক হিসাবে পরিপক্ক নয়।
যদিও মরিচা এবং অন্যান্য ভাষার আকারের মধ্যে ফাইলের আকারের পার্থক্যটি স্ক্যাটার গ্রাফে বেশ কঠোর দেখায়, এটি বাস্তবে এত বড় চুক্তি নয়: 500 বি বা 1.6 কেবি লোড করা এমনকি 2 জি -র চেয়েও সেকেন্ডের 1/10 এর চেয়ে কম সময় নেয়। এবং মরিচা আশাবাদী শীঘ্রই মডিউল আকারের দিক থেকে ফাঁকটি বন্ধ করে দেবে।
রানটাইম পারফরম্যান্সের ক্ষেত্রে, মরিচাগুলি অ্যাসেমব্লিস্ক্রিপ্টের চেয়ে ব্রাউজারগুলিতে দ্রুত গড় রয়েছে। বিশেষত বড় প্রকল্পগুলিতে মরিচা ম্যানুয়াল কোড অপ্টিমাইজেশনের প্রয়োজন ছাড়াই দ্রুত কোড উত্পাদন করার সম্ভাবনা বেশি। তবে এটি আপনাকে সবচেয়ে বেশি স্বাচ্ছন্দ্যযুক্ত যা ব্যবহার করা থেকে বিরত রাখা উচিত নয়।
সবই বলা হচ্ছে: অ্যাসেমব্লিস্ক্রিপ্ট একটি দুর্দান্ত আবিষ্কার হয়েছে। এটি ওয়েব বিকাশকারীদের কোনও নতুন ভাষা না শিখিয়ে ওয়েবসেম্বলি মডিউলগুলি উত্পাদন করতে দেয়। অ্যাসেমব্লিস্ক্রিপ্ট দলটি খুব প্রতিক্রিয়াশীল এবং তাদের সরঞ্জামচেন উন্নত করার জন্য সক্রিয়ভাবে কাজ করছে। আমরা অবশ্যই ভবিষ্যতে অ্যাসেমব্লিস্ক্রিপ্টে নজর রাখব।
আপডেট: মরিচা
এই নিবন্ধটি প্রকাশের পরে, মরিচা দল থেকে নিক ফিৎসগেরাল্ড আমাদের তাদের দুর্দান্ত মরিচা বর্জ্য বইয়ের দিকে ইঙ্গিত করেছেন, এতে ফাইলের আকার অনুকূলকরণের একটি বিভাগ রয়েছে। সেখানে নির্দেশাবলী অনুসরণ করে (সর্বাধিক উল্লেখযোগ্যভাবে লিঙ্ক টাইম অপ্টিমাইজেশন এবং ম্যানুয়াল প্যানিক হ্যান্ডলিং সক্ষম করা) আমাদের "সাধারণ" মরিচা কোড লিখতে এবং ফাইলের আকারটি ফুলে না ফেলে Cargo
(মরিচাটির npm
) ব্যবহার করতে ফিরে যেতে দেয়। মরিচা মডিউলটি জিজিআইপি -র পরে 370 বি দিয়ে শেষ হয়। বিশদগুলির জন্য, দয়া করে স্কুওশে আমি যে পিআরটি খুললাম তা একবার দেখুন।
এই যাত্রায় তাদের সমস্ত সহায়তার জন্য অ্যাশলে উইলিয়ামস , স্টিভ ক্লাবনিক , নিক ফিৎসগেরাল্ড এবং ম্যাক্স গ্রেয়কে বিশেষ ধন্যবাদ।