অগ্রাধিকার বিপরীত এড়িয়ে চলুন

এই নিবন্ধে ব্যাখ্যা করা হয়েছে কীভাবে অ্যান্ড্রয়েডের অডিও সিস্টেম প্রায়োরিটি ইনভার্সন এড়ানোর চেষ্টা করে এবং এমন কিছু কৌশল তুলে ধরা হয়েছে যা আপনিও ব্যবহার করতে পারেন।

এই কৌশলগুলি উচ্চ-পারফরম্যান্স অডিও অ্যাপের ডেভেলপার, OEM, এবং SoC প্রদানকারীদের জন্য উপযোগী হতে পারে, যারা একটি অডিও HAL বাস্তবায়ন করছেন। অনুগ্রহ করে মনে রাখবেন, এই কৌশলগুলি প্রয়োগ করলে গ্লিচ বা অন্যান্য ব্যর্থতা প্রতিরোধ করা যাবেই এমন কোনো নিশ্চয়তা নেই, বিশেষ করে যদি এটি অডিওর প্রেক্ষাপটের বাইরে ব্যবহার করা হয়। আপনার ফলাফল ভিন্ন হতে পারে, এবং আপনার নিজের মূল্যায়ন ও পরীক্ষা করা উচিত।

পটভূমি

ল্যাটেন্সি কমানোর জন্য অ্যান্ড্রয়েড AudioFlinger অডিও সার্ভার এবং AudioTrack/AudioRecord ক্লায়েন্ট ইমপ্লিমেন্টেশনের স্থাপত্য পুনর্গঠন করা হচ্ছে। এই কাজটি অ্যান্ড্রয়েড ৪.১-এ শুরু হয়েছিল এবং ৪.২, ৪.৩, ৪.৪ ও ৫.০ সংস্করণে আরও উন্নত করা হয়েছে।

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

অগ্রাধিকার বিপরীতকরণ

প্রায়োরিটি ইনভার্সন হলো রিয়েল-টাইম সিস্টেমের একটি চিরায়ত ব্যর্থতার ধরণ, যেখানে একটি উচ্চ-প্রায়োরিটির টাস্ক অনির্দিষ্টকালের জন্য আটকে থাকে এবং একটি নিম্ন-প্রায়োরিটির টাস্কের কোনো রিসোর্স (যেমন মিউটেক্স দ্বারা সুরক্ষিত শেয়ার্ড স্টেট) মুক্ত করার জন্য অপেক্ষা করে।

একটি অডিও সিস্টেমে, প্রায়োরিটি ইনভার্সন সাধারণত গ্লিচ (ক্লিক, পপ, ড্রপআউট), সার্কুলার বাফার ব্যবহার করার সময় অডিওর পুনরাবৃত্তি , অথবা কোনো কমান্ডে সাড়া দিতে বিলম্ব হিসাবে প্রকাশ পায়।

প্রায়োরিটি ইনভার্সন এড়ানোর একটি প্রচলিত উপায় হলো অডিও বাফার সাইজ বাড়িয়ে দেওয়া। তবে, এই পদ্ধতিটি ল্যাটেন্সি বাড়িয়ে দেয় এবং সমস্যাটি সমাধান না করে কেবল আড়াল করে রাখে। প্রায়োরিটি ইনভার্সন বোঝা এবং তা প্রতিরোধ করাই শ্রেয়, যেমনটি নিচে দেখানো হলো।

অ্যান্ড্রয়েড অডিও বাস্তবায়নে, প্রায়োরিটি ইনভার্সন এই জায়গাগুলিতে ঘটার সম্ভাবনা সবচেয়ে বেশি। তাই আপনার মনোযোগ এখানেই কেন্দ্রীভূত করা উচিত:

  • AudioFlinger-এ সাধারণ মিক্সার থ্রেড এবং দ্রুত মিক্সার থ্রেডের মধ্যে
  • দ্রুত AudioTrack-এর জন্য অ্যাপ্লিকেশন কলব্যাক থ্রেড এবং দ্রুত মিক্সার থ্রেডের মধ্যে (উভয়েরই উচ্চতর অগ্রাধিকার রয়েছে, কিন্তু অগ্রাধিকারগুলি সামান্য ভিন্ন)
  • দ্রুত AudioRecord এবং দ্রুত ক্যাপচার থ্রেডের জন্য অ্যাপ্লিকেশন কলব্যাক থ্রেডের মধ্যে (পূর্বেরটির অনুরূপ)
  • অডিও হার্ডওয়্যার অ্যাবস্ট্রাকশন লেয়ার (HAL) বাস্তবায়নের মধ্যে, যেমন টেলিফোনি বা ইকো ক্যান্সেলেশনের জন্য।
  • কার্নেলের অডিও ড্রাইভারের মধ্যে
  • AudioTrack বা AudioRecord কলব্যাক থ্রেড এবং অন্যান্য অ্যাপ থ্রেডের মধ্যে (এটি আমাদের নিয়ন্ত্রণের বাইরে)

