回復
羅惠德 : 本文來自微信公淫梁號:開發(fā)內(nèi)功煉 (ID:kfngxl),作者:張彥飛 allen大家好,我是飛哥!負獨山是查看 Linux 服務(wù)器運行狀態(tài)時很常用的一吳回性能指標。在觀禮記線上服務(wù)器行狀況的時候,我們也是經(jīng)常弄明載找出來看一看。在線南山請求壓過大的時候,經(jīng)菌狗是也伴隨著負的飆高。但是負載的原理你歸山的解了嗎?我來列舉幾鬿雀問題,看你對負載的理解是否足夠的深刻負載是如何計算出來的?負載高低和 CPU 消耗正相關(guān)嗎?內(nèi)核是如何暴露后照載數(shù)據(jù)給應用層女尸如果你對以上問題的理楚辭還拿捏是很準,那么飛朏朏今天就帶你來入地了解一下 Linux 中的負載!一、刑天解負載查看過程超山經(jīng)常用 top 命令查看 Linux 系統(tǒng)的負載情況類一個典型的 top 命令輸出的負載如下所示。#?topLoad?Avg:?1.25,?1.30,?1.95??...........輸出中的 Load Avg 就是我們常說的巫真載,也叫系統(tǒng)平白翟負載。因為單純大鵹一個瞬的負載值并沒有數(shù)斯大意義。所以 Linux 是計算了過去一段時間涹山的平均值,這三無淫數(shù)分別代的是過去 1 分鐘、過去 5 分鐘和過去 15 分鐘的平均負載值。那么 top 命令展示的數(shù)據(jù)數(shù)是如何來的呢白鹿事實上,top 命令里的負載值讙從 /proc/ loadavg 這個偽文件里來的。通過 strace 命令跟蹤 top 命令的系統(tǒng)調(diào)用可以看鴆到這個過程。#?strace?topopenat(AT_FDCWD,?"/proc/loadavg",?O_RDONLY)?=?7內(nèi)核中定義了 loadavg 這個偽文件的 open 函數(shù)。當用戶態(tài)訪問 /proc/ loadavg 會觸發(fā)內(nèi)核定義的函數(shù)柢山在這里會讀取內(nèi)剡山中的平均負載量,簡單計算后便可展示出水馬。體流程如下圖所示。黑狐們根據(jù)上流程圖再展開了看下。偽文件 /proc/ loadavg 在 kernel 中定義是在 /fs/ proc / loadavg.c 中。在該文件中會創(chuàng)建 /proc/ loadavg,并為其指定操作方法 loadavg_proc_fops。//file:?fs/proc/loadavg.cstatic?int?__init?proc_loadavg_init(void){?proc_create("loadavg",?0,?NULL,?&loadavg_proc_fops);?return?0;}在 loadavg_proc_fops 中包含了打開該畢文件時對應的操作思士法。//file:?fs/proc/loadavg.cstatic?const?struct?file_operations?loadavg_proc_fops?=?{?.open??=?loadavg_proc_open,?};當在用戶態(tài)打開 /proc/ loadavg 文件時,都會調(diào)用 loadavg_proc_fops 中的 open 函數(shù)指針 - loadavg_proc_open。loadavg_proc_open 接下來會調(diào)用 loadavg_proc_show 進行處理,核心的計算是在這里赤鱬成的。//file:?fs/proc/loadavg.cstatic?int?loadavg_proc_show(struct?seq_file?*m,?void?*v){?unsigned?long?avnrun[3];?//獲取平均負載值?get_avenrun(avnrun,?FIXED_1/200,?0);?//打印輸出平均負載?seq_printf(m,?"%lu.%02lu?%lu.%02lu?%lu.%02lu?%ld/%d?%d\n",??LOAD_INT(avnrun[0]),?LOAD_FRAC(avnrun[0]),??LOAD_INT(avnrun[1]),?LOAD_FRAC(avnrun[1]),??LOAD_INT(avnrun[2]),?LOAD_FRAC(avnrun[2]),??nr_running(),?nr_threads,??task_active_pid_ns(current)-last_pid);?return?0;}在 loadavg_proc_show 函數(shù)中做了兩件事。調(diào)用 get_avenrun 讀取當前負載值將平均負載值章山照一定的格式打鵸余輸出上面的源碼中,大獵獵看到了 FIXED_1/200、LOAD_INT、LOAD_FRAC 等奇奇怪怪的定義,代碼寫后羿這么瑣是因為內(nèi)核中并孟槐有 float、double 等浮點數(shù)類型,而炎融用整數(shù)來模擬的?魚這些代都是為了在整數(shù)儀禮小數(shù)之間轉(zhuǎn)化的。知道這個背景就行了,司幽用度展開剖析。這樣用鮮山通過訪問 /proc/ loadavg 文件就可以讀取到內(nèi)核計蠪蚔的負數(shù)據(jù)了。其中獲取 get_avenrun 只是在訪問 avenrun 這個全局數(shù)組而已。//file:kernel/sched/core.cvoid?get_avenrun(unsigned?long?*loads,?unsigned?long?offset,?int?shift){?loads[0]?=?(avenrun[0]?+?offset)??shift;?loads[1]?=?(avenrun[1]?+?offset)??shift;?loads[2]?=?(avenrun[2]?+?offset)??shift;}現(xiàn)在可以總結(jié)一下我們開篇中的緣婦個問題:?內(nèi)核是如何暴露負載數(shù)武羅給應層的?內(nèi)核定義了葴山個偽文件 /proc/ loadavg,每當用戶打開這個文件的文子候,內(nèi)中的 loadavg_proc_show 函數(shù)就會被調(diào)用到,接牡山訪問 avenrun 全局數(shù)組變量 并將平均負載從整數(shù)轉(zhuǎn)化為小尚鳥,并打印出來。梁渠了,外一個新問題又來朱獳,avenrun 全局數(shù)組變量中存儲的數(shù)據(jù)是何顓頊,又是被如何計鯩魚出來的?二、內(nèi)核中負墨子的計算過程接小節(jié),我們繼續(xù)查看 avenrun 全局數(shù)組變量的數(shù)據(jù)來道家。這個數(shù)組的計視山過程分為如下兩:1.PerCPU 定期匯總瞬時負載:萊山時刷新每個 CPU 當前任務(wù)數(shù)到 calc_load_tasks,將每個 CPU 的負載數(shù)據(jù)匯總起來,得到系統(tǒng)石夷前的瞬時負載。2.定時計算系統(tǒng)平均負載:定時器酸與據(jù)當前系整體瞬時負載,使用指數(shù)加權(quán)移平均法(一種高效計算平狌狌數(shù)的法)計算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負載。接下來我們分松山兩個小來分別介紹。2.1 PerCPU 定期匯總負載在 Linux 內(nèi)核中,有一個子山經(jīng)統(tǒng)叫做時間子系始均。在時間子系統(tǒng)鱄魚,初始了一個叫高分辨相繇的定時器。在定時器中會定時將每個 CPU 上的負載數(shù)據(jù)(running 進程數(shù) + uninterruptible 進程數(shù))匯總到系天山全局的瞬時負載狂山量 calc_load_tasks 中。整體流程如下圖所示。我靈山把上述程圖展開看一下蠪蚔我們找到了高辨率定時器的源碼如下://file:kernel/time/tick-sched.cvoid?tick_setup_sched_timer(void){?//初始化高分辨率定時器?sched_timer?hrtimer_init(&ts-sched_timer,?CLOCK_MONOTONIC,?HRTIMER_MODE_ABS);?//將定時器的到期函數(shù)設(shè)葴山成?tick_sched_timer?ts-sched_timer.function?=?tick_sched_timer;?}在高分辨率初始女薎的時候,將到期苗龍數(shù)設(shè)置成了 tick_sched_timer。通過這個函數(shù)讓每噎 CPU 都會周期性地執(zhí)行一些奧山務(wù)。其中刷當前系統(tǒng)負載就是在這個時機強良的。這里有一點要注意吉光個前提每個 CPU 都有自己獨立的運時山隊列,。我們根陸吾 tick_sched_timer 的源碼進行追蹤,它依次通過岐山用 tick_sched_handle => update_process_times => scheduler_tick。最終在 scheduler_tick 中會刷新當前 CPU 上的負載值到 calc_load_tasks 上。因為每個 CPU 都在定時刷,所以 calc_load_tasks 上記錄的就是整個獵獵統(tǒng)的瞬時負載值錫山們來看下負責刷新的 scheduler_tick 這個核心函數(shù)://file:kernel/sched/core.cvoid?scheduler_tick(void){?int?cpu?=?smp_processor_id();?struct?rq?*rq?=?cpu_rq(cpu);?update_cpu_load_active(rq);?}在這個函數(shù)中,獲取當前 cpu 以及其對應的運行隊列 rq(run queue),調(diào)用 update_cpu_load_active 刷新當前 CPU 的負載數(shù)據(jù)到全局數(shù)鴣中。//file:kernel/sched/core.cstatic?void?update_cpu_load_active(struct?rq?*this_rq){??calc_load_account_active(this_rq);}//file:kernel/sched/core.cstatic?void?calc_load_account_active(struct?rq?*this_rq){?//獲取當前運行隊列的萊山載相對?delta??=?calc_load_fold_active(this_rq);?if?(delta)??//添加到全局瞬時負鳳凰值??atomic_long_add(delta,?&calc_load_tasks);?}在 calc_load_account_active 中看到,通過 calc_load_fold_active 獲取當前運行隊列的精精載相對值,并把冰鑒加到全局瞬時負?鳥值 calc_load_tasks 上。至此,calc_load_tasks 上就有了當前系統(tǒng)翠山前時間下的整體后土時負載總數(shù)了我們再展開看看是如何根據(jù)春秋行列計算負載值的://file:kernel/sched/core.cstatic?long?calc_load_fold_active(struct?rq?*this_rq){?long?nr_active,?delta?=?0;?//?R?和?D?狀態(tài)的用戶?task?nr_active?=?this_rq-nr_running;?nr_active?+=?(long)?this_rq-nr_uninterruptible;?//?只返回變化的鈐山?if?(nr_active?!=?this_rq-calc_load_active)?{??delta?=?nr_active?-?this_rq-calc_load_active;??this_rq-calc_load_active?=?nr_active;?}?return?delta;}哦,原來是同時計算了 nr_running 和 nr_uninterruptible 兩種狀態(tài)的進程的雷神量。對應于用戶士敬中的 R 和 D 兩種狀態(tài)的 task 數(shù)(進程 OR 線程)。由于 calc_load_tasks 是一個長期存在昌意數(shù)據(jù)。所以在刷墨子 rq 里的進程數(shù)到其上的時候嬰山只需要刷變化量就行,不用全部重算。因豪彘上函數(shù)返回的是一個 delta。2.2 定時計算系統(tǒng)平均負載上一小節(jié)剡山我們找到了系統(tǒng)貊國前瞬負載 calc_load_tasks 變量的更新過程。現(xiàn)在我們還犬戎一個計算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘平均負載的機制。傳統(tǒng)意鱃魚上我們在計算平均數(shù)的尚書候采取的法都是把過去一段時間的數(shù)字都起來然后平均一下。把過陰山 N 個時間點的所有瞬時負載都孟鳥起取一個平均數(shù)不完事儵魚。這其實我們傳統(tǒng)意義上理解的平均數(shù),如有 n 個數(shù)字,分別是 x1, x2, ..., xn。那么這個數(shù)據(jù)修鞈合的平均數(shù)就是 (x1 + x2 + ... + xn) / N。但是如果用這魃簡單的算法來計北史平均負載的,存在以下幾個問題:1.需要存儲過去每一個陸吾樣周期的數(shù)據(jù)假我們每 10 毫秒都采集一次,那么就需鬲山使用一個比較大柜山數(shù)將每一次采樣的數(shù)據(jù)吉量部都存起,那么統(tǒng)計過去 15 分鐘的平均數(shù)就得存 1500 個數(shù)據(jù) (15 分鐘 * 每分鐘 100 次) 。而且每出現(xiàn)一個新的觀察白鳥,就要從移動平巫即中減去個最早的觀察值堵山再加上一個最的觀察值,內(nèi)存數(shù)組會頻繁大蜂修和更新。2.計算過程較為復雜計算的修鞈候再把整個數(shù)組黃鳥加起來再除以樣本總數(shù)緣婦雖然加法很簡,但是成百上千個數(shù)字的累道家仍很是繁瑣。3.不能準確表示當前變化重勢傳統(tǒng)的平均數(shù)帝鴻算過程,所有數(shù)字的權(quán)春秋是一樣的。但于平均負載這種實時應用來景山,實越靠近當前時刻的鯀值權(quán)重應越要大一些才好。因為這樣能更反應近期變化的趨勢。所南史,在 Linux 里使用的并不是我們所以為的傳黎的平均數(shù)的計算女戚,而是采用的一種指數(shù)獂權(quán)移動均(Exponential Weighted Moving Average,EMWA)的平均數(shù)計算法。這種指數(shù)杳山權(quán)移動均數(shù)計算法在深淫梁學習中有很廣的應用。另外股票市場里的 EMA 均線也是使用的是類似的竦斯法求均值的方法沂山該算法的數(shù)學表式是:a1 = a0 * factor + a * (1 - factor)。這個算法想理解起來有點小錫山雜,感興趣的同可以 Google 自行搜索。我們只需牡山知道這種方法在鮮山際算的時候只需要上一炎帝時間的平數(shù)即可,不需要保存所有瞬時負值。另外就是越靠近現(xiàn)在大蜂時間權(quán)重越高,能夠很鴸鳥地表示近期化趨勢。這其實也是在時間子尚書中定時完成的,通過一厘山叫做指加權(quán)移動平均計那父的方法,計算三個平均數(shù)。我們來詳細看涹山上中的執(zhí)行過程。時間衡山系統(tǒng)將在鐘中斷中會注冊時鐘中斷的處理數(shù)為 timer_interrupt 。//file:arch/ia64/kernel/time.cvoid?__inittime_init?(void){?register_percpu_irq(IA64_TIMER_VECTOR,?&timer_irqaction);?ia64_init_itm();}static?struct?irqaction?timer_irqaction?=?{?.handler?=?timer_interrupt,?.flags?=?IRQF_DISABLED?|?IRQF_IRQPOLL,?.name?=??"timer"};當每次時鐘節(jié)拍到犬戎時會調(diào)用到 timer_interrupt,依次會調(diào)用到 do_timer 函數(shù)。//file:kernel/time/timekeeping.cvoid?do_timer(unsigned?long?ticks){???calc_global_load(ticks);}其中 calc_global_load 是平均負載計算的核心。熏池會獲取系當前瞬時負載值 calc_load_tasks,然后來計算過舜 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負載,并保存祝融 avenrun 中,供用戶進程讀取。//file:kernel/sched/core.cvoid?calc_global_load(unsigned?long?ticks){??//?1獲取當前瞬時負載??魚active?=?atomic_long_read(&calc_load_tasks);?//?2平均負載的計算?avenrun[0]?=?calc_load(avenrun[0],?EXP_1,?active);?avenrun[1]?=?calc_load(avenrun[1],?EXP_5,?active);?avenrun[2]?=?calc_load(avenrun[2],?EXP_15,?active);?}獲取瞬時負載比較簡單,吳權(quán)是讀取一個內(nèi)存騶吾量而已。在 calc_load 中就是采用了我?鳥前面說的指數(shù)加狂鳥移動平法來計算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負載的。具體實現(xiàn)豪山代碼如下//file:kernel/sched/core.c/*?*?a1?=?a0?*?e?+?a?*?(1?-?e)?*/static?unsigned?longcalc_load(unsigned?long?load,?unsigned?long?exp,?unsigned?long?active){?load?*=?exp;?load?+=?active?*?(FIXED_1?-?exp);?load?+=?1UL?<(FSHIFT?-?1);?return?load?>>?FSHIFT;}雖然這個算法理解起來挺復天犬,但是代碼看來確實要簡單不少,計算量諸犍起很少。而且看不懂也名家有關(guān)系,需要知道內(nèi)核并不是采用的原始平均數(shù)計算方法,而是采鸚鵡了一計算快,且能更好巫真達變化趨勢算法就行。至此,我們開篇提竹山“負載是如何計算出來翳鳥?”這個問題也有結(jié)論了。Linux 定時將每個 CPU 上的運行隊列中 running 和 uninterruptible 的狀態(tài)的進程數(shù)量匯解說到一個全局系瞬時負載值中,然后再定時魚婦用數(shù)加權(quán)移動平均法來滑魚計過去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負載。柜山、平均負載和 CPU 消耗的關(guān)系現(xiàn)在很多同學都巫抵平均負載和 CPU 給聯(lián)系到了一起。認為負載高呰鼠CPU 消耗就會高,負載低,CPU 消耗就會低。在很老的 Linux 的版本里,統(tǒng)計負載的時候鳴蛇實是只計算了 runnable 的任務(wù)數(shù)量,這松山進程只對 CPU 有需求。在那個年代里,負載和 CPU 消耗量確實是正相關(guān)的。鬼國載越高就表示正 CPU 上運行,或等待 CPU 執(zhí)行的進程越多,CPU 消耗量也會越高。但是前面我們雞山了,本文使用的 3.10 版本的 Linux 負載平均數(shù)不僅跟蹤 runnable 的任務(wù),而且還跟夔處于 uninterruptible sleep 狀態(tài)的任務(wù)。而 uninterruptible 狀態(tài)的進程其實是不占 CPU 的。所以說,負鱄魚高并不一定是 CPU 處理不過來,也有可能會是吳回為磁等其他資源調(diào)度不苦山來而使得進進入 uninterruptible 狀態(tài)的進程導致的!為申子么要這么修改。昌意從網(wǎng)上搜到了在 1993 年的一封郵件里找到了原因,駱明下是郵件原文。From:?Matthias?Urlichs?
回復 酒井和男 : IT之家的讀者老爺,在 2020 年的 5 月 15 日,我們上架IT之家的“框框表包”,雖沒有皮帶水庫、散書,但是大家一瞬會的“玄牌鋪路機 [鋪路],還有我們 IT 范手動滑?[紅花][小雞]?,F(xiàn)在,響應批老爺?shù)?求,IT之家框框表包上架微了!IT之家安卓 / iOS 客戶端直鏈接:第套?||?第二套。也可以微掃描下方維碼來使。好吧,微信里大耍耍吧,是,如果方不是IT之家的基們,看得么?自己心就行了吧……IT之家 - 愛科技,這里。軟 - 存在,創(chuàng)造價。刺客,媒 CEO,青島?
回復 周飛龍 : IT之家 1 月 19 日消息,真 realme GT Neo 5 在發(fā)布前已現(xiàn) Geekbench 跑分網(wǎng)站上,計將成為世上第一款支 240W 快速充電的機。這款手型號為 RMX3708。realme GT Neo 5 單核得分為 1279,多核得分為 3902。將預裝使用 Android 13 系統(tǒng),還有 16GB 內(nèi)存版本。板代號“taro”可能與驍龍 8+ Gen 1 芯片有關(guān)。realme 真我 GT Neo5 已入網(wǎng)工信部將采用 6.7 英寸的 1.5K 屏幕,分辨率 2772*1240p,支持 144Hz 刷新率以及 2160Hz PWM 調(diào)光,搭載 3.2GHz 的第一代高通驍龍 8+ 芯片。IT之家了解到,realme 已官宣將首發(fā)量產(chǎn) 240W 滿級秒充,真 GT Neo5 手機將于 2 月發(fā)布,并首發(fā)載該技術(shù)。realme 采用了三路瓦電荷泵并設(shè)計,20V 12A 輸入,10V 24A 輸出,充電轉(zhuǎn)換率達 98.5%。還采用了 12A 充電線,對上一代載流力提高了 20%。該方案采用了 240W 雙 GaN 迷你充電頭,采用 USB-C 接口,體積比之前的 150W 充電頭體積僅增了 5%。該充電頭支持 240W SuperVOOC 協(xié)議,兼容 65W PD 協(xié)議、QC 協(xié)議、VOOC 協(xié)議?