از ftrace استفاده کنید

ftrace یک ابزار اشکال زدایی برای درک آنچه در داخل هسته لینوکس می گذرد است. بخش‌های زیر عملکرد پایه ftrace، استفاده از ftrace با atrace (که رویدادهای هسته را ثبت می‌کند) و ftrace پویا را شرح می‌دهد.

برای جزئیات در مورد عملکرد پیشرفته ftrace که از systrace در دسترس نیست، به مستندات ftrace در <kernel tree>/Documentation/trace/ftrace.txt مراجعه کنید.

رویدادهای هسته را با atrace ضبط کنید

atrace ( frameworks/native/cmds/atrace ) از ftrace برای ثبت رویدادهای هسته استفاده می کند. به نوبه خود، systrace.py (یا run_systrace.py در نسخه‌های بعدی Catapult ) از adb برای اجرای atrace در دستگاه استفاده می‌کند. atrace کارهای زیر را انجام می دهد:

  • ردیابی حالت کاربر را با تنظیم یک ویژگی ( debug.atrace.tags.enableflags ) تنظیم می کند.
  • با نوشتن در گره های ftrace sysfs مناسب، عملکرد ftrace مورد نظر را فعال می کند. با این حال، از آنجایی که ftrace از ویژگی‌های بیشتری پشتیبانی می‌کند، ممکن است برخی از گره‌های sysfs را خودتان تنظیم کنید و سپس از atrace استفاده کنید.

به استثنای ردیابی زمان راه‌اندازی، برای تنظیم ویژگی روی مقدار مناسب، به استفاده از atrace تکیه کنید. این ویژگی یک بیت ماسک است و هیچ راه خوبی برای تعیین مقادیر صحیح به جز نگاه کردن به هدر مناسب (که می تواند بین نسخه های اندروید تغییر کند) وجود ندارد.

رویدادهای ftrace را فعال کنید

گره‌های ftrace sysfs در /sys/kernel/tracing هستند و رویدادهای ردیابی به دسته‌هایی در /sys/kernel/tracing/events تقسیم می‌شوند.

برای فعال کردن رویدادها بر اساس هر دسته، از موارد زیر استفاده کنید:

echo 1 > /sys/kernel/tracing/events/irq/enable

برای فعال کردن رویدادها بر اساس هر رویداد، از موارد زیر استفاده کنید:

echo 1 > /sys/kernel/tracing/events/sched/sched_wakeup/enable

اگر رویدادهای اضافی با نوشتن در گره‌های sysfs فعال شده باشند، توسط atrace بازنشانی نمی‌شوند . یک الگوی رایج برای بازگرداندن دستگاه کوالکام، فعال کردن نقاط ردیابی kgsl (GPU) و mdss (خط لوله نمایش) و سپس استفاده از atrace یا systrace است:

adb shell "echo 1 > /sys/kernel/tracing/events/mdss/enable"
adb shell "echo 1 > /sys/kernel/tracing/events/kgsl/enable"
./systrace.py sched freq idle am wm gfx view binder_driver irq workq ss sync -t 10 -b 96000 -o full_trace.html

همچنین می‌توانید از ftrace بدون atrace یا systrace استفاده کنید، که زمانی مفید است که شما ردیابی‌های فقط هسته را می‌خواهید (یا اگر زمان صرف کرده‌اید و ویژگی ردیابی حالت کاربر را با دست بنویسید). برای اجرای فقط ftrace:

  1. اندازه بافر را به مقدار کافی برای ردیابی خود تنظیم کنید:
    echo 96000 > /sys/kernel/tracing/buffer_size_kb
    
  2. فعال کردن ردیابی:
    echo 1 > /sys/kernel/tracing/tracing_on
    
  3. تست خود را اجرا کنید، سپس ردیابی را غیرفعال کنید:
    echo 0 > /sys/kernel/tracing/tracing_on
    
  4. رها کردن رد:
    cat /sys/kernel/tracing/trace > /data/local/tmp/trace_output
    

trace_output ردیابی را به صورت متن می دهد. برای تجسم آن با استفاده از Catapult، مخزن Catapult را از GitHub دریافت کنید و trace2html را اجرا کنید:

catapult/tracing/bin/trace2html ~/path/to/trace_file

به طور پیش فرض، trace_file.html در همان دایرکتوری می نویسد.

رویدادها را به هم مرتبط کنید