সাধারণ সমাধান

সাধারণ সমাধানগুলোর মধ্যে রয়েছে:

  • ইন্টারাপ্ট নিষ্ক্রিয় করা
  • অগ্রাধিকার উত্তরাধিকার মিউটেক্স

লিনাক্স ইউজার স্পেসে ইন্টারাপ্ট নিষ্ক্রিয় করা সম্ভব নয় এবং এটি সিমেট্রিক মাল্টি-প্রসেসর (SMP)-এর ক্ষেত্রে কাজ করে না।

অডিও সিস্টেমে প্রায়োরিটি ইনহেরিটেন্স ফিউটেক্স (ফাস্ট ইউজার-স্পেস মিউটেক্স) ব্যবহার করা হয় না, কারণ এগুলো তুলনামূলকভাবে ভারী এবং একটি বিশ্বস্ত ক্লায়েন্টের উপর নির্ভরশীল।

অ্যান্ড্রয়েড দ্বারা ব্যবহৃত কৌশল

'ট্রাই লক' এবং টাইমআউটসহ লক দিয়ে পরীক্ষা-নিরীক্ষা শুরু হয়েছিল। এগুলো হলো মিউটেক্স লক অপারেশনের নন-ব্লকিং এবং বাউন্ডেড ব্লকিং সংস্করণ। ট্রাই লক এবং টাইমআউটসহ লক বেশ ভালোভাবে কাজ করলেও, এগুলো কয়েকটি অস্পষ্ট ব্যর্থতার ধরনের প্রতি সংবেদনশীল ছিল: ক্লায়েন্ট ব্যস্ত থাকলে সার্ভার যে শেয়ার্ড স্টেট অ্যাক্সেস করতে পারবে, তার কোনো নিশ্চয়তা ছিল না; এবং যদি পরস্পর সম্পর্কহীন একাধিক লকের একটি দীর্ঘ ক্রম থাকে যেগুলো সবই টাইমআউট হয়ে যায়, তাহলে মোট টাইমআউটের পরিমাণ অনেক বেশি হয়ে যেতে পারত।

আমরা অ্যাটমিক অপারেশনও ব্যবহার করি, যেমন:

  • বৃদ্ধি
  • বিটওয়াইজ "অথবা"
  • বিটওয়াইজ "অ্যান্ড"

এগুলোর সবগুলোই পূর্ববর্তী মান ফেরত দেয় এবং প্রয়োজনীয় SMP ব্যারিয়ার অন্তর্ভুক্ত করে। অসুবিধা হলো, এগুলোর জন্য অসীম সংখ্যকবার পুনরায় চেষ্টা করার প্রয়োজন হতে পারে। তবে বাস্তবে আমরা দেখেছি যে, এই পুনরায় চেষ্টাগুলো কোনো সমস্যা নয়।

দ্রষ্টব্য: অ্যাটমিক অপারেশন এবং মেমোরি ব্যারিয়ারের সাথে এদের মিথস্ক্রিয়া প্রায়শই ভুলভাবে বোঝা ও ব্যবহার করা হয়। আমরা এখানে সম্পূর্ণতার জন্য এই মেথডগুলো অন্তর্ভুক্ত করেছি, তবে আরও তথ্যের জন্য আপনাকে অ্যান্ড্রয়েডের জন্য এসএমপি প্রাইমার (SMP Primer for Android) নিবন্ধটিও পড়ার পরামর্শ দিচ্ছি।

উপরোক্ত সরঞ্জামগুলোর বেশিরভাগই আমাদের কাছে এখনও আছে এবং আমরা সেগুলো ব্যবহার করি, এবং সম্প্রতি এই কৌশলগুলো যুক্ত করেছি:

  • ডেটার জন্য নন-ব্লকিং সিঙ্গেল-রিডার সিঙ্গেল-রাইটার FIFO কিউ ব্যবহার করুন।
  • উচ্চ এবং নিম্ন-অগ্রাধিকারের মডিউলগুলির মধ্যে স্টেট শেয়ার করার পরিবর্তে স্টেট কপি করার চেষ্টা করুন।
  • যখন স্টেট শেয়ার করার প্রয়োজন হয়, তখন স্টেটটিকে সর্বোচ্চ আকারের এমন একটি ওয়ার্ডে সীমাবদ্ধ রাখুন যা রিট্রাই ছাড়াই এক-বাস অপারেশনে অ্যাটমিকভাবে অ্যাক্সেস করা যায়।
  • জটিল ও একাধিক শব্দের স্টেটের জন্য একটি স্টেট কিউ ব্যবহার করুন। স্টেট কিউ মূলত একটি নন-ব্লকিং, সিঙ্গেল-রিডার ও সিঙ্গেল-রাইটার FIFO কিউ, যা ডেটার পরিবর্তে স্টেটের জন্য ব্যবহৃত হয়। তবে এক্ষেত্রে রাইটার পাশাপাশি থাকা পুশগুলোকে একটিমাত্র পুশে একত্রিত করে।
  • SMP-এর সঠিকতার জন্য মেমরি বাধাগুলোর প্রতি মনোযোগ দিন।
  • বিশ্বাস করুন, কিন্তু যাচাই করুন । প্রসেসগুলোর মধ্যে স্টেট শেয়ার করার সময়, ধরে নেবেন না যে স্টেটটি সুগঠিত। উদাহরণস্বরূপ, পরীক্ষা করে দেখুন যে ইনডেক্সগুলো সীমার মধ্যে আছে কিনা। একই প্রসেসের থ্রেডগুলোর মধ্যে, বা পারস্পরিক বিশ্বাসী প্রসেসগুলোর (যাদের সাধারণত একই UID থাকে) মধ্যে এই যাচাইয়ের প্রয়োজন নেই। PCM অডিওর মতো শেয়ার করা ডেটার ক্ষেত্রেও এটি অপ্রয়োজনীয়, যেখানে কোনো ত্রুটি তেমন গুরুতর নয়।

