পাঠ ৪৬ · ৫৭-এর মধ্যে · মডিউল ১১
Home / Courses / Mobile App Development / পারফরম্যান্স

রেন্ডারিং পারফরম্যান্স ও ফ্রেম বাজেট

Rendering performance and frame budgets
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • ফ্রেম বাজেট কী এবং ৬০fps-এ এটি কীভাবে $1000/60$ ms-এ হিসাব হয়
  • একটি বাস্তব ফ্রেম-টাইম তালিকা থেকে কোন ফ্রেমগুলো "জ্যাঙ্কি" তা সত্যিকারের গণনা দিয়ে বের করা
  • জ্যাঙ্কি ফ্রেম থেকে কার্যকর (effective/perceived) fps কীভাবে বের করা হয়
  • একটি বাস্তব অপ্টিমাইজেশন (list virtualization-এর ধাঁচে) প্রয়োগ করলে জ্যাঙ্কি ফ্রেম সংখ্যা ও fps কীভাবে বদলায়, তা সংখ্যা দিয়ে যাচাই করা

১ · ফ্রেম বাজেট কী

একটি ডিসপ্লে প্রতি সেকেন্ডে নির্দিষ্টসংখ্যক বার (রিফ্রেশ রেট, সাধারণত ৬০ Hz) স্ক্রিন রিফ্রেশ করে। প্রতিটি রিফ্রেশের আগে অ্যাপকে সেই ফ্রেমের জন্য প্রয়োজনীয় সব কাজ — লেআউট গণনা, রঙ (paint), কম্পোজিটিং — শেষ করতে হয়। এই সময়সীমাকেই বলা হয় ফ্রেম বাজেটFrame Budgetএকটি ফ্রেমের জন্য বরাদ্দ সর্বোচ্চ সময়, যার মধ্যে ডিসপ্লের রিফ্রেশ রেট অনুযায়ী সব রেন্ডারিং কাজ শেষ করতে হয়।। $60$fps-এ:

$$\text{ফ্রেম বাজেট} = \dfrac{1000\text{ms}}{60} \approx 16.67\text{ms}$$

অর্থাৎ প্রতিটি ফ্রেমের সব কাজ ১৬.৬৭ms-এর মধ্যে শেষ করতে হবে। যদি কোনো ফ্রেমের কাজ এই সময়ের বেশি নেয়, ডিসপ্লে পরবর্তী রিফ্রেশে পুরনো ফ্রেমই দেখাতে বাধ্য হয় (বা একটি ফ্রেম বাদ যায়) — এটিকেই বলা হয় জ্যাঙ্কJankবাজেট ছাড়িয়ে যাওয়া ফ্রেমের কারণে ঘটা দৃশ্যমান স্টাটার/কাঁপুনি — অ্যানিমেশন বা স্ক্রল আর মসৃণ মনে হয় না।।

৬০fps → ১৬.৬৭ms
সবচেয়ে সাধারণ মোবাইল রিফ্রেশ রেট — সবচেয়ে বেশি ব্যবহৃত বাজেট।
৯০/১২০fps → ১১.১১/৮.৩৩ms
উচ্চ রিফ্রেশ রেট ডিভাইসে বাজেট আরও কড়া হয়ে যায়।
জ্যাঙ্কি ফ্রেম
বাজেট ছাড়ানো একটি ফ্রেম — ব্যবহারকারী চোখে "আটকে যাওয়া" অনুভব করেন।

২ · একটি বাস্তব ফ্রেম-টাইম তালিকা থেকে জ্যাঙ্কি ফ্রেম বের করা

নিচে একটি স্ক্রল সিকোয়েন্সের ১০টি পরপর ফ্রেমের প্রকৃত কাজের সময় (ms) দেওয়া আছে। প্রতিটি ফ্রেমের সময়কে ফ্রেম বাজেটের সাথে তুলনা করে কোনগুলো জ্যাঙ্কি তা বের করা হবে, এবং পুরো সিকোয়েন্সের গড় ফ্রেম-সময় থেকে কার্যকর (effective) fps হিসাব করা হবে — যেহেতু ডিসপ্লে সর্বোচ্চ ৬০fps দেখাতে পারে, তাই ফলাফলে min(60.0, ...) দিয়ে একটি সীমা (cap) বসানো হয়েছে।

