মুক্তিপ্রাপ্ত :
অ্যান্ড্রয়েড ১২ (এপিআই লেভেল ৩১) - পারফরম্যান্সহিন্টম্যানেজার
অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) - এনডিকে এপিআই-তে পারফরম্যান্স হিন্ট ম্যানেজার
Android 15 (DP1) - reportActualWorkDuration()
সিপিইউ পারফরম্যান্স হিন্টস-এর মাধ্যমে, একটি অ্যাপ তার প্রয়োজনের সাথে আরও ভালোভাবে মেলানোর জন্য ডাইনামিক সিপিইউ পারফরম্যান্স আচরণকে প্রভাবিত করতে পারে। বেশিরভাগ ডিভাইসে, অ্যান্ড্রয়েড পূর্ববর্তী চাহিদার উপর ভিত্তি করে একটি ওয়ার্কলোডের জন্য সিপিইউ ক্লক স্পিড এবং কোর টাইপ ডাইনামিকভাবে অ্যাডজাস্ট করে। যদি কোনো ওয়ার্কলোড বেশি সিপিইউ রিসোর্স ব্যবহার করে, তাহলে ক্লক স্পিড বাড়ানো হয় এবং ওয়ার্কলোডটিকে অবশেষে একটি বড় কোরে স্থানান্তর করা হয়। যদি ওয়ার্কলোডটি কম রিসোর্স ব্যবহার করে, তাহলে অ্যান্ড্রয়েড রিসোর্স বরাদ্দ কমিয়ে দেয়। ADPF-এর মাধ্যমে, একটি অ্যাপ তার পারফরম্যান্স এবং ডেডলাইন সম্পর্কে একটি অতিরিক্ত সংকেত পাঠাতে পারে। এটি সিস্টেমকে আরও দ্রুত গতি বাড়াতে (পারফরম্যান্স উন্নত করতে) এবং ওয়ার্কলোড শেষ হলে দ্রুত ক্লক স্পিড কমাতে (বিদ্যুৎ সাশ্রয় করতে) সাহায্য করে।
ঘড়ির গতি
যখন অ্যান্ড্রয়েড ডিভাইসগুলো গতিশীলভাবে তাদের সিপিইউ ক্লক স্পিড সমন্বয় করে, তখন সেই ফ্রিকোয়েন্সি আপনার কোডের পারফরম্যান্স পরিবর্তন করতে পারে। সর্বোচ্চ পারফরম্যান্স অর্জন, নিরাপদ থার্মাল অবস্থা বজায় রাখা এবং দক্ষতার সাথে শক্তি ব্যবহার করার জন্য, ডাইনামিক ক্লক স্পিডের সাথে সামঞ্জস্যপূর্ণ কোড ডিজাইন করা গুরুত্বপূর্ণ। আপনি আপনার অ্যাপ কোডে সরাসরি সিপিইউ ফ্রিকোয়েন্সি নির্ধারণ করতে পারবেন না। ফলস্বরূপ, অ্যাপগুলো উচ্চতর সিপিইউ ক্লক স্পিডে চলার চেষ্টা করার একটি সাধারণ উপায় হলো ব্যাকগ্রাউন্ড থ্রেডে একটি বিজি লুপ চালানো, যাতে কাজের চাপ বেশি বলে মনে হয়। এটি একটি খারাপ অভ্যাস, কারণ এটি শক্তি অপচয় করে এবং ডিভাইসের উপর থার্মাল লোড বাড়ায়, যখন অ্যাপটি আসলে অতিরিক্ত রিসোর্স ব্যবহার করে না। সিপিইউ PerformanceHint এপিআই এই সমস্যা সমাধানের জন্য ডিজাইন করা হয়েছে। সিস্টেমকে প্রকৃত কাজের সময়কাল এবং লক্ষ্যমাত্রার কাজের সময়কাল জানানোর মাধ্যমে, অ্যান্ড্রয়েড অ্যাপটির সিপিইউ চাহিদার একটি সার্বিক ধারণা পেতে এবং দক্ষতার সাথে রিসোর্স বরাদ্দ করতে সক্ষম হবে। এর ফলে সাশ্রয়ী শক্তি খরচের স্তরে সর্বোত্তম পারফরম্যান্স পাওয়া যাবে।
মূল প্রকারগুলি
আপনার অ্যাপটি যে ধরনের সিপিইউ কোরে চলে, সেটিও পারফরম্যান্সের জন্য একটি গুরুত্বপূর্ণ বিষয়। অ্যান্ড্রয়েড ডিভাইসগুলো প্রায়শই সাম্প্রতিক ওয়ার্কলোডের আচরণের উপর ভিত্তি করে একটি থ্রেডের জন্য নির্ধারিত সিপিইউ কোর গতিশীলভাবে পরিবর্তন করে। একাধিক কোর টাইপযুক্ত এসওসি-তে সিপিইউ কোর নির্ধারণ আরও বেশি জটিল। এই ডিভাইসগুলোর কয়েকটিতে, তাপীয়ভাবে অস্থিতিশীল অবস্থায় না গিয়ে বড় কোরগুলো কেবল অল্প সময়ের জন্যই ব্যবহার করা যায়।
নিম্নলিখিত কারণগুলোর জন্য আপনার অ্যাপের সিপিইউ কোর অ্যাফিনিটি সেট করার চেষ্টা করা উচিত নয়:
- ডিভাইসের মডেল অনুযায়ী কোনো নির্দিষ্ট ওয়ার্কলোডের জন্য সেরা কোর টাইপ ভিন্ন হয়ে থাকে।
- বৃহত্তর কোর চালানোর স্থায়িত্ব এসওসি (SoC) এবং প্রতিটি ডিভাইস মডেল দ্বারা প্রদত্ত বিভিন্ন তাপীয় সমাধানের উপর নির্ভর করে।
- তাপীয় অবস্থার উপর পরিবেশগত প্রভাব কোর নির্বাচনকে আরও জটিল করে তুলতে পারে। উদাহরণস্বরূপ, আবহাওয়া বা ফোনের কেস একটি ডিভাইসের তাপীয় অবস্থা পরিবর্তন করতে পারে।
- অতিরিক্ত পারফরম্যান্স এবং তাপীয় ক্ষমতা সম্পন্ন নতুন ডিভাইসগুলোকে কোর সিলেকশন সমর্থন করতে পারে না। ফলে, ডিভাইসগুলো প্রায়শই কোনো অ্যাপের প্রসেসর অ্যাফিনিটি উপেক্ষা করে।
ডিফল্ট লিনাক্স শিডিউলার আচরণের উদাহরণ