নন-ব্লকিং অ্যালগরিদম

নন-ব্লকিং অ্যালগরিদম সাম্প্রতিককালে ব্যাপক গবেষণার বিষয় হয়ে উঠেছে। কিন্তু সিঙ্গেল-রিডার সিঙ্গেল-রাইটার FIFO কিউ ছাড়া, আমরা দেখেছি যে এগুলো জটিল এবং ত্রুটিপ্রবণ।

অ্যান্ড্রয়েড ৪.২ থেকে, আপনি আমাদের নন-ব্লকিং, সিঙ্গেল-রিডার/রাইটার ক্লাসগুলো এই স্থানগুলোতে খুঁজে পাবেন:

  • ফ্রেমওয়ার্ক/av/include/media/nbaio/
  • ফ্রেমওয়ার্কস/এভি/মিডিয়া/লিবএনবাইও/
  • ফ্রেমওয়ার্ক/এভি/সার্ভিস/অডিওফ্লিংগার/স্টেট সারি

এগুলো বিশেষভাবে AudioFlinger-এর জন্য ডিজাইন করা হয়েছে এবং এগুলো সাধারণ ব্যবহারের জন্য নয়। নন-ব্লকিং অ্যালগরিদমগুলো ডিবাগ করা কঠিন বলে পরিচিত। আপনি এই কোডটিকে একটি মডেল হিসেবে দেখতে পারেন। কিন্তু মনে রাখবেন, এতে বাগ থাকতে পারে এবং ক্লাসগুলো অন্য কোনো কাজের জন্য উপযুক্ত হবে এমন কোনো নিশ্চয়তা নেই।

ডেভেলপারদের জন্য, কিছু নমুনা OpenSL ES অ্যাপ্লিকেশন কোড নন-ব্লকিং অ্যালগরিদম ব্যবহার করার জন্য অথবা কোনো নন-অ্যান্ড্রয়েড ওপেন সোর্স লাইব্রেরি রেফারেন্স করার জন্য আপডেট করা উচিত।

আমরা অ্যাপ্লিকেশন কোডের জন্য বিশেষভাবে ডিজাইন করা একটি উদাহরণ নন-ব্লকিং FIFO ইমপ্লিমেন্টেশন প্রকাশ করেছি। প্ল্যাটফর্ম সোর্স ডিরেক্টরি frameworks/av/audio_utils এ অবস্থিত এই ফাইলগুলি দেখুন:

সরঞ্জাম

আমাদের জানামতে, প্রায়োরিটি ইনভার্সন খুঁজে বের করার জন্য কোনো স্বয়ংক্রিয় টুল নেই, বিশেষ করে এটি ঘটার আগে। কিছু গবেষণামূলক স্ট্যাটিক কোড অ্যানালাইসিস টুল সম্পূর্ণ কোডবেস অ্যাক্সেস করতে পারলে প্রায়োরিটি ইনভার্সন খুঁজে বের করতে সক্ষম। অবশ্যই, যদি এতে ব্যবহারকারীর যথেচ্ছ কোড জড়িত থাকে (যেমনটি এই অ্যাপ্লিকেশনের ক্ষেত্রে) অথবা কোডবেসটি বড় হয় (যেমন লিনাক্স কার্নেল এবং ডিভাইস ড্রাইভারের ক্ষেত্রে), তবে স্ট্যাটিক অ্যানালাইসিস অবাস্তব হতে পারে। সবচেয়ে গুরুত্বপূর্ণ বিষয় হলো কোডটি খুব সাবধানে পড়া এবং সম্পূর্ণ সিস্টেম ও এর পারস্পরিক ক্রিয়া সম্পর্কে একটি ভালো ধারণা অর্জন করা। systrace এবং ps -t -p মতো টুলগুলো প্রায়োরিটি ইনভার্সন ঘটার পরে তা দেখার জন্য উপযোগী, কিন্তু এগুলো আপনাকে আগে থেকে জানায় না।

শেষ কথা

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