Python
# ৬০fps-এ ফ্রেম বাজেট = 1000ms / 60 frame ≈ 16.67ms প্রতি ফ্রেমে
FRAME_BUDGET_MS = 1000 / 60
print(f"ফ্রেম বাজেট (60fps): {FRAME_BUDGET_MS:.4f} ms\n")

# একটি রিয়েল স্ক্রল সিকোয়েন্সের ১০টি ফ্রেমের প্রকৃত কাজের সময় (ms)
frame_times = [12.5, 16.0, 18.2, 15.9, 22.4, 16.7, 30.1, 14.3, 17.5, 20.0]

janky_frames = []
for i, t in enumerate(frame_times, start=1):
    is_janky = t > FRAME_BUDGET_MS
    if is_janky:
        janky_frames.append(i)
    status = "জ্যাঙ্কি (বাজেট ছাড়িয়েছে)" if is_janky else "ঠিক আছে"
    print(f"ফ্রেম {i:>2} | কাজের সময়: {t:>5.1f} ms | {status}")

total_frames = len(frame_times)
janky_count = len(janky_frames)
total_time_ms = sum(frame_times)
avg_frame_time = total_time_ms / total_frames
effective_fps = min(60.0, 1000 / avg_frame_time)

print(f"\nমোট ফ্রেম: {total_frames}")
print(f"জ্যাঙ্কি ফ্রেম: {janky_count} টি -> {janky_frames}")
print(f"গড় ফ্রেম সময়: {avg_frame_time:.2f} ms")
print(f"কার্যকর (effective) fps: {effective_fps:.2f}  (টার্গেট ৬০fps-এর তুলনায়)")

    
লক্ষ্য করুন ফ্রেম ৬-এর সময় (১৬.৭ms) বাজেটের (১৬.৬৭ms) চেয়ে সামান্যই বেশি — তবুও এটি জ্যাঙ্কি হিসেবে গণনা হয়, কারণ শর্তটি কড়াভাবে t > FRAME_BUDGET_MS। মোট ১০টির মধ্যে ৬টি ফ্রেম বাজেট ছাড়িয়ে যায়, ফলে গড় ফ্রেম-সময় ১৮.৩৬ms দাঁড়ায় ও কার্যকর fps নেমে প্রায় ৫৪.৪৭-এ চলে আসে — টার্গেট ৬০fps থেকে স্পষ্টভাবে কম।

৩ · কী কারণে ফ্রেম বাজেট ছাড়িয়ে যায়

বেশিরভাগ জ্যাঙ্ক হয় মূল (UI/main) থ্রেডে অতিরিক্ত সিনক্রোনাস কাজের কারণে — যেমন প্রতিটি স্ক্রলে একটি বড় লিস্টের সব আইটেম নতুন করে রেন্ডার করা, ভারী ইমেজ ডিকোডিং মূল থ্রেডে করা, বা লেআউট গণনা বারবার ট্রিগার করা।

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

৪ · অপ্টিমাইজেশনের প্রভাব হিসাব করে দেখা

ধরা যাক উপরের জ্যাঙ্কি ফ্রেমগুলোর কারণ ছিল একটি লিস্টের সব আইটেম প্রতি ফ্রেমে নতুন করে রেন্ডার হওয়া। একটি অপ্টিমাইজেশন (list virtualization-এর ধাঁচে, শুধু বদলে যাওয়া আইটেম রেন্ডার করা) প্রয়োগ করলে বাজেট-ছাড়ানো ফ্রেমগুলোর কাজের সময় অর্ধেক হয়ে যায় — নিচে এই প্রভাব সত্যিকারের হিসাব দিয়ে যাচাই করা হচ্ছে।