اغلب مفید است که به تجسم منجنیق و گزارش ftrace به طور همزمان نگاه کنید. برای مثال، برخی از رویدادهای ftrace (مخصوصاً رویدادهای خاص فروشنده) توسط Catapult تجسم نمی شوند. با این حال، مُهرهای زمان Catapult یا به اولین رویداد در ردیابی یا به یک مهر زمانی خاص که توسط atrace ریخته شده است، مرتبط هستند، در حالی که مُهرهای زمانی ftrace خام بر اساس یک منبع ساعت مطلق خاص در هسته لینوکس هستند.

برای پیدا کردن یک رویداد ftrace داده شده از یک رویداد Catapult:

  1. گزارش خام ftrace را باز کنید. ردیابی ها در نسخه های اخیر systrace به طور پیش فرض فشرده می شوند:
    • اگر systrace خود را با --no-compress گرفته‌اید، این در فایل html در بخشی است که با BEGIN TRACE شروع می‌شود.
    • در غیر این صورت، html2trace را از درخت Catapult ( tracing/bin/html2trace ) اجرا کنید تا ردیابی از حالت فشرده خارج شود.
  2. مهر زمانی نسبی را در تجسم منجنیق پیدا کنید.
  3. یک خط در ابتدای ردیابی حاوی tracing_mark_sync پیدا کنید. باید چیزی شبیه این باشد:
    <5134>-5134  (-----) [003] ...1    68.104349: tracing_mark_write: trace_event_clock_sync: parent_ts=68.104286
    

    اگر این خط وجود نداشته باشد (یا اگر از ftrace بدون atrace استفاده کرده اید)، زمان بندی از اولین رویداد در گزارش ftrace نسبی خواهد بود.
    1. مهر زمانی نسبی (بر حسب میلی ثانیه) را به مقدار در parent_ts (در ثانیه) اضافه کنید.
    2. مُهر زمانی جدید را جستجو کنید.

این مراحل باید شما را در رویداد (یا حداقل بسیار نزدیک به آن) قرار دهند.

از frace پویا استفاده کنید

وقتی systrace و ftrace استاندارد کافی نیستند، آخرین راه‌حل موجود است: dynamic ftrace . Ftrace پویا شامل بازنویسی کد هسته پس از راه‌اندازی می‌شود و در نتیجه به دلایل امنیتی در هسته‌های تولیدی موجود نیست. با این حال، تک تک باگ‌های عملکردی دشوار در سال‌های 2015 و 2016 در نهایت با استفاده از fttrace پویا به وجود آمدند. این به ویژه برای اشکال زدایی خواب های بی وقفه قدرتمند است زیرا هر بار که عملکردی را که باعث ایجاد خواب بدون وقفه می شود ضربه بزنید، می توانید یک stack trace در هسته دریافت کنید. همچنین می‌توانید بخش‌هایی را که وقفه‌ها و پیش‌پرداخت‌ها غیرفعال هستند اشکال‌زدایی کنید، که می‌تواند برای اثبات مسائل بسیار مفید باشد.

برای روشن کردن fttrace پویا، defconfig هسته خود را ویرایش کنید:

  1. CONFIG_STRICT_MEMORY_RWX را بردارید (اگر موجود است). اگر روی 3.18 یا جدیدتر و arm64 هستید، اینجا نیست.
  2. موارد زیر را اضافه کنید: CONFIG_DYNAMIC_FTRACE=y، CONFIG_FUNCTION_TRACER=y، CONFIG_IRQSOFF_TRACER=y، CONFIG_FUNCTION_PROFILER=y، و CONFIG_PREEMPT_TRACER=y
  3. هسته جدید را بازسازی و بوت کنید.
  4. برای بررسی ردیاب های موجود موارد زیر را اجرا کنید:
    cat /sys/kernel/tracing/available_tracers
    
  5. دستور بازگشت function ، irqsoff ، preemptoff و preemptirqsoff را تأیید کنید.
  6. برای اطمینان از اینکه fttrace پویا کار می کند موارد زیر را اجرا کنید:
    cat /sys/kernel/tracing/available_filter_functions | grep <a function you care about>
    

پس از انجام این مراحل، fttrace پویا، نمایه ساز تابع، پروفایلر irqsoff و نمایه ساز preemptoff را در دسترس دارید. ما قویاً توصیه می کنیم اسناد ftrace در مورد این موضوعات را قبل از استفاده از آنها بخوانید زیرا قدرتمند اما پیچیده هستند. irqsoff و preemptoff در درجه اول برای تأیید اینکه رانندگان ممکن است وقفه ها یا preemption را برای مدت طولانی خاموش بگذارند مفید هستند.

نمایه ساز تابع بهترین گزینه برای مسائل مربوط به عملکرد است و اغلب برای یافتن مکان فراخوانی یک تابع استفاده می شود.