PerformanceHint API শুধু DVFS লেটেন্সির চেয়েও বেশি কিছুকে বিমূর্ত করে।

- যদি টাস্কগুলো কোনো নির্দিষ্ট সিপিইউতে চালানোর প্রয়োজন হয়, তাহলে পারফরম্যান্সহিন্ট এপিআই আপনার হয়ে সেই সিদ্ধান্তটি নিতে জানে।
- সুতরাং, আপনার অ্যাফিনিটি ব্যবহার করার প্রয়োজন নেই।
- ডিভাইসগুলো বিভিন্ন টপোলজিতে আসে; এগুলোর পাওয়ার এবং থার্মাল বৈশিষ্ট্য এতটাই বৈচিত্র্যপূর্ণ যে তা অ্যাপ ডেভেলপারের কাছে তুলে ধরা সম্ভব নয়।
- আপনি যে মূল সিস্টেমের ওপর কাজ করছেন, সে সম্পর্কে কোনো অনুমান করা যায় না।
সমাধান
ADPF PerformanceHintManager ক্লাসটি প্রদান করে, যার ফলে অ্যাপগুলো সিপিইউ ক্লক স্পিড এবং কোর টাইপের জন্য অ্যান্ড্রয়েডে পারফরম্যান্স হিন্ট পাঠাতে পারে। এরপর অপারেটিং সিস্টেম ডিভাইসটির এসওসি (SoC) এবং থার্মাল সলিউশনের উপর ভিত্তি করে সিদ্ধান্ত নিতে পারে যে এই হিন্টগুলো কীভাবে সবচেয়ে ভালোভাবে ব্যবহার করা যায়। যদি আপনার অ্যাপ থার্মাল স্টেট মনিটরিং-এর সাথে এই এপিআই ব্যবহার করে, তবে এটি বিজি লুপ এবং থ্রটলিং ঘটাতে পারে এমন অন্যান্য কোডিং কৌশল ব্যবহার না করে, অপারেটিং সিস্টেমকে আরও তথ্যবহুল হিন্ট প্রদান করতে পারে।
তত্ত্বটিকে বাস্তবে প্রয়োগ করার উপায় নিচে দেওয়া হলো:
PerformanceHintManager শুরু করুন এবং HintSession তৈরি করুন
সিস্টেম সার্ভিস ব্যবহার করে ম্যানেজারকে অ্যাক্সেস করুন এবং একই ওয়ার্কলোডে কর্মরত আপনার থ্রেড বা থ্রেড গ্রুপের জন্য একটি হিন্ট সেশন তৈরি করুন।
সি++
int32_t tids[1];
tids[0] = gettid();
int64_t target_fps_nanos = getFpsNanos();
APerformanceHintManager* hint_manager = APerformanceHint_getManager();
APerformanceHintSession* hint_session =
APerformanceHint_createSession(hint_manager, tids, 1, target_fps_nanos);
জাভা
int[] tids = {
android.os.Process.myTid()
};
long targetFpsNanos = getFpsNanos();
PerformanceHintManager performanceHintManager =
(PerformanceHintManager) this.getSystemService(Context.PERFORMANCE_HINT_SERVICE);
PerformanceHintManager.Session hintSession =
performanceHintManager.createHintSession(tids, targetFpsNanos);
প্রয়োজনে সুতা সেট করুন।
মুক্তিপ্রাপ্ত :
অ্যান্ড্রয়েড ১১ (এপিআই লেভেল ৩৪)
যখন আপনার অন্য থ্রেড পরে যোগ করার প্রয়োজন হয়, তখন PerformanceHintManager.Session এর setThreads ফাংশনটি ব্যবহার করুন। উদাহরণস্বরূপ, যদি আপনি পরে আপনার ফিজিক্স থ্রেড তৈরি করেন এবং সেটিকে সেশনে যোগ করার প্রয়োজন হয়, তাহলে আপনি এই setThreads API-টি ব্যবহার করতে পারেন।
সি++
auto tids = thread_ids.data();
std::size_t size = thread_ids_.size();
APerformanceHint_setThreads(hint_session, tids, size);
জাভা
int[] tids = new int[3];
// add all your thread IDs. Remember to use android.os.Process.myTid() as that
// is the linux native thread-id.
// Thread.currentThread().getId() will not work because it is jvm's thread-id.
hintSession.setThreads(tids);
আপনি যদি নিম্নতর এপিআই লেভেল টার্গেট করেন, তাহলে প্রতিবার থ্রেড আইডি পরিবর্তন করার জন্য আপনাকে সেশনটি মুছে ফেলে একটি নতুন সেশন তৈরি করতে হবে।
প্রকৃত কাজের সময়কাল রিপোর্ট করুন
কাজটি সম্পন্ন করতে প্রয়োজনীয় প্রকৃত সময়কাল ন্যানোসেকেন্ডে ট্র্যাক করুন এবং প্রতিটি সাইকেলে কাজটি সম্পন্ন হওয়ার পর সিস্টেমকে তা জানান। উদাহরণস্বরূপ, যদি এটি আপনার রেন্ডারিং থ্রেডগুলোর জন্য হয়, তবে প্রতিটি ফ্রেমে এটি কল করুন।
নির্ভরযোগ্যভাবে সঠিক সময় পেতে, ব্যবহার করুন:
সি++
clock_gettime(CLOCK_MONOTONIC, &clock); // if you prefer "C" way from <time.h>
// or
std::chrono::high_resolution_clock::now(); // if you prefer "C++" way from <chrono>
জাভা
System.nanoTime();
উদাহরণস্বরূপ:
সি++
// All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)`
auto start_time = std::chrono::high_resolution_clock::now();
// do work
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
int64_t actual_duration = static_cast<int64_t>(duration);
APerformanceHint_reportActualWorkDuration(hint_session, actual_duration);
জাভা
long startTime = System.nanoTime();
// do work
long endTime = System.nanoTime();
long duration = endTime - startTime;
hintSession.reportActualWorkDuration(duration);
প্রয়োজনে কাজের লক্ষ্যমাত্রা সময়কাল হালনাগাদ করুন।
যখনই আপনার নির্ধারিত কাজের সময়কাল পরিবর্তিত হয়, উদাহরণস্বরূপ যদি প্লেয়ার একটি ভিন্ন টার্গেট এফপিএস (fps) বেছে নেয়, তখন সিস্টেমকে জানানোর জন্য updateTargetWorkDuration মেথডটি কল করুন, যাতে অপারেটিং সিস্টেম (OS) নতুন টার্গেট অনুযায়ী রিসোর্সগুলো সমন্বয় করতে পারে। আপনাকে এটি প্রতিটি ফ্রেমে কল করতে হবে না, শুধুমাত্র টার্গেট সময়কাল পরিবর্তিত হলেই এটি কল করা প্রয়োজন।
সি++
APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);
জাভা
hintSession.updateTargetWorkDuration(targetDuration);