Python
# আগের সেলের মতোই বাজেট ও মূল frame_times, এবার একটি অপ্টিমাইজেশনের প্রভাব যাচাই করা হচ্ছে:
# শুধু বদলে যাওয়া লিস্ট-আইটেম রেন্ডার করার ফলে যেসব ফ্রেম বাজেট ছাড়িয়ে গিয়েছিল, তাদের কাজের সময় অর্ধেক হয়ে যায়।

FRAME_BUDGET_MS = 1000 / 60
original_frame_times = [12.5, 16.0, 18.2, 15.9, 22.4, 16.7, 30.1, 14.3, 17.5, 20.0]

def count_janky(times):
    return sum(1 for t in times if t > FRAME_BUDGET_MS)

def effective_fps_of(times):
    avg = sum(times) / len(times)
    return min(60.0, 1000 / avg)

optimized_frame_times = [
    (t / 2) if t > FRAME_BUDGET_MS else t
    for t in original_frame_times
]

before_janky = count_janky(original_frame_times)
after_janky = count_janky(optimized_frame_times)
before_fps = effective_fps_of(original_frame_times)
after_fps = effective_fps_of(optimized_frame_times)

print(f"অপ্টিমাইজেশনের আগে -> জ্যাঙ্কি ফ্রেম: {before_janky}/10, effective fps: {before_fps:.2f}")
print(f"অপ্টিমাইজেশনের পরে  -> জ্যাঙ্কি ফ্রেম: {after_janky}/10, effective fps: {after_fps:.2f}")
print(f"\nপ্রতিটি ফ্রেমের নতুন সময় (ms): {[round(t, 2) for t in optimized_frame_times]}")

    
অপ্টিমাইজেশনের পর সবগুলো ফ্রেমের সময়ই বাজেটের নিচে নেমে আসে (জ্যাঙ্কি ফ্রেম ৬ থেকে ০-তে), এবং কার্যকর fps পুরো ৬০.০০-এ পৌঁছায় — কারণ কোডে min(60.0, ...) ব্যবহার করা হয়েছে, যেহেতু বাস্তবে ডিসপ্লে রিফ্রেশ রেটের চেয়ে বেশি fps "দেখানো" সম্ভব নয়, সফটওয়্যার যত দ্রুতই হিসাব করুক না কেন।
মূল কথা · Key takeaway

ফ্রেম বাজেট একটি নির্দিষ্ট, গণনাযোগ্য সংখ্যা ($1000/60 \approx 16.67$ms) — এবং জ্যাঙ্ক মানে শুধু "ধীর মনে হওয়া" নয়, বরং প্রতিটি ফ্রেমের প্রকৃত কাজের সময়কে এই বাজেটের সাথে তুলনা করে নির্ভুলভাবে গণনাযোগ্য একটি ব্যাপার। একবার কোন ফ্রেমগুলো বাজেট ছাড়াচ্ছে তা চিহ্নিত হলে, লক্ষ্যভিত্তিক অপ্টিমাইজেশন (যেমন অপ্রয়োজনীয় রি-রেন্ডার কমানো) দিয়ে সেই সংখ্যা সরাসরি হিসাব করে যাচাই করা যায়।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ একটি ডিভাইসের রিফ্রেশ রেট ৬০Hz-এর বদলে ১২০Hz হলে ফ্রেম বাজেট কীভাবে বদলাবে?

বাজেট হবে $1000/120 \approx 8.33$ms — অর্থাৎ প্রায় অর্ধেক সময়ে সব কাজ শেষ করতে হবে। উপরের কোড সেলের একই frame_times তালিকা ১২০Hz ডিভাইসে চালালে জ্যাঙ্কি ফ্রেমের সংখ্যা আরও বেড়ে যাবে, কারণ অনেক ফ্রেম যা ৬০Hz-এ "ঠিক আছে" ছিল, তা ৮.৩৩ms বাজেটের তুলনায় অনেক বেশি সময় নিচ্ছে।

