این صفحه نمای کلیای از چارچوب دورسنجی هسته «فیلتر بسته برکلی توسعهیافته» (eBPF) در Android ارائه میدهد و معماری چارچوب، سنجههای داخلی، و نحوه افزودن سنجههای هسته جدید را شرح میدهد.
Android شامل چارچوب تلهمتری هسته eBPF یکپارچه برای جمعآوری
سنجههای هسته با سربار کم و نمایان کردن آن سنجهها برای سرویسهای فضای کاربر
مثل statsd است. با پیوست کردن برنامههای قابلحمل eBPF به نقاط ردیابی هسته و
kprobes، چارچوب رویدادهای هسته با بسامد بالا را درجا تجمیع میکند و
هیستوگرامها یا شمارندههای فشرده را بدون تغییر دادن
تصویر هسته عمومی (GKI) یا شکستن «میانای واحد هسته» (KMI) صادر میکند.
رویکردهای سنتی به تلهمتری هسته به procfs یا sysfs
گرههای سفارشی، وصلههای هسته خارج از درخت، یا قلابهای فروشنده که نیازمند لولهکشی سفارشی
در سراسر هسته، SELinux، میانای بومی جاوا (JNI)، و سرویسهای فضای کاربر هستند، متکی است.
چارچوب دورسنجی هسته eBPF این خط لوله را در سراسر هستههای مشترک Android (ACK) استاندارد میکند و مزایای زیر را ارائه میدهد:
- از تلاطم KMI و ABI هسته جلوگیری میکند: برنامههای eBPF را به نقاط ردیابی هسته یا kprobes موجود متصل میکند بدون اینکه کد منبع هسته را اصلاح کند، میانای دودویی کاربردی (ABI) هسته را تغییر دهد، یا قلابهای فروشنده Android مانند
TRACE_ANDROID_VH_*را اضافه کند. سازندگان دستگاه و شرکای سیستم روی تراشه (SoC) میتوانند بهجای افزودن قلابهای جدید فروشنده تلهمتری یا برای انتقال از قلابهای فروشنده موجود، از تلهمتری eBPF استفاده کنند. - قابلیت حمل بین نسخههای هسته را حفظ میکند: از BPF Compile Once -
Run Everywhere (CO-RE) و BPF Type Format (BTF) استفاده میکند تا یک برنامه eBPF کامپایلشده واحد بهطور خودکار با تغییرات چیدمان ساختار هسته داخلی در نسخههای GKI، مانند
android14-6.1و بالاتر، سازگار شود. - سربار سلامت سیستم را بهحداقل میرساند: رویدادهای هسته با بسامد بالا را مستقیماً در منبع به هیستوگرامهای فشرده ۳۲ سطلی لگاریتمی در مبنای ۲ (
log2) فیلتر و تجمیع میکند، معمولاً کمتر از ۱ کیلوبایت در هر نقشه BPF. فضای کاربر ورودیهای نقشه انبوهشی را یکبار در روز بااستفاده از یکBPF_MAP_LOOKUP_BATCHفراخوانی سیستمی دستهای بازیابی میکند. - ادغام SELinux و JNI را ساده میکند: نقشههای تلهمتری را در
/sys/fs/bpf/kernelstats/سنجاق میکند تا وراثت نوع SELinux سطح دایرکتوریfs_bpf_kernelstatsاعمال شود و جابهجاییهای عضو ساختار را در زمان اجرا در JNI بااستفاده از فراداده BTF حل میکند تا کد تجزیه سفارشی C++ هنگام افزودن سنجههای جدید حذف شود.
برای کسب اطلاعات بیشتر درباره نحوه بار کردن و سنجاق کردن برنامهها و نقشههای eBPF توسط Android، به گسترش هسته با eBPF مراجعه کنید.
نمای کلی معماری
خط لوله دورسنجی هسته eBPF مؤلفههای زیرساخت عمومی را از تعاریف خاص سنجه جدا میکند تا افزودن سنجه هسته جدید به حداقل تغییرات کد نیاز داشته باشد. جدول زیر اجزای خط لوله را شرح میدهد:
| مؤلفه | نقش در خط لوله | حوزه |
|---|---|---|
بارکننده BPF، bpfloader | برنامههای eBPF کامپایلشده را از /system/etc/bpf/kernelstats/ در زمان راهاندازی بار میکند (اگر با هسته درحال اجرا سازگار باشد) و نقشهها را به /sys/fs/bpf/kernelstats/ سنجاق میکند. وقتی غیرفعال یا پشتیبانینشده باشد، از بار کردن تمیز رد میشود. | Generic |
خطمشی SELinux، fs_bpf_kernelstats | برچسبهای SELinux سطح دایرکتوری را به /sys/fs/bpf/kernelstats/ اعمال میکند تا system_server بتواند نقشههای تلهمتری را بدون بهروزرسانیهای خطمشی SELinux بهازای هر سنجه بخواند. | Generic |
برنامه eBPF در system/bpfprogs/telemetry/ | به نقطههای ردیابی هسته یا kprobes پیوست میشود، رویدادها را فیلتر میکند، و معیارها را در نقشههای BPF تجمیع میکند. | سفارشی براساس سنجه |
| خوانشگر JNI BTF | فراداده BTF را از کد باینری «قالب اجرایی و پیوندپذیر BPF» (ELF) کامپایلشده در زمان اجرا تجزیه میکند، جابهجاییهای عضو ساختار را در حافظه نهان ذخیره میکند، و خواندن دستهای نقشه را در آرایههای اولیه جاوا انجام میدهد. | Generic |
کشنده فضای کاربر در statsd | نقشههای هیستوگرام تجمعی را در یک برنامه روزانه میکشد، دلتاها را دربرابر سابقه ذخیرهشده در حافظه پنهان محاسبه میکند، و اتمهای کششی StatsEvent با نوع قوی میسازد. | یاریرسان عمومی با یک ورودی case در هر اتم |
| طرح دورسنجی | statsd اتم کششی با نوع قوی protobuf و هیستوگرام سمت سرور یا تجمیع سنجه مقدار را تعریف میکند. | سفارشی براساس سنجه |
مدلهای مصرف فضای کاربر
هنگام طراحی سنجه دورسنجی هسته، بسته به اینکه سنجه نشاندهنده وضعیت تجمعی است یا توالی رویداد مرتبشده، بین دو مدل مصرف فضای کاربر انتخاب کنید. جدول زیر این دو مدل را مقایسه میکند:
| دارایی | انباشتگرها | جاریسازیها |
|---|---|---|
| تعریف | شمارندهها یا هیستوگرامهای تجمعی حالتدار و یکنواخت افزایشی | توالی مرتبشده رویدادهای هسته با مُهر زمان |
| الگوی دسترسی | فضای کاربر درصورت درخواست، مثلاً هر ۲۴ ساعت یکبار ازطریق statsd، نظرسنجی میکند | فضای کاربر بهطور مداوم از میانگیر حلقهای مصرف میکند تا از رویدادهای حذفشده جلوگیری کند |
| انواع نقشه BPF معمولی | BPF_MAP_TYPE_HASH، BPF_MAP_TYPE_LRU_HASH، BPF_MAP_TYPE_PERCPU_HASH، BPF_MAP_TYPE_LRU_PERCPU_HASH | BPF_MAP_TYPE_RINGBUF |
| مدل همرس | جستجوی نقشه هسته اتمی است؛ چندین خواننده میتوانند بدون قفل کردن فضای کاربر نظرسنجی کنند | معناشناسی خواندن مخرب به یک رشته خواننده واحد نیاز دارد که به مصرفکنندگان ارسال شود |
| نمونه موارد استفاده | هیستوگرامهای تأخیر مدیریت حافظه، اندازههای تخصیص «میانگیر دسترسی مستقیم به حافظه» (DMA-BUF)، تکرارکنندههای منبع بیداری | رویدادهای ردیابی زمانبندی فیلترشده، ردیابیهای توان زیرسیستم با فرکانس بالا |
سنجههای دورسنجی هسته داخلی
Android شامل برنامههای تلهمتری هسته eBPF داخلی است که در سراسر هستههای GKI نسخه ۶.۱ و بالاتر، ازجمله android14-6.1، android15-6.6، android16-6.12، و android17-6.18 کار میکنند. هر سنجه تأخیر و اندازه از یک
هیستوگرام نمایی ۳۲ سطلی (log2) استفاده میکند که در یک پنجره ۲۴ ساعته جمعآوری شده است. جدول زیر سنجههای تلهمتری هسته داخلی را فهرست میکند:
| اتم سنجه | زیرسیستم | شرح | کلید بُعد |
|---|---|---|---|
KswapdLatency | مدیریت حافظه | Kernel swap daemon, kswapd, wake-to-sleep execution latency in microseconds | دسترسی غیریکنواخت به حافظه (NUMA) node_id |
DirectReclaimLatency | مدیریت حافظه | تأخیر بازیابی حافظه مستقیم همگام برحسب میکروثانیه | پردازش وضعیت oom_score_adj کمبود حافظه (OOM) |
CompactionDuration | مدیریت حافظه | مدت زمان اجرای فشردهسازی حافظه در سراسر سیستم برحسب میکروثانیه، جایگزین قلابهای فروشنده فشردهسازی قدیمی | سراسری |
CmaAllocationLatency | مدیریت حافظه | تأخیر تخصیص صفحه «تخصیصدهنده حافظه پیوسته» (CMA) برحسب میکروثانیه | نام پشته CMA |
DmabufRequestSizes | مدیریت حافظه | اندازههای درخواست تخصیص DMA-BUF به بایت | نام انباره صادرکننده |
SuspendResumeLatency | مدیریت شارژ باتری | تأخیر در مراحل تعلیق و ازسرگیری هسته به میکروثانیه | مرحله کنش تعلیق |
افزودن سنجه دورسنجی هسته
برای افزودن سنجه انباشتگر جدید به خط لوله تلهمتری هسته eBPF، مراحل زیر را به ترتیب تکمیل کنید:
- برنامه eBPF را در
system/bpfprogs/telemetry/بنویسید و باینری را در/system/etc/bpf/kernelstats/بسازید. - بررسی سازگاری طرحبندی ساختار BTF برای خواننده JNI BTF عمومی.
- اتم pull را در
statsdثبت کنید. - طرحواره protobuf اتم کشش را تعریف کنید.
بخشهای زیر از DirectReclaimLatency (directReclaim.c) بهعنوان مثال استفاده میکنند.
نوشتن برنامه eBPF
در system/bpfprogs/telemetry/، <bpf_telemetry.h> را اضافه کنید و کلید نقشه و نقشه انباشتگر خروجی را تعریف کنید. برای بهحداقل رساندن ردپای حافظه نقشه و حفظ حریم خصوصی،
از شناسههای عدد صحیح یا شمارشی در کلیدهای نقشه BPF بهجای رشتههای خام استفاده کنید:
#include <android_bpf_defs.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf_telemetry.h>
#include <stdint.h>
struct direct_reclaim_key {
uint32_t process_state;
};
#define DIRECT_RECLAIM_START_MAP_ENTRIES 128
#define DIRECT_RECLAIM_OUTPUT_MAP_ENTRIES 8
// Temporary map to store start time. Key: pid (thread_id), Value: start_time_ns
DEFINE_BPF_MAP_GRO(direct_reclaim_start_map, HASH, uint32_t, uint64_t,
DIRECT_RECLAIM_START_MAP_ENTRIES, AID_SYSTEM);
// Output map. Key: direct_reclaim_key, Value: accumulator_value (32 log2 buckets)
DEFINE_BPF_MAP_GRO(direct_reclaim_latency_map, HASH, struct direct_reclaim_key,
struct accumulator_value, DIRECT_RECLAIM_OUTPUT_MAP_ENTRIES,
AID_SYSTEM);
در گردانندههای نقطه ردیابی، مُهر زمان شروع را در ورودی ثبت کنید،
log2 سطل تأخیر را در خروجی بااستفاده از GET_LATENCY_BUCKET محاسبه کنید، و
ورودی نقشه انباشتگر را با INCREMENT_ACCUMULATOR افزایش دهید:
DEFINE_BPF_PROG("tp_btf/mm_vmscan_direct_reclaim_begin", AID_ROOT, AID_SYSTEM,
tracepoint_vmscan_mm_vmscan_direct_reclaim_begin)(
uint64_t* args) {
(void)args;
uint32_t pid = (uint32_t)bpf_get_current_pid_tgid();
SAVE_FIRST_START_TIME(direct_reclaim_start_map, &pid);
return 0;
}
DEFINE_BPF_PROG("tp_btf/mm_vmscan_direct_reclaim_end", AID_ROOT, AID_SYSTEM,
tracepoint_vmscan_mm_vmscan_direct_reclaim_end)(
uint64_t* args) {
(void)args;
uint32_t pid = (uint32_t)bpf_get_current_pid_tgid();
uint32_t bucket = GET_LATENCY_BUCKET(direct_reclaim_start_map, &pid);
if (bucket == BPF_TELEMETRY_INVALID_BUCKET) return 0;
struct task_struct* task = (struct task_struct*)bpf_get_current_task();
int oom_score_adj = BPF_CORE_READ(task, signal, oom_score_adj);
enum process_state state = get_process_state(oom_score_adj);
struct direct_reclaim_key key = {.process_state = (uint32_t)state};
INCREMENT_ACCUMULATOR(direct_reclaim_latency_map, &key, bucket);
return 0;
}
درستیسنجی سازگاری چیدمان ساختار BTF
هنگام افزودن نقشه هیستوگرام جدید، تا زمانی که ساختارهای مقدار و کلید نقشه شما از انواع عدد صحیح استاندارد، شمارشی، و آرایه ثابت استفاده کنند، نیازی به نوشتن کد C++ سفارشی JNI ندارید. بهجای تبدیل ورودیهای نقشه BPF به ساختارهای C کدگذاریشده در زمان ترجمه، خواننده JNI عمومی طرحبندیهای ساختار را بهطور پویا در زمان اجرا در سه مرحله حل میکند:
- ارتباط ELF-to-map: لایه JNI فراداده BTF را مستقیماً از
فایل BPF ELF کامپایلشده در دیسک، مانند
/system/etc/bpf/kernelstats/directReclaim.bpf، بااستفاده از تابعlibbpfbtf__parseتجزیه میکند. - وضوح نوع BTF: در اولین دسترسی، خواننده یک نمایش ساختاری از ساختارهای C کلید و مقدار نقشه را میسازد و ذخیره میکند، و افستهای بایت تجمعی را برای اعضای ساختار، عرضهای بایت عدد صحیح و enum، و اندازههای عنصر آرایه از اشارهگر پایه محاسبه میکند.
- جستجوی دستهای و سریالسازی: وقتی
statsdنقشه را میکشد، لایه JNI یک فرمانBPF_MAP_LOOKUP_BATCHبه سیستمفراخوانsys_bpfصادر میکند تا همه ورودیهای درهمسازی را بهصورت انبوه بخواند و شناسههای کلید حلوفصلشده و آرایههای سطلی را مستقیماً در آرایههایlong[]اولیه جاوا بااستفاده از تابعSetLongArrayRegionJNI کپی میکند.
اگر ساختار BPF C در نسخه پخش بعدی تغییر کند، بخش BTF بازکامپایلشده بهطور خودکار بهروزرسانی میشود و خواننده JNI در زمان اجرا بدون نیاز به بازکامپایل JNI تطبیق پیدا میکند.
ثبت اتم کشش در statsd
در StatsPullAtomService.java، دستیار عمومی pullKernelTelemetry نقشه BPF سنجاقشده را میخواند،
تغییرات دلتای دستهها را دربرابر تعداد ذخیرهشده در حافظه نهان کشش قبلی محاسبه میکند،
و StatsEvent ورودی منتشر میکند. افزودن سنجه دورسنجی هسته جدید
فقط به سه مورد اضافه کوچک نیاز دارد:
// 1. Dispatch the atom tag to pullKernelTelemetry() in onPullAtomLocked():
case FrameworkStatsLog.DIRECT_RECLAIM_LATENCY:
return pullKernelTelemetry(atomTag, data);
// 2. Add the atom tag to the registered atoms list in registerKernelTelemetry():
int[] atoms = {
FrameworkStatsLog.DIRECT_RECLAIM_LATENCY,
// ...
};
// 3. Map the atom tag to its pinned BPF map path:
case FrameworkStatsLog.DIRECT_RECLAIM_LATENCY ->
"/sys/fs/bpf/kernelstats/map_directReclaim_direct_reclaim_latency_map";
تعریف کردن پروتوباف اتم کششی
پیام اتم کششی با نوع قوی را در frameworks/proto_logging/ تعریف کنید تا
با کلید بُعد و آرایه هیستوگرام log2 ۳۲-سطل تولیدشده توسط
نقشه BPF مطابقت داشته باشد:
message DirectReclaimLatency {
enum ProcessState {
PROCESS_STATE_UNSPECIFIED = 0;
STATE_NATIVE = 1;
STATE_SYSTEM = 2;
STATE_PERSISTENT = 3;
STATE_FOREGROUND = 4;
STATE_VISIBLE = 5;
STATE_PERCEPTIBLE = 6;
STATE_SERVICE_BACKGROUND = 7;
STATE_CACHED = 8;
}
optional ProcessState process_state = 1;
repeated int32 duration_log2_buckets_micros = 2;
}