Android系統(tǒng)Cortex-A57 內(nèi)核壓力測試連續(xù)震蕩性內(nèi)存泄漏導(dǎo)致OOM Killer
硬件平臺
公司自研 ARM Cortex-A57 4核 SOC 產(chǎn)品板軟件環(huán)境
系統(tǒng): Android-P
Linux內(nèi)核版本: 4.9
運行公司內(nèi)部的Linux內(nèi)核壓力測試腳本,通過內(nèi)存工具抓取物理內(nèi)存使用率的情況-
現(xiàn)象描述
系統(tǒng)內(nèi)存使用率的情況如圖谷徙,該圖是連續(xù)24小時Linux 內(nèi)核壓力測試的物理內(nèi)存使用率的情況拒啰,藍色的點代表不運行壓力測試的時候正常的內(nèi)存使用率,紅色的點代表運行內(nèi)核壓力測試時物理內(nèi)存使用率上下震蕩完慧,緩慢上升谋旦,在16小時左右發(fā)生了low memory killer (oom killer) 導(dǎo)致系統(tǒng)很多后臺服務(wù)被殺死,內(nèi)存使用率斷崖式下滑
- Root Cause
Linux內(nèi)核某個模塊的驅(qū)動代碼是這樣寫的屈尼,
int bug_driver(struct bug_dev *dev)
{
struct foo *bar = NULL;
bar = kzalloc(sizeof(struct foo)) ;
if (bar) {
kfree(dev->spec);
dev->spec = bar;
bar = NULL;
return 0;
}
return -1;
}
這段代碼看起來沒有導(dǎo)致內(nèi)存泄漏册着,因為舊的dev->spec指針先kfree()之后,重新保存了kzalloc()分配的內(nèi)存脾歧,下次運行到這里的時候甲捏,會先釋放舊的,再獲取新的內(nèi)存鞭执,不會泄漏司顿。
但是大公司,分工比較細兄纺,一個驅(qū)動模塊可能很多個人進來修改過大溜,另外一個工程師在這個函數(shù)上層的某個地方寫了一段這樣的代碼:
struct bug_dev dev;
bug_driver(&dev);
....................一大段代碼省略...................................
memset(&dev, 0x00, sizeof(struct bug_dev));
dev.spec = kmalloc(sizeof(struct bug_dev))
因為這段代碼直接把通過bug_driver()函數(shù)獲取的bug_dev->spec指針意外得memset()再重新分配了,因而下次再調(diào)用bug_driver(&dev) 函數(shù)時估脆,在里面kfree(dev->spec)的指針并不是上一次的kzalloc()的bar指針,上一次kzalloc()的bar指針徹底變成孤魂野鬼未引用對象存在內(nèi)核里面疙教,久而久之內(nèi)存使用率就上去了,造成了內(nèi)存泄漏
該內(nèi)存泄漏導(dǎo)致oom killer需要16小時才復(fù)現(xiàn)葵诈,每次泄漏2KB其實很少作喘,而且該內(nèi)核壓力測試腳本本身運行時就有內(nèi)存使用上下震蕩波動泞坦,因而幾分鐘之內(nèi)的實驗是看不出有內(nèi)存泄漏的
- 解決過程總結(jié)
- 剛開始跑壓力測試的工程師反饋回來的是oom killer的問題,需要16小時復(fù)現(xiàn)豌熄, 我只能一邊分析log一邊拿著腳本繼續(xù)跑復(fù)現(xiàn)锣险。
- 我看著log有一大段內(nèi)存使用率的打印芯肤,于是突發(fā)奇想用最近學(xué)的python matplotlib畫圖功能把內(nèi)存使用率的數(shù)據(jù)都抓出來,畫成散點圖, 看看能不能擬合出什么晴弃,畫出來之后就看到了內(nèi)存使用率緩慢震蕩上升的趨勢
- 在內(nèi)核中打開了kmemleak工具际邻,改了一下壓力測試腳本世曾,每跑一次壓力測試之后轮听,就scan一次kememleak的情況萧锉,記錄log柿隙, 通過kmemleak工具打印出來的stack找到了內(nèi)存泄漏的函數(shù)
- 一開始看泄漏的函數(shù)禀崖,發(fā)現(xiàn)第一段代碼挺正常,有記得free之前的指針昼钻,看不出內(nèi)存泄漏的情況折晦,直到后面加了一點打印满着,打出每次kzalloc()分配的指針的具體地址和kfree()釋放的具體指針地址风喇,發(fā)現(xiàn)與差異,然后全局檢查代碼其它地方的調(diào)用耙考,終于發(fā)現(xiàn)這套函數(shù)調(diào)用邏輯的bug所在倦始,不同的工程師寫的代碼鞋邑,互相之間不知道對方做了哪些細節(jié)調(diào)用逾一,遂導(dǎo)致這個內(nèi)存泄漏遵堵。
Android系統(tǒng)Cortex-A57 Android Framework 反復(fù)stop/start 導(dǎo)致內(nèi)存碎片鄙早,內(nèi)存占用率連續(xù)震蕩性升高最終引發(fā)oom killer
硬件平臺
公司自研 ARM Cortex-A57 4核 SOC 產(chǎn)品板軟件環(huán)境
系統(tǒng): Android-P
Linux內(nèi)核版本: 4.9
運行公司內(nèi)部的Linux內(nèi)核壓力測試腳本,通過內(nèi)存工具抓取物理內(nèi)存使用率的情況-
現(xiàn)象描述
系統(tǒng)內(nèi)存使用率的情況如圖呀舔,物理內(nèi)存使用率上下震蕩,緩慢上升惧磺,該圖是連續(xù)24小時Linux 內(nèi)核壓力測試的物理內(nèi)存使用率的情況磨隘,通過縮小范圍番捂,修復(fù)內(nèi)存泄露問題之后,發(fā)現(xiàn)壓力測試反復(fù)調(diào)用Android Framework的stop / start 命令引發(fā)內(nèi)存使用率升高鳖枕,導(dǎo)致oom killer宾符。從該圖得到的另外的信息是吸奴,stop / start 壓力測試停止之后(停止震蕩上升的后面藍色直線)考润,內(nèi)存使用率就維持一個很高的比例糊治,不會降低
Root Cause
跑Android Framework stop /start 反復(fù)kill 和啟動FW的核心進程,會導(dǎo)致物理內(nèi)存的碎片化粥脚,而Android核心進程啟動又需要大塊的內(nèi)存頁刷允,從 cat /proc/buddyinfo 可以看出剛開始跑測試树灶,系統(tǒng)還要很多較大塊的內(nèi)存頁,結(jié)果到后來熄驼,大塊內(nèi)存頁越來越少萝映,碎片頁得不到釋放合并序臂,F(xiàn)W 的server 重新啟動又不得不去分配超過需求的內(nèi)存大頁奥秆,引發(fā)內(nèi)存使用率不斷上升,最后oom killer解決過程總結(jié)
- 一開始處理這個問題避矢,大家的焦點都在內(nèi)存泄露上,而且內(nèi)核驅(qū)動確實有內(nèi)存泄露的情況卸勺,所以大家花很多精力去debug內(nèi)存泄露問題,而忽略內(nèi)存碎片對內(nèi)存使用率升高的影響悟狱。
- 在花費很多精力挤渐,解決了一個非常隱蔽的重要內(nèi)存泄露問題時挣菲,內(nèi)存使用率還是會在壓力測試中攀升。
- 經(jīng)過縮小debug范圍抚岗,發(fā)現(xiàn)是反復(fù)執(zhí)行stop / start命令導(dǎo)致的宣蔚,而且在縮小模擬測試的時候,并沒有嚴重的內(nèi)核內(nèi)存泄露發(fā)生亩冬,并且用戶態(tài)的舊進程也在不斷被kill, 再重新啟動新進程硅急,用top -s 10 排序觀察用戶態(tài)進程的狀態(tài)营袜,似乎也沒有看出哪個進程內(nèi)存使用率明顯升高的跡象
- 后面把注意力放到內(nèi)存碎片上荚板,cat /proc/buddyinfo 發(fā)現(xiàn)內(nèi)存碎片化非常嚴重
-
在stop 之后加入清理pages cache, inode節(jié)點和壓縮碎片內(nèi)存頁的命令
echo 3 > /proc/sys/vm/drop_caches
echo 1 >/proc/sys/vm/compact_memory
內(nèi)存碎片導(dǎo)致內(nèi)存使用率不斷升高的問題得到根本性解決客扎。解決后的內(nèi)存使用率如下圖:
Android系統(tǒng)Cortex-A57 Coresight PTM ARM官方驅(qū)動不能正常工作
硬件平臺
公司自研 ARM Cortex-A57 4核 SOC 參考板軟件環(huán)境
系統(tǒng): Android-N
Linux內(nèi)核版本: 4.4
驅(qū)動: linux/drivers/hwtracing/coresight現(xiàn)象描述
將Linux-4.4 upstream 官方內(nèi)核ARM提交的的CPU coresight PTM驅(qū)動移植到板子上,替換公司私有的coresight PTM驅(qū)動袱吆,寄存器和pipeline的dts配置都正常绞绒,但是ARM官方的coresight PTM驅(qū)動不能正常工作蓬衡,而公司私有驅(qū)動可以正常工作Root Cause
跑Android 系統(tǒng) ARM Cortex-A57 CPU有用于低功耗電源管理的dynamic power gating功能,該功能會以一定頻率不停地運行壁晒。在系統(tǒng)運行dynamic power gating的時候秒咐,會把coresight PTM的寄存器全部清零携取,而如果沒有保存之前寄存器的值,則cpu從dynamic power gating恢復(fù)之后你弦,寄存器的值一直是0尸昧,之前配置的值沒有恢復(fù)導(dǎo)致不能正常工作解決過程總結(jié)
- 第一次接觸Android項目對低功耗管理烹俗,dynamic power gating的side effect完全沒有概念幢妄,一直在花時間配置coresight PTM驅(qū)動的寄存器和pipeline dts上乎赴,但是一直不工作
2.突發(fā)奇想地把私有可以工作的驅(qū)動和ARM官方upstream的驅(qū)動一起加載的情況下榕吼,ARM官方upstream的coresight PTM驅(qū)動卻可以正常工作 - 通過分析舊的私有驅(qū)動羹蚣,發(fā)現(xiàn)里面有注冊一個dynamic power gating 事件的notifier chain通知鏈, 每當dynamic power gating 事件發(fā)生時顽素,會通過通知鏈調(diào)用callback函數(shù)保存寄存器的當前值,dynamic power gating 事件恢復(fù)的的時候再恢復(fù)寄存器的值
- 將該通知鏈的業(yè)務(wù)邏輯和流程移植到ARM官方的upstream的coresight PTM驅(qū)動划鸽,稍微優(yōu)化一下就解決了該問題
Android系統(tǒng) Bring up 由電源管理造成的security問題導(dǎo)致系統(tǒng)無法正常啟動
硬件平臺
公司自研 ARM Cortex-A57 4核 SOC CostDown版本參考板
在之前的參考板基礎(chǔ)上,內(nèi)存從8G縮減到4G, 更換了PMIC, eMMC從32G縮減到16G
之前的板子是已經(jīng)量產(chǎn)型凳,完全能夠正常工作嘱函,SOC芯片和CostDown的參考板完全一樣軟件環(huán)境
系統(tǒng): Android-N
Linux內(nèi)核版本: 4.4現(xiàn)象描述
Android系統(tǒng)啟動Zygote SystemServer的時候疏唾,在嘗試啟動其它服務(wù)進程的時候槐脏,那些服務(wù)進程都因為SELinux security的原因顿天,被kill掉牌废,在嘗試多次啟動服務(wù)和被Kill之后鸟缕,系統(tǒng)最后關(guān)機重啟Root Cause
PMIC 的SOC Thermal 加入了限流功能三妈,一旦啟動的時候開啟限流畴蒲,SOC的CPU就會降頻模燥,一旦CPU降頻, 啟動過程就會減慢辽旋,Security固件加載就會延后补胚,一旦Security固件加載延后溶其,就會在Zygote 啟動各種系統(tǒng)服務(wù)的時候瓶逃,引發(fā)SELinux的安全保護機制厢绝,導(dǎo)致各個系統(tǒng)服務(wù)因為Security原因被Kill掉,進而關(guān)機浓利。可謂是一個小問題引發(fā)一連串問題解決過程總結(jié)
- 一開始做Bring up, 發(fā)現(xiàn)這些系統(tǒng)Server都是因為Security的原因被Kill掉的,都去抓Security相關(guān)的Log檢查昆咽,沒有注意到系統(tǒng)整體的原因掷酗,后來改了一些代碼泻轰,延時了系統(tǒng)Server啟動時間到Security固件加載之后才啟動虚婿,這樣用WorkAround方法解決了Security原因?qū)е路?wù)被Kill掉錯誤然痊,治標不治本剧浸,繼續(xù)Bring up
- 雖然不會有Security問題導(dǎo)致系統(tǒng)服務(wù)被Kill, 但是整個系統(tǒng)啟動時間很慢,而且運行一段時間之后袋马,GPU驅(qū)動會導(dǎo)致系統(tǒng)Crash
- 為了檢查系統(tǒng)啟動慢的原因,我們檢查了CPU和GPU的時鐘頻率软啼,發(fā)現(xiàn)其遠低于正常的工作頻率
- 和硬件還有芯片的工程師討論之后,發(fā)現(xiàn)這款芯片有溫度保護限流SOC降頻保護的功能贿条,而新的PMIC Thermal不支持該溫度保護相關(guān)的功能胧辽,因而我們?nèi)サ袅讼蘖鹘殿l相關(guān)的dts配置邑商,這樣CPU就能以正常頻率啟動人断,之前的延時的WorkAround去掉之后也不會再引發(fā)Security固件加載慢導(dǎo)致系統(tǒng)服務(wù)被Kill的現(xiàn)象了
Linux 內(nèi)核 eMMC 5.1 存儲驅(qū)動添加異步I/O新命令特性時關(guān)于內(nèi)核線程同步問題
硬件平臺
公司自研 ARM Cortex-A57 4核 SOC 產(chǎn)品板
eMMC使用SanDisk新一代 eMMC 5.1存儲器,有擴展指令支持device report 等溫度信息暇仲、flash讀寫次數(shù)等芯片狀態(tài)軟件環(huán)境
系統(tǒng): Android-P
Linux內(nèi)核版本: 4.9現(xiàn)象描述
想在sysfs中增加一個文件熔吗,通過eMMC芯片的異步I/O讀取eMMC芯片的溫度信息,但是總是因為各種原因讀取的時候直接卡死或者失敗Root Cause
eMMC設(shè)備驅(qū)動不同于led, 電源管理芯片等普通的字符設(shè)備驅(qū)動中跌,可以直接異步I/O讀取漩符。因為在Linux內(nèi)核里面存儲相關(guān)的設(shè)備驅(qū)動上層有負責(zé)塊Block設(shè)備隊列管理的內(nèi)核線程在實時占用設(shè)備并與文件系統(tǒng)數(shù)據(jù)同步,如果不加同步互斥的方法直接異步I/O讀取eMMC的device report狀態(tài)信息,那么將與其eMMC驅(qū)動上層的Block設(shè)備隊列管理的內(nèi)核線程發(fā)生干擾和沖突舆逃,進而會卡死或者引發(fā)意想不到的side effect路狮。
另一方面涂籽,由于Android系統(tǒng)有動態(tài)電源,時鐘等功耗管理锰悼,及時此時Block設(shè)備隊列很空閑柳骄,沒有做同步,但是由于電源管理的dynamic clock gating等特性箕般,沒有加鎖互斥去情況下異步I/O讀取的時候耐薯,eMMC可能會由于dynamic clock gating導(dǎo)致暫時休眠而讀不到數(shù)據(jù)解決過程總結(jié)
- 仔細閱讀芯片手冊,發(fā)現(xiàn)Linux 4.9內(nèi)核MMC框架只支持標準的eMMC 4.1指令丝里,我做的eMMC 5.1 的新特性指令需要自己添加
- 添加自己的指令曲初,實現(xiàn)好驅(qū)動接口之后,異步I/O讀取eMMC device report信息不是卡死就是失敗
- 通過 dump_stack()追蹤eMMC控制器驅(qū)動函數(shù)的調(diào)用流程杯聚,發(fā)現(xiàn)dynamic clock gating功能導(dǎo)致芯片低功耗休眠無法讀取數(shù)據(jù)傀广,加了一些workaround方法,關(guān)閉休眠,再次嘗試讀取骄瓣,發(fā)現(xiàn)會卡死
- 繼續(xù)研究emmc驅(qū)動代碼,發(fā)現(xiàn)emmc設(shè)備驅(qū)動上層被Block設(shè)備隊列管理內(nèi)核線程實時調(diào)用盟萨,所以認為這不是簡單的異步I/O讀取功能均澳,應(yīng)該要加鎖做通讀
- 研究了一下eMMC一些異步 ioctl的實現(xiàn)方法,找到了給emmc設(shè)備加互斥鎖獨占的方法,解決了該問題
嵌入式Linux系統(tǒng) NandFlash的rootfs掛載遇到概率性Kernel Panic
硬件平臺
公司自研ARM Cortex-A9 / MIPS 32 SOC
NorFlash 啟動bootloader槐臀,加載 Nandflash 中的Linux 內(nèi)核與Rootfs軟件環(huán)境
- 嵌入式Linux系統(tǒng), Buildroot構(gòu)建ubifs格式Rootfs
- 公司自研windows平臺燒寫工具
現(xiàn)象描述
不同平臺分別測試3塊demo板朝抖,有一些板子掛載rootfs的時候出現(xiàn)kernel panic, 有一些沒有侮邀,看上去和arm 還是 mips cpu無關(guān)鹏秋, arm mips都有出現(xiàn),是概率性問題压汪,不是必現(xiàn)Root Cause
燒寫工具標記Nandflash壞塊記錄BBT表的功能出現(xiàn)bug, 導(dǎo)致燒寫的時候某些壞塊沒有跳過,而rootfs如果正好燒寫到某些壞塊上,則出現(xiàn)kernel Panic
不要認為燒寫工具是絕對可靠宏浩, 沒有Bug的解決過程總結(jié)
1.剛?cè)肼殞BT壞塊表的概念不是很清楚扒最,以為燒寫工具是絕對沒問題的岔霸,所以不敢懷疑。
- 由于是概率性出現(xiàn)的問題柜蜈,沒有找到復(fù)現(xiàn)問題的規(guī)律捷绒,因而研究了很多代碼但是都沒有頭緒
- 老大根據(jù)猜測可能是Nandflash有問題些举,讓我用uboot讀取Nandflash壞塊信息,再和燒寫工具打印的Nandflash壞塊信息對比發(fā)現(xiàn)有不一致绰垂。
- 選擇一塊可以復(fù)現(xiàn)問題的板,通過uboot打印的壞塊信息樊诺,發(fā)現(xiàn)壞塊點比較靠前必搞,調(diào)整rootfs的大小咆课,當rootfs大小可以覆蓋壞塊點的時候,問題復(fù)現(xiàn),當rootfs大小無法覆蓋壞塊點的時候缴阎,問題不復(fù)現(xiàn)廊驼,從而證明可Kernel Panic是壞塊導(dǎo)致的
- 進而對比燒寫工具打印的Nandflash壞塊信息镶苞,發(fā)現(xiàn)該壞塊點沒有被標記存入BBT表敬鬓,證明Bug出現(xiàn)在燒寫工具壞塊標記與BBT表更新。
嵌入式Linux Nandflash Only 啟動的方案,客戶更換不同型號的nand會有一定概率無法正常啟動
- 硬件平臺
公司自研 MIPS 32 SOC, 低成本方案,平臺只有Nandflash, 沒有NorFlash, 才有Nandflash啟動的方式 - 軟件環(huán)境
- 嵌入式Linux系統(tǒng), Buildroot構(gòu)建ubifs格式Rootfs
- 公司自研windows平臺燒寫工具
- 啟動流程: bootrom --> Nandflash中的uboot -->Linux內(nèi)核 --> rootfs
現(xiàn)象描述
客戶更換的某些型號的NandFlash 產(chǎn)品板有一定概率無法啟動UbootRoot Cause
這一代SOC芯片的bootrom 固件程序?qū)δ承㎞andFlash較長位數(shù)的ECC校驗存在Bug
不要認為芯片本身是絕對可靠弄砍,沒有Bug的解決過程總結(jié)
- 對BootRom 程序的實現(xiàn)不了解住册,沒有敢懷疑芯片本身存在的問題。有了之前的經(jīng)驗堂油,先開始懷疑燒寫工具兴使,和負責(zé)燒寫工具的工程師一起調(diào)試,但是沒有什么結(jié)果
- 在調(diào)試燒寫工具的時候有滑,注意到ECC校驗碼的一些信息有異常
- 在芯片部門BootRom工程師指點下,客戶板子上fused的芯片換成內(nèi)部unfused的芯片,觀察BootRom的打印信息右遭,發(fā)現(xiàn)對NandFlash ECC校驗有問題
- 更換客戶的NandFlash 為我們Demo板的Nandflash之后發(fā)現(xiàn)ECC校驗正常
- 懷疑Nandflash有問題,找客戶要了不同Nandflash的產(chǎn)品板各2塊缤削,發(fā)現(xiàn)某幾個型號的Nandflash能準確復(fù)現(xiàn)ECC校驗出錯
- 最后Bootrom工程師通過手動計算ECC校驗碼與程序計算對比窘哈,發(fā)現(xiàn)這幾款NandFlash的ECC位數(shù)比較長,會觸發(fā)BootRom代碼邏輯里的Bug亭敢,但是這一代芯片已經(jīng)賣出去很多了
- 給出WorkAround的解決方法滚婉,以后這一代芯片使用帶有Bug的BootRom程序的,只出NorFlash啟動的方案帅刀,不出Nand Only的方案满哪,建議客戶將Nandflash Only的方案換成Nor + Nand, 采用Norflash啟動
嵌入式Linux 客戶通過某認證的平臺的MP3音頻播放出現(xiàn)異常錯誤
硬件平臺
公司自研 MIPS 32 SOC + 客戶通過某安全認證的產(chǎn)品板軟件環(huán)境
嵌入式Linux系統(tǒng), 客戶基于公司Buildroot 構(gòu)建rootfs移植了自己的系統(tǒng),應(yīng)用以及安全認證相關(guān)的第三方軟件庫劝篷,rootfs是ramdisk readonly的, 啟動先掛載ramdisk rootfs再掛載客戶自己的應(yīng)用分區(qū)現(xiàn)象描述
運行公司提供的SDK音樂播放測試用例民宿,播放mp3文件出現(xiàn)exception異常娇妓,該異常來自于glibc,客戶聲稱沒有對sdk底層代碼進行修改Root Cause
客戶為通過第三方安全認證的specification規(guī)定glibc庫的要求活鹰,強行替換升級了板子里面rootfs的glibc庫的版本重新編譯哈恰。公司發(fā)布給客戶的SDK里面有不開源的固件(比如MP3硬解碼器插件)是基于舊的glibc編譯的,客戶替換升級glibc版本的時候志群,無法重新編譯替換不開源的插件着绷,從而導(dǎo)致兼容性問題解決過程總結(jié)
- 因為對SDK里面的各種不開源插件不是很了解,加上錯誤莫名其妙锌云,看代碼和錯誤提示看不出端倪荠医。
- 嘗試remount 掛載我們自己的rootfs,則該問題無法復(fù)現(xiàn),如果采用客戶的rootfs則可以復(fù)現(xiàn)
- 把問題范圍縮小到rootfs里面彬向,進而發(fā)現(xiàn)了公司的rootfs和客戶的rootfs的libc版本的差異兼贡,通過和客戶溝通了解到他們過安全認證的時候替換過glibc重新編譯
- 最后升級我們的glibc重新給客戶發(fā)布了固件
嵌入式Linux MIPS 32位平臺內(nèi)存由256MB升級512MB之后,PVR長時間錄制壓力測試導(dǎo)致系統(tǒng)死機
硬件平臺
公司自研 MIPS 32 SOC demo板娃胆, DRAM由256MB升級到512MB軟件環(huán)境
- 嵌入式Linux系統(tǒng), Buildroot構(gòu)建ubifs格式Rootfs
- 出于對內(nèi)容保護的安全性考慮遍希,PVR錄像程序是在內(nèi)核態(tài)使用內(nèi)核地址空間進行錄像并保存的,用戶態(tài)地址空間是拿不到音視頻數(shù)據(jù)的
現(xiàn)象描述
PVR做整晚的錄像和刪除壓力測試(錄像文件超過某個大小里烦,前面的幀會被刪除)凿蒜, 用以測試新的512MB內(nèi)存是否能夠全部利用正常工作,結(jié)果壓力測試導(dǎo)致系統(tǒng)死機Root Cause
MIPS 32位架構(gòu)的CPU的物理內(nèi)存胁黑,普通內(nèi)存是0~256MB废封, 高端內(nèi)存默認從256MB往上。由于使用了512MB的DRAM, 重新調(diào)整了某些IP的memory CMA的地址空間别厘,導(dǎo)致PVR錄像模塊使用了高端內(nèi)存虱饿,而MIPS高端內(nèi)存映射是不穩(wěn)定不保證物理地址連續(xù)的,而錄像一般需要連續(xù)的物理地址触趴,從而導(dǎo)致系統(tǒng)問題死機解決過程總結(jié)
- 處理這個項目的時候氮发,對Linux內(nèi)核,cpu體系結(jié)構(gòu)冗懦,高端內(nèi)存尤其是MIPS架構(gòu)的高端內(nèi)存概念沒有深刻的認識爽冕,認為理所當然做下去應(yīng)該沒問題
- 壓力測試出現(xiàn)異常之后,保存log但是沒有分析出頭緒披蕉,后來和一個內(nèi)核專家一起討論颈畸,找資料,在MIPS社區(qū)找到高端內(nèi)存相關(guān)的一些資料
- 重新調(diào)整了cma的memory map空間没讲,在512MB的DRAM平臺上眯娱,將PVR IP的地址限定在256MB之內(nèi)的地址空間,和之前出現(xiàn)死機的平臺再次進行對比壓力測試爬凑,發(fā)現(xiàn)限制PVR限制在256MB地址空間之內(nèi)的平臺徙缴,錄像壓力測試不死機,而沒有限制的則出現(xiàn)死機嘁信,證明了確實是高端內(nèi)存物理地址不連續(xù)于样,映射不穩(wěn)定導(dǎo)致的問題
- 在512MB DRAM的平臺上重新調(diào)整了CMA Memory MAP的地址空間,解決死機問題
嵌入式Linux ARM Cortex-A7 科大訊飛在線翻譯壓力測試概率性段錯誤
硬件平臺
全志R16 SOC Cortext-A7 四核處理器潘靖,公司產(chǎn)品板(某IPC+智能音箱產(chǎn)品)軟件環(huán)境
嵌入式Linux OpenWRT系統(tǒng)穿剖, 使用科大訊飛的SDK做離線的NLP語音識別,運行流程如下:
麥克風(fēng)采集的語音信息 --> 訊飛遠端服務(wù)器 --> 識別語音信息卦溢,轉(zhuǎn)換成文字 --> 根據(jù)識別的文字生成對答的文字 --> 返回識別的文字與對答的文字的字符串數(shù)據(jù)(json格式)現(xiàn)象描述
一晚上不停輸入語音信息糊余,做壓力測試秀又,會概率性出現(xiàn)段錯誤,找不到規(guī)律性復(fù)現(xiàn)段錯誤的方法Root Cause
之前歷史遺留代碼代碼中啄刹,有一段從返回關(guān)于“今天天氣如何?/今天天氣怎么樣?”的對答語句中提取天氣信息的代碼涮坐,該代碼在提取信息格式時用了一些hardcode編碼,而服務(wù)器端返回相關(guān)對答信息的文字格式和組合會有一些變化誓军,使用hardcode導(dǎo)致解析信息時指針越界段錯誤解決過程總結(jié)
- 這個問題最大的難點是找不到規(guī)律的復(fù)現(xiàn)方法袱讹,最后我接手這個問題建議把ARM平臺的gdb調(diào)試器編譯燒寫進去,其實現(xiàn)在的Cortex-A 系列SOC嵌入式平臺用gdb本底調(diào)試完全沒有問題
- 打開gdb調(diào)試最終語音對話模塊應(yīng)用昵时,繼續(xù)做壓力測試捷雕,出現(xiàn)段錯誤時通過bt指令分析打印棧,發(fā)現(xiàn)天氣相關(guān)的信息壹甥,縮小范圍救巷,通過手機錄音一段"今天天氣怎么樣?"的語音句柠,不斷輸入設(shè)備做壓力測試浦译,發(fā)現(xiàn)復(fù)現(xiàn)概率明顯增加
- 再添加一些調(diào)試信息,根據(jù)段錯誤打印的函數(shù)調(diào)用棧溯职,追溯到段錯誤的具體函數(shù)精盅,發(fā)現(xiàn)了這個hardcode導(dǎo)致的指針越界段錯誤問題,并且代碼存在多處hardcode(可能是因為前期代碼開發(fā)猛操快谜酒,不注意代碼規(guī)范)
- 通過打印訊飛服務(wù)器返回的語音識別和對答信息叹俏,發(fā)現(xiàn)"今天天氣怎么樣?"這樣一句簡單的問題僻族,服務(wù)器端返回的對答信息有一定較小概率出現(xiàn)不同格式的答案(可能是對方NLP人工智能為了模擬人說話的多樣性粘驰,而不是機械般地重復(fù)某些回答),所以做在線語音識別一定不能想當然假定服務(wù)器端針對某句語音對答的問題返回的結(jié)果是絕對確定述么,一模一樣的, 避免hardcode去解析不確定的信息
嵌入式Linux ARM Cortex-A7 音頻應(yīng)用壓力測試導(dǎo)致OOM Killer
硬件平臺
全志R16 SOC Cortext-A7 四核處理器蝌数,公司產(chǎn)品板(某IPC+智能音箱產(chǎn)品)軟件環(huán)境
嵌入式Linux OpenWRT系統(tǒng)現(xiàn)象描述
晚上燒機壓力測試,發(fā)現(xiàn)系統(tǒng)核心的業(yè)務(wù)進程被OOM Killer殺死度秘,而根據(jù)抓取的Log顯示系統(tǒng)應(yīng)該還剩余20%左右的物理內(nèi)存籽前,應(yīng)該不至于觸發(fā)Linux內(nèi)核的oom killer機制Root Cause
全志提供的Linux內(nèi)核可能和Android版的Linux內(nèi)核一起維護或者混用,在OpenWRT系統(tǒng)的Linux內(nèi)核配置中有一些Android Linux內(nèi)核的配置敷钾,其中Android內(nèi)核使用的Low Memory Killer模塊被選中,而Low Memory Killer 對最少物理內(nèi)存的容忍程度比普通Linux內(nèi)核的oom killer低肄梨,在還剩20%左右物理內(nèi)存的情況下觸發(fā)killer, 殺死了進程解決過程總結(jié)
- 因為之前沒有做過Android相關(guān)的項目阻荒,對Android和Linux 內(nèi)核的差異不是很了解,認為Android的Linux內(nèi)核和普通Linux內(nèi)核差不多众羡,因而該問題一直掛著很久沒解決
- 后面又興趣看了一下Android的書侨赡,發(fā)現(xiàn)了Android和Linux差異中提到了Low Memory Killer不同于Linux官方的oom Killer, 于是檢查了一下配置,關(guān)閉Android Low Memory Killer的選項,果然該問題就不再復(fù)現(xiàn)
嵌入式Linux ARM Cortex-A7 用戶空間內(nèi)存碎片化問題
硬件平臺
全志R16 SOC Cortext-A7 四核處理器羊壹,公司產(chǎn)品板(某IPC+智能音箱產(chǎn)品)軟件環(huán)境
嵌入式Linux OpenWRT系統(tǒng)蓖宦, 交叉工具鏈使用arm-linux-uclibc-gcc現(xiàn)象描述
晚上燒機壓力測試, 發(fā)現(xiàn)系統(tǒng)應(yīng)用程序空間出現(xiàn)了較為嚴重的內(nèi)存碎片油猫,后面可能導(dǎo)致一些應(yīng)用進程申請內(nèi)存失敗Root Cause
系統(tǒng)使用了基于較低版本的uclibc的交叉工具鏈稠茂,該uclibc庫的內(nèi)存分配和管理的函數(shù)對對避免內(nèi)存碎片這塊做的很差,換成較高版本的glibc工具鏈情妖,則不會復(fù)現(xiàn)這個問題解決過程總結(jié)
- 這個問題剛開始不是我處理睬关,那個負責(zé)的工程師總認為內(nèi)存碎片管理是Linux內(nèi)核做得事情,因而犯了方向性錯誤毡证,拼命地在內(nèi)核內(nèi)存管理电爹,虛擬地址空間管理等代碼上加調(diào)試,結(jié)果一籌莫展料睛。
- 我有原廠相關(guān)的工作經(jīng)驗丐箩,之前做過工具鏈升級的工作,對工具鏈恤煞,libc庫這些基礎(chǔ)設(shè)施有天然的敏感性屎勘,而且知道m(xù)alloc這類函數(shù)在glibc中有通過內(nèi)存池,緩沖區(qū)等方法避免碎片阱州,因而我認為應(yīng)該問題不在Linux內(nèi)核挑秉,而在用戶態(tài),是libc庫的malloc底層的內(nèi)存管理出來問題
- 通過替換升級工具鏈和庫苔货,成功驗證了我猜想的正確性犀概,最后找到一些文章和資料證明低版本的uclibc庫在內(nèi)存管理與分配上做得太簡陋,容易碎片化夜惭。
嵌入式Linux USB攝像頭無法兼容高版本Linux內(nèi)核UVC驅(qū)動
硬件平臺
Tiny4412 開發(fā)板姻灶, 三星Exynos-4412 Cortex-A9 四核處理器
使用臺灣沛成科技iP297X 系列UVC轉(zhuǎn)換芯片的USB攝像頭軟件環(huán)境
嵌入式Linux Builroot制作的rootfs, Linux內(nèi)核采用 Linux-3.5/Linux-4.4等較高版本內(nèi)核現(xiàn)象描述
根據(jù)原廠提供的移植手冊,在Linux較高版的內(nèi)核(3.5/4.4), 將官方補丁加入Linux內(nèi)核開源的UVC驅(qū)動中诈茧,USB攝像頭不能正常工作产喉,而在Linux-2.6 版本的內(nèi)核中,加入官方補丁之后敢会,USB攝像頭是可以正常工作的Root Cause
該臺灣小廠的UVC攝像頭USB轉(zhuǎn)換芯片存在Bug, 看起來沒有拿到USB UVC官方組織的認證和ID號曾沈,在補丁中PID, VID都是手動加上去的(不是USB UVC Class官方自帶兼容的)。
這個未認證的USB UVC芯片鸥昏,它枚舉出來的最高帶寬endpoint是無法在iso模式下正常工作的塞俱,而Linux-2.6 內(nèi)核的UVC驅(qū)動可以獲取攝像頭512Bytes的次高帶寬Endpoint進行ISO模式的數(shù)據(jù)傳輸,而Linux 3.5/4.4等高版本的內(nèi)核中采用的Endpoint選擇方法都是一定要找到最高帶寬Endpoint來在ISO模式下傳輸吏垮,最后選擇了無法正常工作的最高帶寬Endpoint解決過程總結(jié)
- 通過Dump 出插入USB 攝像頭時USB Host 控制器枚舉的device endpoint信息障涯,再在開源UVC驅(qū)動中加入一些打印罐旗,通過Linux-2.6 與 Linux-3.5 內(nèi)核的打印信息對比,發(fā)現(xiàn)他們選擇了不同Endpoint, 而Linux-3.5內(nèi)核選擇的高帶寬Endpoint無法正常工作
- 在UVC驅(qū)動中加入一些WorkAround, 如果枚舉的VID PID信息顯示是這款特殊的攝像頭唯蝶,則在選擇Endpoint時強制設(shè)置成512Bytesd帶寬的節(jié)點
- 總結(jié): 小公司未通過認證的USB芯片可能有Bug, 與通用開源驅(qū)動的兼容性可能有一些未經(jīng)測試過的問題九秀,廉價模塊和芯片總有挖坑的地方。
Android系統(tǒng) 電源regulator動態(tài)調(diào)壓響應(yīng)測試ovp/uvp欠壓過壓保護導(dǎo)致系統(tǒng)死機
硬件平臺
公司自研 ARM Cortex-A57 4核 SOC 參考板軟件環(huán)境
系統(tǒng): Android-N
Linux內(nèi)核版本: 4.4現(xiàn)象描述
Android系統(tǒng)為了支持低功耗動態(tài)調(diào)壓調(diào)頻粘我,板子上有很多regulator動態(tài)調(diào)壓芯片鼓蜒,對regulator調(diào)壓做穩(wěn)定性壓力測試,在規(guī)定的調(diào)壓范圍內(nèi)涂滴,自動腳本通過驅(qū)動隨機發(fā)出regulator調(diào)壓指令友酱,調(diào)節(jié)相關(guān)IP的regulator電壓,發(fā)行某個IP在該regulator動態(tài)調(diào)壓壓力測試中容易導(dǎo)致系統(tǒng)死機Root Cause
Android系統(tǒng)板的SOC有ovp/uvp欠壓保護功能柔纵,某些regulator芯片調(diào)壓范圍太廣缔杉,當前電壓和regulator設(shè)置的電壓的delta值過大,而由于板子上電容搁料,電感的影響或详,電壓變化曲線太平緩,沒有及時升壓到指定的電壓而導(dǎo)致系統(tǒng)過壓欠壓保護引發(fā)死機解決過程總結(jié)
- 該自動測試腳本設(shè)置的regulator調(diào)壓值是在某范圍內(nèi)隨機產(chǎn)生的郭计,因而該開始死機有一定概率性霸琴,沒有找到重復(fù)性地復(fù)現(xiàn)規(guī)律
- 后來在專家的指導(dǎo)下,在腳本加入一些regulator調(diào)壓范圍限制和偏置值昭伸,發(fā)現(xiàn)把regulator調(diào)壓范圍縮小到某個區(qū)域的時候有很高的復(fù)現(xiàn)概率梧乘,找到復(fù)現(xiàn)規(guī)律,所以猜測和電壓變化曲線有關(guān)
- 拿著示波器測試腳本運行時的電壓曲線庐杨,果然在某范圍內(nèi)上升曲線較慢选调,容易觸發(fā)uvp欠壓保護
- 和硬件商議修改了板子上的一些電容的值,于是解決了這個regulator穩(wěn)定性問題
Android系統(tǒng) 外設(shè)芯片i2c地址的小改動導(dǎo)致ADB不能使用
硬件平臺
RK3399產(chǎn)品板灵份, USB ADB口用的是USB type-C軟件環(huán)境
系統(tǒng): Android-M
Linux內(nèi)核版本: 4.4現(xiàn)象描述
客戶根據(jù)開發(fā)板稍微修改的產(chǎn)品板仁堪,板子的USB上電檢測,燒寫固件沒有問題填渠,刷入Android-M系統(tǒng)弦聂,開機能正常啟動進入系統(tǒng),但是adb 功能不能正常工作氛什,
adb devices沒有反應(yīng)Root Cause
硬件工程師對USB Type-C電路的原理和結(jié)構(gòu)理解有誤莺葫,不知道USB Type-C和以前USB2.0有區(qū)別,type-C除了本身的USB協(xié)議熱插拔電路功能另外還有控制芯片與系統(tǒng)進行i2c通信枪眉,系統(tǒng)USB驅(qū)動通過i2c發(fā)命令給Type-C的控制芯片設(shè)置USB的工作模式(如充電捺檬, ADB等)。硬件工程師將該Type-C的控制芯片的i2c地址換瑰谜,設(shè)備樹沒有配置欺冀,i2c時鐘頻率也沒有想過配置,導(dǎo)致無法設(shè)置成ADB模式解決過程總結(jié)
- 之前硬件工程師看到板子能通過USB口上電檢測萨脑,燒寫就以為USB硬件電路上沒有問題隐轩,認為是軟件問題
- 我檢查了設(shè)備樹配置,發(fā)現(xiàn)某個i2c master控制器下面有一個芯片似乎與USB Type-C有關(guān)
- 在我對硬件工程師的追問下渤早,發(fā)現(xiàn)他為了走線方便职车,并且以為USB和i2c總線似乎沒有關(guān)系,改動了該芯片的i2c控制器和地址
- 重新配置了該改芯片的i2c地址核時鐘頻率鹊杖,ADB就能正常工作