প্র ০২ ফ্রেম ৬-এর সময় (১৬.৭ms) বাজেটের (১৬.৬৭ms) চেয়ে মাত্র ০.০৩ms বেশি — এত সামান্য পার্থক্যও কি সত্যিই সমস্যা?

একটি বিচ্ছিন্ন ফ্রেম হিসেবে হয়তো ব্যবহারকারী টের পাবেন না, কিন্তু কোডে শর্তটি কড়াভাবে গণনা হয় বলেই এটি গুরুত্বপূর্ণ — বাস্তব অ্যাপে এই ধরনের "সামান্য ছাড়িয়ে যাওয়া" ফ্রেম প্রায়ই একবার নয়, বারবার ঘটে (একই কারণে), এবং সেই সঞ্চিত প্রভাবই দৃশ্যমান কাঁপুনি তৈরি করে। তাই প্রতিটি ফ্রেমকে কড়াভাবে বাজেটের বিপরীতে মাপা জরুরি।

প্র ০৩ দ্বিতীয় কোড সেলে effective_fps_of ফাংশনে min(60.0, ...) কেন ব্যবহার করা হয়েছে?

কারণ একটি ৬০Hz ডিসপ্লে সর্বোচ্চ সেকেন্ডে ৬০ বার রিফ্রেশ করতে পারে — সফটওয়্যার যত দ্রুতই ফ্রেম তৈরি করুক না কেন, ডিসপ্লে তার চেয়ে বেশি দেখাতে পারবে না। অপ্টিমাইজেশনের পরে গড় ফ্রেম-সময় থেকে গাণিতিকভাবে ৮২fps-এর মতো বের হয় (কোড সেলে 1000 / avg), কিন্তু min(60.0, ...) এটিকে বাস্তবসম্মত ৬০.০০-এ সীমাবদ্ধ করে।

অনুশীলন

  1. চিন্তা করুন: আপনার ব্যবহৃত কোনো অ্যাপে স্ক্রল করার সময় কখনো "কাঁপুনি" বা "আটকে যাওয়া" অনুভূতি হয়েছে কি? সেই মুহূর্তে অ্যাপটি সম্ভবত কী ভারী কাজ করছিল বলে আপনার মনে হয়?

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

  2. পরীক্ষা করুন: প্রথম কোড সেলে frame_times তালিকার শেষে 25.0 যোগ করুন (মোট ১১টি ফ্রেম হবে), তারপর কোডটি চালিয়ে দেখুন janky_count ও effective_fps কীভাবে বদলায়।

    নতুন ফ্রেমটি (২৫.০ms) বাজেট (১৬.৬৭ms) ছাড়িয়ে যায়, তাই janky_count বেড়ে ৭ হবে (মোট ১১টির মধ্যে)। মোট সময় বেড়ে $183.6 + 25.0 = 208.6$ms হবে, গড় ফ্রেম-সময় $208.6/11 \approx 18.96$ms, ফলে effective_fps আরও কমে প্রায় $1000/18.96 \approx 52.74$-এ নেমে আসবে — অর্থাৎ আরেকটি ভারী ফ্রেম যোগ হওয়ায় সামগ্রিক পারফরম্যান্স আরও খারাপ হয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ অ্যাপ লাইফসাইকেল, মোবাইল UI/UX, MVVM/MVI আর্কিটেকচার, নেভিগেশন, স্টেট ম্যানেজমেন্ট, লোকাল স্টোরেজ, নেটওয়ার্কিং, ডিভাইস ফিচার, পারফরম্যান্স ও ডিপ্লয়মেন্ট — সব একসাথে।
  • পরের পাঠ: মেমোরি ম্যানেজমেন্ট ও লিক প্রতিরোধ L47 পারফরম্যান্স মডিউলের পরের ধাপ — সাবস্ক্রাইবার/লিসেনার সঠিকভাবে পরিষ্কার না করলে কীভাবে মেমোরি লিক হয়, তার বাস্তব গণনা।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics, Full-Stack Web Frameworks ও Mobile App Development — সব এক জায়গায়।
আগের পাঠ
পুশ নোটিফিকেশন