در این شماره، استفاده از Pixel XL برای گرفتن عکس HDR+ و سپس چرخاندن فوری منظره یاب هر بار باعث انحراف می‌شود. ما از نمایه ساز تابع برای رفع اشکال در کمتر از یک ساعت استفاده کردیم. برای ادامه مثال، فایل زیپ تریس ها را دانلود کنید (که شامل سایر ردپای های اشاره شده در این قسمت نیز می شود)، فایل را از حالت فشرده خارج کنید و فایل trace_30898724.html را در مرورگر خود باز کنید.

ردیابی چندین رشته در فرآیند سرور دوربین را نشان می دهد که در حالت خواب بی وقفه در ion_client_destroy مسدود شده اند. این یک تابع گران است، اما باید به ندرت فراخوانی شود زیرا مشتریان یونی باید تخصیص های زیادی را در بر گیرند. در ابتدا، تقصیر روی کد شش گوش در Halide بود که در واقع یکی از مقصران بود (برای هر تخصیص یون یک کلاینت جدید ایجاد کرد و زمانی که تخصیص آزاد شد، آن مشتری را از بین برد که بسیار گران بود). انتقال به یک کلاینت یونی برای همه تخصیص‌های شش‌ضلعی وضعیت را بهبود بخشید، اما jank ثابت نشد.

در این مرحله باید بدانیم چه کسی ion_client_destroy را فراخوانی می‌کند، بنابراین وقت آن است که از نمایه‌کننده تابع استفاده کنیم:

  1. از آنجایی که گاهی اوقات توابع توسط کامپایلر تغییر نام می‌دهند، تأیید کنید که ion_client_destroy وجود دارد با استفاده از:
    cat /sys/kernel/tracing/available_filter_functions | grep ion_client_destroy
    
  2. پس از تأیید وجود آن، از آن به عنوان فیلتر ftrace استفاده کنید:
    echo ion_client_destroy > /sys/kernel/tracing/set_ftrace_filter
    
  3. نمایه ساز عملکرد را روشن کنید:
    echo function > /sys/kernel/tracing/current_tracer
    
  4. هر زمان که یک تابع فیلتر فراخوانی می شود، ردیابی پشته را روشن کنید:
    echo func_stack_trace > /sys/kernel/tracing/trace_options
    
  5. افزایش اندازه بافر:
    echo 64000 > /sys/kernel/tracing/buffer_size_kb
    
  6. ردیابی را روشن کنید:
    echo 1 > /sys/kernel/tracing/trace_on
    
  7. تست را اجرا کنید و ردیابی را دریافت کنید:
    cat /sys/kernel/tracing/trace > /data/local/tmp/trace
    
  8. برای مشاهده تعداد زیادی رد پشته، ردیابی را مشاهده کنید:
        cameraserver-643   [003] ...1    94.192991: ion_client_destroy <-ion_release
        cameraserver-643   [003] ...1    94.192997: <stack trace>
     => ftrace_ops_no_ops
     => ftrace_graph_call
     => ion_client_destroy
     => ion_release
     => __fput
     => ____fput
     => task_work_run
     => do_notify_resume
     => work_pending
     

بر اساس بازرسی درایور یون، می‌توانیم ببینیم که ion_client_destroy توسط یک تابع userpace که یک fd را به /dev/ion می‌بندد، نه یک درایور هسته تصادفی، اسپم می‌شود. با جستجو در پایگاه کد اندروید برای \"/dev/ion\" ، چندین درایور فروشنده را می‌یابیم که همان کار درایور Hexagon را انجام می‌دهند و /dev/ion را باز/بسته می‌کنند (ایجاد و از بین می‌برند یک کلاینت یون جدید) هر بار که به یک مشتری نیاز دارند. تخصیص یون جدید با تغییر آن‌ها برای استفاده از یک کلاینت یونی برای طول عمر فرآیند، باگ برطرف شد.


اگر داده های تابع پروفایلر به اندازه کافی خاص نیست، می توانید نقاط ردیابی ftrace را با نمایه ساز تابع ترکیب کنید. رویدادهای ftrace را می توان دقیقاً به همان روش معمول فعال کرد و با ردیابی شما تداخل پیدا می کند. اگر گهگاه یک خواب بدون وقفه طولانی در یک تابع خاص وجود داشته باشد که می‌خواهید اشکال‌زدایی کنید، عالی است: فیلتر ftrace را روی تابعی که می‌خواهید تنظیم کنید، نقاط ردیابی را فعال کنید، ردیابی کنید. می‌توانید ردیابی به‌دست‌آمده را با trace2html تجزیه کنید، رویدادی را که می‌خواهید پیدا کنید، سپس ردیابی‌های پشته نزدیک را در ردیابی خام دریافت کنید.

