回復(fù) 馮鋼 : 感謝IT之家網(wǎng)友 華南吳彥祖 的線索投遞!IT之家 1 月 13 日消息,System76 Pangolin 系列筆記本電腦是輕型記本電腦,備 15.6 英寸顯示屏和 AMD Ryzen 處理器。和有 System76 計(jì)算機(jī)一樣,們預(yù)裝了 GNU / Linux 發(fā)行版。當(dāng) Pangolin 幾年前首次推出時,最初配備了 AMD Ryzen 4000U 處理器。后來,System76 發(fā)布了搭載 Ryzen 5000U 芯片的更新型號?,F(xiàn),Ryzen 6000U 型號正在開發(fā)中。最新本將配備 AMD Ryzen 7 6800U 處理器、15.6 英寸、144Hz、1920 x 1080 像素磨砂顯示,以及高達(dá) 32GB 的 LDDR5-6400 內(nèi)存和高達(dá) 16TB 的 PCIe Gen 4 NVMe 存儲。由于有個 M.2 插槽,存儲以升級,但用 LPDDR5 內(nèi)存表明 RAM 將焊接到主上,用戶無更換。目前不清楚所有號是否都會備 Ryzen 7 芯片或 144 Hz 顯示屏。Pangolin 早期版本已提供 Ryzen 5 和 Ryzen 7 處理器選項(xiàng)因此如果有些不同的配選擇也是合的。其他功預(yù)計(jì)包括 70Wh 容量電池、WiFi 6E 和藍(lán)牙 5.2,以及一組口,包括 HDMI 2.0 和以太網(wǎng)插孔以及 USB 3.2 Gen 2 Type-C。這款筆記本電腦擁有合金底盤、150 度鉸鏈、背光鍵盤還有安全開,確保不使時,可以物地斷開筆記電腦的 720p 網(wǎng)絡(luò)攝像頭。IT之家了解到,的 System76 Pangolin 筆記本電腦尺寸為 371 x 248 x 18 毫米,重量為 1.79 千克。可選擇預(yù)裝 Ubuntu 22.04 LTS 或 Pop!_OS 22.04 軟件,這款筆記本電將于 2 月開始銷售,價 1299 美元(約 8755 元人民幣)起
回復(fù)
冼偉光 : 本文來自微信公眾號開發(fā)內(nèi)功修煉 (ID:kfngxl),作者:張彥飛 allen大家好,我是飛哥!負(fù)載是查看 Linux 服務(wù)器運(yùn)行狀態(tài)時很常用的一個性能指。在觀察線上服務(wù)器行狀況的時候,我們是經(jīng)常把負(fù)載找出來一看。在線上請求壓過大的時候,經(jīng)常是伴隨著負(fù)載的飆高。是負(fù)載的原理你真的解了嗎?我來列舉幾問題,看看你對負(fù)載理解是否足夠的深刻負(fù)載是如何計(jì)算出來?負(fù)載高低和 CPU 消耗正相關(guān)嗎?內(nèi)核是如何暴露負(fù)載數(shù)據(jù)應(yīng)用層的?如果你對上問題的理解還拿捏是很準(zhǔn),那么飛哥今就帶你來深入地了解下 Linux 中的負(fù)載!一、理解負(fù)載看過程我們經(jīng)常用 top 命令查看 Linux 系統(tǒng)的負(fù)載情況。一個典型的 top 命令輸出的負(fù)載如下所示。#?topLoad?Avg:?1.25,?1.30,?1.95??...........輸出中的 Load Avg 就是我們常說的負(fù)載,也叫系統(tǒng)平均負(fù)。因?yàn)閱渭兡骋粋€瞬的負(fù)載值并沒有太大義。所以 Linux 是計(jì)算了過去一段時間內(nèi)的平均值,這三數(shù)分別代表的是過去 1 分鐘、過去 5 分鐘和過去 15 分鐘的平均負(fù)載值。那 top 命令展示的數(shù)據(jù)數(shù)是如何來的呢事實(shí)上,top 命令里的負(fù)載值是從 /proc/ loadavg 這個偽文件里來的。通過 strace 命令跟蹤 top 命令的系統(tǒng)調(diào)用可以看的到這個冰鑒程。#?strace?topopenat(AT_FDCWD,?"/proc/loadavg",?O_RDONLY)?=?7內(nèi)核中定義了 loadavg 這個偽文件的 open 函數(shù)。當(dāng)用戶態(tài)訪問 /proc/ loadavg 會觸發(fā)內(nèi)核定義的函數(shù)在這里會讀取內(nèi)核中平均負(fù)載變量,簡單算后便可展示出來。體流程如下圖所示。們根據(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 中包含了打開該文件時對應(yīng)的作方法。//file:?fs/proc/loadavg.cstatic?const?struct?file_operations?loadavg_proc_fops?=?{?.open??=?loadavg_proc_open,?};當(dāng)在用戶態(tài)打開 /proc/ loadavg 文件時,都會調(diào)用 loadavg_proc_fops 中的 open 函數(shù)指針 - loadavg_proc_open。loadavg_proc_open 接下來會調(diào)用 loadavg_proc_show 進(jìn)行處理,核心的計(jì)算是在這里完成。//file:?fs/proc/loadavg.cstatic?int?loadavg_proc_show(struct?seq_file?*m,?void?*v){?unsigned?long?avnrun[3];?//獲取平均負(fù)載值?get_avenrun(avnrun,?FIXED_1/200,?0);?//打印輸出平均負(fù)載?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 讀取當(dāng)前負(fù)載值將平負(fù)載值按照一定的格打印輸出在上面的源中,大家看到了 FIXED_1/200、LOAD_INT、LOAD_FRAC 等奇奇怪怪的定義,代寫的這么猥瑣是因?yàn)?核中并沒有 float、double 等浮點(diǎn)數(shù)類型,而是用數(shù)來模擬的。這些代都是為了在整數(shù)和小之間轉(zhuǎn)化使的。知道個背景就行了,不用度展開剖析。這樣用通過訪問 /proc/ loadavg 文件就可以讀取到內(nèi)計(jì)算的負(fù)載數(shù)據(jù)了。中獲取 get_avenrun 只是在訪問 avenrun 這個全局?jǐn)?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)核是如何暴露負(fù)數(shù)據(jù)給應(yīng)用層的?內(nèi)定義了一個偽文件 /proc/ loadavg,每當(dāng)用戶打開這個文件的時候,內(nèi)中的 loadavg_proc_show 函數(shù)就會被調(diào)用到,接著訪問 avenrun 全局?jǐn)?shù)組變量 并將平均負(fù)載從整數(shù)化為小數(shù),并打印出。好了,另外一個新題又來了,avenrun 全局?jǐn)?shù)組變量中存儲的數(shù)據(jù)是何時,是被如何計(jì)算出來的?二、內(nèi)核中負(fù)載的算過程接上小節(jié),我繼續(xù)查看 avenrun 全局?jǐn)?shù)組變量的數(shù)據(jù)來源。這個數(shù)組計(jì)算過程分為如下兩:1.PerCPU 定期匯總瞬時負(fù)載:時刷新每個 CPU 當(dāng)前任務(wù)數(shù)到 calc_load_tasks,將每個 CPU 的負(fù)載數(shù)據(jù)匯總起來,得到系統(tǒng)虎蛟前的瞬負(fù)載。2.定時計(jì)算系統(tǒng)平均負(fù)載:定時器據(jù)當(dāng)前系統(tǒng)整體瞬時載,使用指數(shù)加權(quán)移平均法(一種高效計(jì)平均數(shù)的算法)計(jì)算去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負(fù)載。接下來我們分成兩個小來分別介紹。2.1 PerCPU 定期匯總負(fù)載在 Linux 內(nèi)核中,有一個子系統(tǒng)叫做時間子系統(tǒng)。時間子系統(tǒng)里,初始了一個叫高分辨率的時器。在該定時器中定時將每個 CPU 上的負(fù)載數(shù)據(jù)(running 進(jìn)程數(shù) + uninterruptible 進(jìn)程數(shù))匯總到系統(tǒng)全局的時負(fù)載變量 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ù)。其中刷當(dāng)前系統(tǒng)負(fù)載就是在個時機(jī)進(jìn)行的。這里一點(diǎn)要注意一個前提每個 CPU 都有自己獨(dú)立的運(yùn)行隊(duì)列,我們根據(jù) tick_sched_timer 的源碼進(jìn)行追蹤,它依次通過調(diào)用 tick_sched_handle => update_process_times => scheduler_tick。最終在 scheduler_tick 中會刷新當(dāng)前 CPU 上的負(fù)載值到 calc_load_tasks 上。因?yàn)槊總€ CPU 都在定時刷,所以 calc_load_tasks 上記錄的就是整個系統(tǒng)的瞬負(fù)載值。我們來看下責(zé)刷新的 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ù)中,獲取當(dāng)前 cpu 以及其對應(yīng)的運(yùn)行隊(duì)列 rq(run queue),調(diào)用 update_cpu_load_active 刷新當(dāng)前 CPU 的負(fù)載數(shù)據(jù)到全局?jǐn)?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){?//獲取當(dāng)前運(yùn)行隊(duì)列的載相對值?delta??=?calc_load_fold_active(this_rq);?if?(delta)??//添加到全局瞬時負(fù)載??atomic_long_add(delta,?&calc_load_tasks);?}在 calc_load_account_active 中看到,通過 calc_load_fold_active 獲取當(dāng)前運(yùn)行隊(duì)列的負(fù)載相對值,并把它到全局瞬時負(fù)載值 calc_load_tasks 上。至此,calc_load_tasks 上就有了當(dāng)前系統(tǒng)當(dāng)前時間下整體瞬時負(fù)載總數(shù)了我們再展開看看是如根據(jù)運(yùn)行隊(duì)列計(jì)算負(fù)值的://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;}哦,原來是同時計(jì)算了 nr_running 和 nr_uninterruptible 兩種狀態(tài)的進(jìn)程的數(shù)量。對應(yīng)儵魚用戶空中的 R 和 D 兩種狀態(tài)的 task 數(shù)(進(jìn)程 OR 線程)。由于 calc_load_tasks 是一個長期存在的數(shù)據(jù)。所以在刷新 rq 里的進(jìn)程數(shù)到其上的時候,只需要刷變化量就行,不用全部重。因此上述函數(shù)返回是一個 delta。2.2 定時計(jì)算系統(tǒng)平均負(fù)載上一小節(jié)中們找到了系統(tǒng)當(dāng)前瞬負(fù)載 calc_load_tasks 變量的更新過程?,F(xiàn)在們還缺一個計(jì)算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘平均負(fù)載的機(jī)制。統(tǒng)意義上,我們在計(jì)平均數(shù)的時候采取的法都是把過去一段時的數(shù)字都加起來然后均一下。把過去 N 個時間點(diǎn)的所有瞬時載都加起來取一個平數(shù)不完事了。這其實(shí)我們傳統(tǒng)意義上理解平均數(shù),假如有 n 個數(shù)字,分別是 x1, x2, ..., xn。那么這個數(shù)據(jù)集合的平均數(shù)就是 (x1 + x2 + ... + xn) / N。但是如果用這種簡單的算法來計(jì)算均負(fù)載的話,存在以幾個問題:1.需要存儲過去每一個采樣周的數(shù)據(jù)假設(shè)我們每 10 毫秒都采集一次,那么就需要使用一個較大的數(shù)組將每一次樣的數(shù)據(jù)全部都存起,那么統(tǒng)計(jì)過去 15 分鐘的平均數(shù)就得存 1500 個數(shù)據(jù) (15 分鐘 * 每分鐘 100 次) 。而且每出現(xiàn)一個新觀察值,就要從移動均中減去一個最早的察值,再加上一個最的觀察值,內(nèi)存數(shù)組頻繁地修改和更新。2.計(jì)算過程較為復(fù)雜計(jì)算的時候再把整個數(shù)全加起來,再除以樣總數(shù)。雖然加法很簡,但是成百上千個數(shù)的累加仍然很是繁瑣3.不能準(zhǔn)確表示當(dāng)前變化趨勢傳統(tǒng)的平均計(jì)算過程中,所有數(shù)的權(quán)重是一樣的。但于平均負(fù)載這種實(shí)時用來說,其實(shí)越靠近前時刻的數(shù)值權(quán)重應(yīng)越要大一些才好。因這樣能更好反應(yīng)近期化的趨勢。所以,在 Linux 里使用的并不是我們所以為的統(tǒng)的平均數(shù)的計(jì)算方,而是采用的一種指加權(quán)移動平均(Exponential Weighted Moving Average,EMWA)的平均數(shù)計(jì)算法。這種指加權(quán)移動平均數(shù)計(jì)算在深度學(xué)習(xí)中有很廣的應(yīng)用。另外股票市里的 EMA 均線也是使用的是類似的方求均值的方法。該算的數(shù)學(xué)表達(dá)式是:a1 = a0 * factor + a * (1 - factor)。這個算法想理解起來有點(diǎn)小復(fù)雜,興趣的同學(xué)可以 Google 自行搜索。我們只需要知道這種法在實(shí)際計(jì)算的時候需要上一個時間的平數(shù)即可,不需要保存有瞬時負(fù)載值。另外是越靠近現(xiàn)在的時間權(quán)重越高,能夠很好表示近期變化趨勢。其實(shí)也是在時間子系中定時完成的,通過種叫做指數(shù)加權(quán)移動均計(jì)算的方法,計(jì)算三個平均數(shù)。我們來細(xì)看下上圖中的執(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"};當(dāng)每次時鐘節(jié)拍到來時會用到 timer_interrupt,依次會調(diào)用到 do_timer 函數(shù)。//file:kernel/time/timekeeping.cvoid?do_timer(unsigned?long?ticks){???calc_global_load(ticks);}其中 calc_global_load 是平均負(fù)載計(jì)算的核心。它會獲取系當(dāng)前瞬時負(fù)載值 calc_load_tasks,然后來計(jì)算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負(fù)載,并保存到 avenrun 中,供用戶進(jìn)程讀取。//file:kernel/sched/core.cvoid?calc_global_load(unsigned?long?ticks){??//?1獲取當(dāng)前瞬時負(fù)載值?active?=?atomic_long_read(&calc_load_tasks);?//?2平均負(fù)載的計(jì)算?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);?}獲取瞬時負(fù)載比較簡單就是讀取一個內(nèi)存變而已。在 calc_load 中就是采用了我們前面說的指數(shù)權(quán)移動平均法來計(jì)算去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負(fù)載的。具體實(shí)現(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;}雖然這個算法理解起挺復(fù)雜,但是代碼看來確實(shí)要簡單不少,算量看起來很少。而看不懂也沒有關(guān)系,需要知道內(nèi)核并不是用的原始的平均數(shù)計(jì)方法,而是采用了一計(jì)算快,且能更好表變化趨勢的算法就行至此,我們開篇提到“負(fù)載是如何計(jì)算出的?”這個問題也有結(jié)論了。Linux 定時將每個 CPU 上的運(yùn)行隊(duì)列中 running 和 uninterruptible 的狀態(tài)的進(jìn)程數(shù)量匯總到一個全局系瞬時負(fù)載值中,然后定時使用指數(shù)加權(quán)移平均法來統(tǒng)計(jì)過去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負(fù)載。三、平負(fù)載和 CPU 消耗的關(guān)系現(xiàn)在很多同學(xué)將平均負(fù)載和 CPU 給聯(lián)系到了一起。認(rèn)為負(fù)載高、CPU 消耗就會高,負(fù)載低,CPU 消耗就會低。在很老的 Linux 的版本里,統(tǒng)計(jì)負(fù)載時候確實(shí)是只計(jì)算了 runnable 的任務(wù)數(shù)量,這些進(jìn)程對 CPU 有需求。在那個年代里,負(fù)載 CPU 消耗量確實(shí)是正相關(guān)的。負(fù)載越就表示正在 CPU 上運(yùn)行,或等待 CPU 執(zhí)行的進(jìn)程越多,CPU 消耗量也會越高。但是前面我們看了,本文使用的 3.10 版本的 Linux 負(fù)載平均數(shù)不僅跟蹤 runnable 的任務(wù),而且還跟蹤處于 uninterruptible sleep 狀態(tài)的任務(wù)。而 uninterruptible 狀態(tài)的進(jìn)程其實(shí)是不 CPU 的。所以說,負(fù)載高并不一定是 CPU 處理不過來,也有可能會是因?yàn)榇?等其他資源調(diào)度不過而使得進(jìn)程進(jìn)入 uninterruptible 狀態(tài)的進(jìn)程導(dǎo)致的!為什么要這么改。我從網(wǎng)上搜到了在 1993 年的一封郵件里找到了原因以下是郵件原文。From:?Matthias?Urlichs?
回復(fù) 莊楓 : IT之家 1 月 21 日消息,vivo 近日在國際市場上推出了 Y55s 5G 手機(jī),和上月在國內(nèi)市場上出的 Y55s 5G 在外觀上存在差異。國際版 Y55s 5G國內(nèi)版 Y55s 5G國際版 Y55s 5G 手機(jī)配備了 6.58 英寸的 IPS LCD 屏幕,配備 FHD+ 分辨率和 60Hz 刷新率。該機(jī)機(jī)身正采用水滴屏設(shè)計(jì),備了 800 萬像素的自拍攝像頭。IT之家了解到,國際版 Y55s 5G 機(jī)身背面配備了方形的攝像頭模塊曾子括 5000 萬像素的主攝,200 萬像素深度傳感器 200 萬像素微距傳感器。官方提星空黑和銀河藍(lán)兩顏色。該機(jī)配備聯(lián)科八核天璣 700 芯片,最高 6GB+128GB 組合,支持 MicroSD 卡擴(kuò)展。該機(jī)內(nèi)置 5000mAh 容量電池,支持 18W 快充。該機(jī)出廠搭載基于卓 12 的 FuntouchOS 12。