Perfetto 翻譯第十一篇-數(shù)據(jù)來源-內(nèi)存的計數(shù)和事件

前言:雖然有翻譯軟件秧倾,雖然有chatgpt,畢竟語言隔閡,對這個工具還是一知半解衣陶,因此想通過翻譯的方式和大家來一起學(xué)習(xí)下Perfetto這個強大的工具

目錄

#####################以下分割線#####################
英文原文在這里
Perfetto可以從Android和Linux上收集大量內(nèi)存相關(guān)的事件和計數(shù)器财饥。這些事件來自內(nèi)核接口,包括ftrace和/proc接口务嫡,有兩種類型:輪詢計數(shù)器和內(nèi)核在ftrace緩沖區(qū)中推送的事件甲抖。

進程輪詢計數(shù)器

進程統(tǒng)計數(shù)據(jù)源允許以用戶定義的間隔輪詢/proc/<pid>/status和/proc/<pid>/oom_score_adj。

參見man 5 proc了解其語義心铃。

UI
proc_stat.png

SQL

select c.ts, c.value, t.name as counter_name, p.name as proc_name, p.pid
from counter as c left join process_counter_track as t on c.track_id = t.id
left join process as p using (upid)
where t.name like 'mem.%'
memory_1.png
TraceConfig

如果需要每X毫秒收集一次進程統(tǒng)計計數(shù)器准谚,請在進程統(tǒng)計配置中設(shè)置proc_stats_poll_ms=X。X必須大于100ms去扣,以避免過度使用CPU柱衔。有關(guān)正在收集的特定計數(shù)器的詳細(xì)信息,請參閱ProcessStats reference.。

data_sources: {
    config {
        name: "linux.process_stats"
        process_stats_config {
            scan_all_processes_on_start: true
            proc_stats_poll_ms: 1000
        }
    }
}
進程內(nèi)存事件 (ftrace)
rss_stat

最新版本的Linux內(nèi)核允許在Resident Set Size(RSS)mm計數(shù)器更新時通知ftrace事件唆铐。這是/proc/pid/status即VmRSS使用相同的計數(shù)器哲戚。rss_stat事件的主要優(yōu)點是,作為一個事件驅(qū)動的推送事件艾岂,它可以檢測非常短的內(nèi)存使用突發(fā)顺少,而使用/proc計數(shù)器將無法檢測到這些突發(fā)。

數(shù)百MB的內(nèi)存使用峰值可能會對安卓系統(tǒng)產(chǎn)生巨大的負(fù)面影響澳盐,即使它們只持續(xù)幾毫秒祈纯,因為它們可能會導(dǎo)致大量內(nèi)存不足,從而回收內(nèi)存叼耙。

這個功能在 b3d1411b6中的Linux內(nèi)核中引入腕窥,后來通過e4dcad20進行了改進。它們在Linux v5.5-rc1之后的之后版本中可用筛婉。該補丁已在運行Android 10(Q)的幾個Google Pixel內(nèi)核中進行了移植簇爆。

mm_event

mm_event是一個ftrace事件,它捕獲關(guān)鍵內(nèi)存事件(/proc/vmstat公開的事件的子集)的統(tǒng)計信息爽撒。與RSS統(tǒng)計計數(shù)器更新不同入蛆,mm事件的數(shù)量非常大,單獨跟蹤它們是不可行的硕勿。mm_event只報告跟蹤中的周期性直方圖哨毁,從而顯著降低了開銷。

mm_event僅在一些運行Android 10(Q)及更高版本的Google Pixel內(nèi)核上可用源武。

啟用mm_event時扼褪,將記錄以下mm事件類型:

  • mem.mm.min_flt: Minor page faults

  • mem.mm.maj_flt: Major page faults

  • mem.mm.swp_flt: Page faults served by swapcache

  • mem.mm.read_io: Read page faults backed by I/O

  • mem.mm..compaction: Memory compaction events

  • mem.mm.reclaim: Memory reclaim events

對于每種事件類型,事件記錄:

count:自上次事件以來粱栖,事件發(fā)生的次數(shù)话浇。

min_lat:自上次事件以來記錄的最小延遲(mm事件的持續(xù)時間)。

max_lat:自上次事件以來記錄的最高延遲闹究。

UI
rss_stat_and_mm_event.png
SQL

在SQL級別幔崖,這些事件的導(dǎo)入和導(dǎo)出方式與相應(yīng)的輪詢事件相同。這允許收集兩種類型的事件(推送和輪詢)渣淤,并在查詢和腳本中統(tǒng)一處理它們

select c.ts, c.value, t.name as counter_name, p.name as proc_name, p.pid
from counter as c left join process_counter_track as t on c.track_id = t.id
left join process as p using (upid)
where t.name like 'mem.%'
memory_2.png
TraceConfig

要啟用對LMK的跟蹤赏寇,請在trace config中添加以下選項:

data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            ftrace_events: "kmem/rss_stat"
            ftrace_events: "mm_event/mm_event_record"
        }
    }
}

# This is for getting Thread<>Process associations and full process names.
data_sources: {
    config {
        name: "linux.process_stats"
    }
}
全系統(tǒng)輪詢計數(shù)器

此數(shù)據(jù)源允許從以下位置定期輪詢系統(tǒng)數(shù)據(jù):

/proc/stat

/proc/vmstat

/proc/meminfo`

參見 man 5 proc了解其語義。

UI

可以在trace config中設(shè)置要包含在trace中的輪詢周期和特定計數(shù)器价认。

SQL
select c.ts, t.name, c.value / 1024 as value_kb from counters as c left join counter_track as t on c.track_id = t.id
memory_3.png
TraceConfig

TraceConfig reference查看所支持的計數(shù)器

data_sources: {
    config {
        name: "linux.sys_stats"
        sys_stats_config {
            meminfo_period_ms: 1000
            meminfo_counters: MEMINFO_MEM_TOTAL
            meminfo_counters: MEMINFO_MEM_FREE
            meminfo_counters: MEMINFO_MEM_AVAILABLE

            vmstat_period_ms: 1000
            vmstat_counters: VMSTAT_NR_FREE_PAGES
            vmstat_counters: VMSTAT_NR_ALLOC_BATCH
            vmstat_counters: VMSTAT_NR_INACTIVE_ANON
            vmstat_counters: VMSTAT_NR_ACTIVE_ANON

            stat_period_ms: 1000
            stat_counters: STAT_CPU_TIMES
            stat_counters: STAT_FORK_COUNT
        }
    }
}
LMK
背景

在內(nèi)存緊張的時候 蹋订,Android framework會殺死應(yīng)用程序和服務(wù),尤其是后臺應(yīng)用程序刻伊,以便在需要內(nèi)存時為新打開的應(yīng)用程序騰出空間。這些被稱為LMK。

值得注意的是捶箱,發(fā)生LMK并不意味著有性能問題智什。經(jīng)驗法則是,嚴(yán)重程度(如:用戶感知的影響)與應(yīng)用程序被殺的狀態(tài)成正比丁屎。應(yīng)用程序狀態(tài)可以從OOM調(diào)整分?jǐn)?shù)的軌跡中導(dǎo)出荠锭。

LMK殺死前臺應(yīng)用程序或服務(wù)通常是一個大問題。因為這意味著用戶在操作app時晨川,忽然app 就被殺掉了证九,或者正在播放的音樂忽然就被停止了。

相反共虑,如果是緩存的應(yīng)用程序或服務(wù)被LMK愧怜,這是通常發(fā)生的情況。在大多數(shù)情況下用戶并不會注意到妈拌,被緩存的應(yīng)用程序被殺掉拥坛,只是回到應(yīng)用程序的時候發(fā)生一次冷啟動。

介于這兩個極端之間的情況更加微妙尘分。如果短時間之內(nèi)猜惋,緩存的應(yīng)用程序/服務(wù)都被LMK殺掉(即觀察到大多數(shù)進程在短時間內(nèi)得到LMK),并且通常是系統(tǒng)某些組件導(dǎo)致內(nèi)存峰值的表現(xiàn)培愁,那么它可能是個問題著摔。

lowmemorykiller vs lmkd

內(nèi)核LMK 驅(qū)動

在Android中,LMK曾經(jīng)由一個特殊的內(nèi)核驅(qū)動程序處理定续,即Linux的drivers/staging/android/lowmemorykiller.c谍咆。該驅(qū)動程序會在trace中發(fā)出ftrace事件lowmemorykill/lowmemory_kill。

用戶空間的lmkd

安卓9引入了一個用戶空間的原生守護進程香罐,接管了LMK的職責(zé):lmkd卧波。并不是所有運行Android 9的設(shè)備都必須使用lmkd,因為內(nèi)核內(nèi)與用戶空間的最終選擇取決于手機制造商使用內(nèi)核版本和內(nèi)核配置庇茫。

在谷歌Pixel手機上港粱,自從Pixel 2運行Android 9以來,就使用了lmkd旦签。

看見https://source.android.com/devices/tech/perf/lmkd詳細(xì)信息查坪。

lmkd發(fā)出一個名為kill_one_process的用戶空間的atrace計數(shù)器事件。

android 的lmk和Linux 的oomkiller

安卓系統(tǒng)上的LMK宁炫,無論是舊的內(nèi)核lmk還是新的lmkd偿曙,都使用與標(biāo)準(zhǔn)Linux內(nèi)核的OOM Killer完全不同的機制。Perfetto目前只支持Android LMK事件(在內(nèi)核和用戶空間中)羔巢,不支持跟蹤Linux內(nèi)核OOM Killer事件望忆。Linux OOM Killer事件理論上在Android上仍然是可能的罩阵,但極不可能發(fā)生。如果發(fā)生這種情況启摄,則更有可能是BSP配置錯誤的癥狀稿壁。

UI

較新的用戶空間LMK以計數(shù)器的形式出現(xiàn)在lmkd 軌跡下的UI中。計數(shù)器值是終止進程的PID(在下面的示例中歉备,PID=27985)傅是。


lmk_lmkd.png

TODO: we are working on a better UI support for LMKs.

SQL

較新的lmkd和舊版本內(nèi)核驅(qū)動的LMK事件,都會在導(dǎo)入時進行格式化蕾羊,并在instants表中的mem.lmk鍵下可用喧笔。

SELECT ts, process.name, process.pid 
FROM instant 
JOIN process_track ON instant.track_id = process_track.id
JOIN process USING (upid)
WHERE instant.name = 'mem.lmk'
memory_4.png
TraceConfig

要啟用對LMK的跟蹤,請在trace config中添加以下選項:

data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            # For old in-kernel events.
            ftrace_events: "lowmemorykiller/lowmemory_kill"

            # For new userspace lmkds.
            atrace_apps: "lmkd"

            # This is not strictly required but is useful to know the state
            # of the process (FG, cached, ...) before it got killed.
            ftrace_events: "oom/oom_score_adj_update"
        }
    }
}
app運行狀態(tài)和OOM分?jǐn)?shù)調(diào)整

Android應(yīng)用程序狀態(tài)可以在進程oom_score_adj的跟蹤中推斷出來龟再。但映射不是1:1书闸,狀態(tài)比oom_score_adj值多,緩存進程的oom_score _adj范圍從900到1000吸申。

映射可以從 ActivityManager's ProcessList sources找到

// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 999;
static final int CACHED_APP_MIN_ADJ = 900;

// This is the oom_adj level that we allow to die first. This cannot be equal to
// CACHED_APP_MAX_ADJ unless processes are actively being assigned an oom_score_adj of
// CACHED_APP_MAX_ADJ.
static final int CACHED_APP_LMK_FIRST_ADJ = 950;

// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 800;

// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app.  This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 700;

// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 600;

// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 500;

// This is a process with a heavy-weight application.  It is in the
// background, but we want to try to avoid killing it.  Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 400;

// This is a process currently hosting a backup operation.  Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 300;

// This is a process bound by the system (or other app) that's more important than services but
// not so perceptible that it affects the user immediately if killed.
static final int PERCEPTIBLE_LOW_APP_ADJ = 250;

// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 200;

// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 100;

// This is a process that was recently TOP and moved to FGS. Continue to treat it almost
// like a foreground app for a while.
// @see TOP_TO_FGS_GRACE_PERIOD
static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

// This is the process running the current foreground app.  We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;

// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
static final int PERSISTENT_SERVICE_ADJ = -700;

// This is a system persistent process, such as telephony.  Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -800;

// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -900;

// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -1000;

#####################以上分割線#####################

后記:
1 本次主要使用百度翻譯梗劫,雖然被罵,但至少翻譯這個工具降低了門檻截碴。
2 英文文檔中的長難句真的是又長又難梳侨,基于百度的翻譯,然后自己再調(diào)整下日丹,水平實在有限走哺。
3 技術(shù)背景知識不夠,有些專有名詞不知道怎么翻譯哲虾,也不知道百度翻譯的是否準(zhǔn)確丙躏,功夫在詩外。
4 萬事開頭難束凑,中間難不難晒旅,還不知道。中間的事后面再說汪诉,正確一天翻譯一篇废恋。
5 雖然可能會有人不屑,但總要有人去做不起眼的小事扒寄。
6 google 厲害鱼鼓,這個perfetto 工具也很厲害。君子善假于物也该编。
7 工具的使用是最簡單的入門迄本,背后還有更多的東西值得學(xué)習(xí)。
8 水平實在有限课竣,聞過則喜嘉赎,希望有更多的人反饋置媳,期待更好的建議

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市曹阔,隨后出現(xiàn)的幾起案子半开,更是在濱河造成了極大的恐慌,老刑警劉巖赃份,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異奢米,居然都是意外死亡抓韩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門鬓长,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谒拴,“玉大人,你說我怎么就攤上這事涉波∮⑸希” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵啤覆,是天一觀的道長苍日。 經(jīng)常有香客問我,道長窗声,這世上最難降的妖魔是什么相恃? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮笨觅,結(jié)果婚禮上拦耐,老公的妹妹穿的比我還像新娘。我一直安慰自己见剩,他們只是感情好杀糯,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苍苞,像睡著了一般固翰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柒啤,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天倦挂,我揣著相機與錄音,去河邊找鬼担巩。 笑死方援,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涛癌。 我是一名探鬼主播犯戏,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼送火,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了先匪?” 一聲冷哼從身側(cè)響起种吸,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呀非,沒想到半個月后坚俗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡岸裙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年猖败,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片降允。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡恩闻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剧董,到底是詐尸還是另有隱情幢尚,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布翅楼,位于F島的核電站尉剩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏犁嗅。R本人自食惡果不足惜边涕,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褂微。 院中可真熱鬧功蜓,春花似錦、人聲如沸宠蚂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽求厕。三九已至著隆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間呀癣,已是汗流浹背美浦。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留项栏,地道東北人浦辨。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像沼沈,于是被迫代替她去往敵國和親流酬。 傳聞我的和親對象是個殘疾皇子币厕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容