از lockstat استفاده کنید

گاهی اوقات، ftrace کافی نیست و شما واقعاً نیاز به اشکال زدایی دارید که به نظر می رسد مناقشه قفل هسته است. یک گزینه هسته دیگر وجود دارد که ارزش امتحان کردن دارد: CONFIG_LOCK_STAT . این آخرین راه حل است، زیرا کار کردن بر روی دستگاه های اندرویدی بسیار دشوار است زیرا اندازه هسته را فراتر از آن چیزی است که اکثر دستگاه ها می توانند تحمل کنند.

با این حال، lockstat از زیرساخت قفل اشکال زدایی استفاده می کند که برای بسیاری از برنامه های دیگر مفید است. هرکسی که روی بالا بردن دستگاه کار می‌کند باید راهی پیدا کند تا آن گزینه روی هر دستگاهی کار کند، زیرا زمانی می‌رسد که فکر می‌کنید «اگر فقط می‌توانستم LOCK_STAT روشن کنم، می‌توانم به جای اینکه مشکل را در پنج دقیقه تأیید یا رد کنم. پنج روز."

در این شماره، رشته SCHED_FIFO زمانی که تمام هسته‌ها در حداکثر بار با رشته‌های غیر SCHED_FIFO بودند متوقف شد. ما ردپایی داشتیم که اختلاف قفل قابل توجهی را در یک fd در برنامه‌های VR نشان می‌داد، اما نمی‌توانستیم fd در حال استفاده را به راحتی شناسایی کنیم. برای دنبال کردن مثال، فایل زیپ Traces را دانلود کنید (که شامل سایر ردپای های اشاره شده در این بخش نیز می شود)، فایل را از حالت فشرده خارج کنید و فایل trace_30905547.html را در مرورگر خود باز کنید.

ما فرض کردیم که ftrace خود منبع جدال قفل است، زمانی که یک رشته با اولویت پایین شروع به نوشتن در لوله ftrace می کند و سپس قبل از اینکه بتواند قفل را آزاد کند، از پیش گرفته می شود. این بدترین سناریویی است که با ترکیبی از رشته‌های با اولویت بسیار پایین که روی نشانگر ftrace نوشته می‌شوند، همراه با چند رشته با اولویت بالاتر که روی CPU می‌چرخند برای شبیه‌سازی یک دستگاه کاملاً بارگذاری شده تشدید می‌شود.

از آنجایی که نمی‌توانستیم از ftrace برای اشکال‌زدایی استفاده کنیم، LOCK_STAT کار می‌کرد و سپس همه ردیابی‌های دیگر را از برنامه خاموش کردیم. نتایج نشان داد که جدال قفل در واقع از ftrace است زیرا هیچ یک از اختلافات در ردیابی قفل زمانی که ftrace در حال اجرا نبود نشان داده نمی شود.


اگر بتوانید یک هسته را با گزینه config بوت کنید، lock tracing شبیه ftrace است:

  1. فعال کردن ردیابی:
    echo 1 > /proc/sys/kernel/lock_stat
    
  2. تست خود را اجرا کنید
  3. غیرفعال کردن ردیابی:
    echo 0 > /proc/sys/kernel/lock_stat
    
  4. رد خود را رها کنید:
    cat /proc/lock_stat > /data/local/tmp/lock_stat
    

برای کمک به تفسیر خروجی به دست آمده، به مستندات lockstat در <kernel>/Documentation/locking/lockstat.txt مراجعه کنید.

از نقاط ردیابی فروشنده استفاده کنید

ابتدا از نقاط ردیابی بالادستی استفاده کنید، اما گاهی اوقات باید از نقاط ردیابی فروشنده استفاده کنید:

  { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
        { OPT,      "events/mdss/enable" },
        { OPT,      "events/sde/enable" },
        { OPT,      "events/mali_systrace/enable" },
    } },

نقاط ردیابی توسط سرویس HAL قابل گسترش هستند و به شما این امکان را می‌دهند که نقاط/دسته‌های ردیابی خاص دستگاه را اضافه کنید. نقاط ردیابی با perfetto، atrace/systrace و برنامه ردیابی سیستم روی دستگاه یکپارچه شده اند.

API ها برای پیاده سازی نقاط/دسته ها عبارتند از:

  • listCategories() دسته بندی (vec<TracingCategory>) را ایجاد می کند.
  • enableCategories(vec<string> category) ایجاد می کند (وضعیت وضعیت).
  • disableAllCategories() ایجاد می کند (وضعیت وضعیت)؛
برای اطلاعات بیشتر، به تعریف HAL ​​و پیاده سازی پیش فرض در AOSP مراجعه کنید: