回復(fù) 薩拉·科朗吉洛 : IT之家 1 月 15 日消息,三已經(jīng)敲定將 2 月 1 日推出 Galaxy S23 系列,爆料人士 Evan Blass(網(wǎng)名 @Elveaks)分享了三星 Galaxy S23 Ultra 的官方硅膠和左翻蓋保護(hù)套染圖。IT之家從 Evan Blass 的渲染圖中了解到,星為 Galaxy S23 Ultra 提供的硅膠保護(hù)套有色、藍(lán)色、色和淺粉色種顏色。這保護(hù)套由三設(shè)計(jì),并在內(nèi)生產(chǎn),保套內(nèi)部由“Designed by Samsung,Made in China”字樣。Galaxy S23 Ultra 的左右翻蓋保套有黑色、粉色、綠色米色可供選,與旗艦產(chǎn)的標(biāo)準(zhǔn)顏色似?
回復(fù) Palmer : IT之家 1 月 15 日消息,KDE 項(xiàng)目團(tuán)隊(duì)于今天出了 KDE Frameworks 5.102 版本更新。本次更新中值得關(guān)注的改就是,KDE Connect 應(yīng)用中支持傳輸超過 2GB 大小的文件。IT之家小課堂:KDE Connect 應(yīng)用是一款允許戶在移動(dòng)設(shè)備電腦之間傳輸件的應(yīng)用,也持接收通知、制媒體播放器功能。KDE Frameworks 5.102 另一個(gè)值得關(guān)注的改進(jìn)是 Meta Key 等修改鍵。這個(gè)變化出現(xiàn)在即將到的 KDE Plasma 5.27 桌面環(huán)境系列中,KDE 開發(fā)者希望取代 KWin 窗口和復(fù)合管理器中奇燕山的修改器鍵處理式,這樣你就以直接將修改鍵分配給 Kickoff 或 Overview。KDE Frameworks 5.102 更新還支持在“打開”話框的目錄選器字段中,使其完整文件路訪問文件。在啟過程中支持Always use Touch Mode”;在基于 Kirigami 的應(yīng)用程序中,支持使用 Esc 鍵或通過點(diǎn)擊視圖中的暗區(qū)關(guān)閉側(cè)抽。KDE Frameworks 5.102 還改進(jìn)了 Plasma Wayland 會(huì)話,修復(fù)了個(gè)和粘貼相關(guān)問題。這次 KDE Frameworks 的更新包含了過 140 個(gè)變化,所以請(qǐng)看發(fā)布公告頁(yè)上的完整更新志以了解更多節(jié)?
回復(fù)
拉蒙·梅嫩德斯 : 本文來自微信公眾:開發(fā)內(nèi)功修煉 (ID:kfngxl),作者:張彥飛 allen大家好,我是飛哥!負(fù)載是看 Linux 服務(wù)器運(yùn)行狀態(tài)時(shí)很用的一個(gè)性能指標(biāo)在觀察線上服務(wù)器行狀況的時(shí)候,我也是經(jīng)常把負(fù)載找來看一看。在線上求壓力過大的時(shí)候經(jīng)常是也伴隨著負(fù)的飆高。但是負(fù)載原理你真的理解了?我來列舉幾個(gè)問,看看你對(duì)負(fù)載的解是否足夠的深刻負(fù)載是如何計(jì)算出的?負(fù)載高低和 CPU 消耗正相關(guān)嗎??jī)?nèi)核是如何暴露載數(shù)據(jù)給應(yīng)用層的如果你對(duì)以上問題理解還拿捏不是很,那么飛哥今天就你來深入地了解一 Linux 中的負(fù)載!一、理解負(fù)查看過程我們經(jīng)常 top 命令查看 Linux 系統(tǒng)的負(fù)載情況。一個(gè)型的 top 命令輸出的負(fù)載如下所。#?topLoad?Avg:?1.25,?1.30,?1.95??...........輸出中的 Load Avg 就是我們常說的負(fù)載,也叫統(tǒng)平均負(fù)載。因?yàn)?純某一個(gè)瞬時(shí)的負(fù)值并沒有太大意義所以 Linux 是計(jì)算了過去一段間內(nèi)的平均值,這個(gè)數(shù)分別代表的是去 1 分鐘、過去 5 分鐘和過去 15 分鐘的平均負(fù)載值。那么 top 命令展示的數(shù)據(jù)數(shù)是如何來的呢?事上,top 命令里的負(fù)載值是從 /proc/ loadavg 這個(gè)偽文件里來的。通過 strace 命令跟蹤 top 命令的系統(tǒng)調(diào)用可以看的到個(gè)過程。#?strace?topopenat(AT_FDCWD,?"/proc/loadavg",?O_RDONLY)?=?7內(nèi)核中定義了 loadavg 這個(gè)偽文件的 open 函數(shù)。當(dāng)用戶態(tài)訪 /proc/ loadavg 會(huì)觸發(fā)內(nèi)核定義的函數(shù)在這里會(huì)讀取內(nèi)核的平均負(fù)載變量,單計(jì)算后便可展示來。整體流程如下所示。我們根據(jù)上流程圖再展開了看。偽文件 /proc/ loadavg 在 kernel 中定義是在 /fs/ proc / loadavg.c 中。在該文件中會(huì)創(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 中包含了打開該文件時(shí)對(duì)應(yīng)的操作無淫。//file:?fs/proc/loadavg.cstatic?const?struct?file_operations?loadavg_proc_fops?=?{?.open??=?loadavg_proc_open,?};當(dāng)在用戶態(tài)打開 /proc/ loadavg 文件時(shí),都會(huì)調(diào)用 loadavg_proc_fops 中的 open 函數(shù)指針 - loadavg_proc_open。loadavg_proc_open 接下來會(huì)調(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)閮?nèi)中并沒有 float、double 等浮點(diǎn)數(shù)類型,而用整數(shù)來模擬的。些代碼都是為了在數(shù)和小數(shù)之間轉(zhuǎn)化的。知道這個(gè)背景行了,不用過度展剖析。這樣用戶通訪問 /proc/ loadavg 文件就可以讀取到核計(jì)算的負(fù)載數(shù)據(jù)。其中獲取 get_avenrun 只是在訪問 avenrun 這個(gè)全局?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)層的??jī)?nèi)核定義了個(gè)偽文件 /proc/ loadavg,每當(dāng)用戶打開這個(gè)文件的時(shí)候弇茲內(nèi)中的 loadavg_proc_show 函數(shù)就會(huì)被調(diào)用到,接著訪問 avenrun 全局?jǐn)?shù)組變量 并將平均負(fù)載從整數(shù)轉(zhuǎn)化為數(shù),并打印出來。了,另外一個(gè)新問又來了,avenrun 全局?jǐn)?shù)組變量中存儲(chǔ)的數(shù)據(jù)是何,又是被如何計(jì)算來的呢?二、內(nèi)核負(fù)載的計(jì)算過程接小節(jié),我們繼續(xù)查 avenrun 全局?jǐn)?shù)組變量的數(shù)來源。這個(gè)數(shù)組的算過程分為如下兩:1.PerCPU 定期匯總瞬時(shí)負(fù)載:定時(shí)刷新役采個(gè) CPU 當(dāng)前任務(wù)數(shù)到 calc_load_tasks,將每個(gè) CPU 的負(fù)載數(shù)據(jù)匯總起來,到系統(tǒng)當(dāng)前的瞬時(shí)載。2.定時(shí)計(jì)算系統(tǒng)平均負(fù)載:定時(shí)根據(jù)當(dāng)前系統(tǒng)整體時(shí)負(fù)載,使用指數(shù)權(quán)移動(dòng)平均法(一高效計(jì)算平均數(shù)的法)計(jì)算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負(fù)載。接來我們分成兩個(gè)小來分別介紹。2.1 PerCPU 定期匯總負(fù)載在 Linux 內(nèi)核中,有一個(gè)子系統(tǒng)叫做時(shí)子系統(tǒng)。在時(shí)間子統(tǒng)里,初始化了一叫高分辨率的定時(shí)。在該定時(shí)器中會(huì)時(shí)將每個(gè) CPU 上的負(fù)載數(shù)據(jù)(running 進(jìn)程數(shù) + uninterruptible 進(jìn)程數(shù))匯總到系統(tǒng)全局的瞬時(shí)負(fù)載量 calc_load_tasks 中。整體流程如下所示。我們把上述程圖展開看一下,們找到了高分辨率時(shí)器的源碼如下://file:kernel/time/tick-sched.cvoid?tick_setup_sched_timer(void){?//初始化高分辨率定時(shí)器?sched_timer?hrtimer_init(&ts-sched_timer,?CLOCK_MONOTONIC,?HRTIMER_MODE_ABS);?//將定時(shí)器的到期函數(shù)設(shè)置?tick_sched_timer?ts-sched_timer.function?=?tick_sched_timer;?}在高分辨率初始化的候,將到期函數(shù)設(shè)成了 tick_sched_timer。通過這個(gè)函數(shù)讓每個(gè) CPU 都會(huì)周期性地執(zhí)行一些務(wù)。其中刷新當(dāng)前統(tǒng)負(fù)載就是在這個(gè)機(jī)進(jìn)行的。這里有點(diǎn)要注意一個(gè)前提每個(gè) CPU 都有自己獨(dú)立的運(yùn)行隊(duì),。我們根據(jù) tick_sched_timer 的源碼進(jìn)行追蹤,它依次過調(diào)用 tick_sched_handle => update_process_times => scheduler_tick。最終在 scheduler_tick 中會(huì)刷新當(dāng)前 CPU 上的負(fù)載值到 calc_load_tasks 上。因?yàn)槊總€(gè) CPU 都在定時(shí)刷,所以 calc_load_tasks 上記錄的就是整個(gè)統(tǒng)的瞬時(shí)負(fù)載值。們來看下負(fù)責(zé)刷新 scheduler_tick 這個(gè)核心函數(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);?}在這個(gè)函數(shù)中,獲取當(dāng)前 cpu 以及其對(duì)應(yīng)的運(yùn)行列 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ì)列的負(fù)載對(duì)值?delta??=?calc_load_fold_active(this_rq);?if?(delta)??//添加到全局瞬時(shí)負(fù)載值??atomic_long_add(delta,?&calc_load_tasks);?}在 calc_load_account_active 中看到,通過 calc_load_fold_active 獲取當(dāng)前運(yùn)行隊(duì)列的負(fù)相對(duì)值,并把它加全局瞬時(shí)負(fù)載值 calc_load_tasks 上。至此,calc_load_tasks 上就有了當(dāng)前系統(tǒng)前時(shí)間下的整體瞬負(fù)載總數(shù)了。我們展開看看是如何根運(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;}哦,原來是同時(shí)計(jì)算 nr_running 和 nr_uninterruptible 兩種狀態(tài)的進(jìn)程的數(shù)量。應(yīng)于用戶空間中的 R 和 D 兩種狀態(tài)的 task 數(shù)(進(jìn)程 OR 線程)。由于 calc_load_tasks 是一個(gè)長(zhǎng)期存在的數(shù)據(jù)。所以在新 rq 里的進(jìn)程數(shù)到其上的時(shí)候,需要刷變化的量就,不用全部重算。此上述函數(shù)返回的一個(gè) delta。2.2 定時(shí)計(jì)算系統(tǒng)平均負(fù)載上一小中我們找到了系統(tǒng)前瞬時(shí)負(fù)載 calc_load_tasks 變量的更新過程。現(xiàn)在我們還一個(gè)計(jì)算過去 1 分鐘、過去 5 分鐘、過去 15 分鐘平均負(fù)載的機(jī)制傳統(tǒng)意義上,我們計(jì)算平均數(shù)的時(shí)候取的方法都是把過一段時(shí)間的數(shù)字都起來然后平均一下把過去 N 個(gè)時(shí)間點(diǎn)的所有瞬時(shí)負(fù)載加起來取一個(gè)平均不完事了。這其實(shí)我們傳統(tǒng)意義上理的平均數(shù),假如有 n 個(gè)數(shù)字,分別是 x1, x2, ..., xn。那么這個(gè)數(shù)據(jù)集合的均數(shù)就是 (x1 + x2 + ... + xn) / N。但是如果用這種簡(jiǎn)單的算法來計(jì)平均負(fù)載的話,存以下幾個(gè)問題:1.需要存儲(chǔ)過去每一采樣周期的數(shù)據(jù)假我們每 10 毫秒都采集一次,那么需要使用一個(gè)比較的數(shù)組將每一次采的數(shù)據(jù)全部都存起,那么統(tǒng)計(jì)過去 15 分鐘的平均數(shù)就得存 1500 個(gè)數(shù)據(jù) (15 分鐘 * 每分鐘 100 次) 。而且每出現(xiàn)一個(gè)新的觀察,就要從移動(dòng)平均減去一個(gè)最早的觀值,再加上一個(gè)最的觀察值,內(nèi)存數(shù)會(huì)頻繁地修改和更。2.計(jì)算過程較為復(fù)雜計(jì)算的時(shí)候再整個(gè)數(shù)組全加起來再除以樣本總數(shù)。然加法很簡(jiǎn)單,但成百上千個(gè)數(shù)字的加仍然很是繁瑣。3.不能準(zhǔn)確表示當(dāng)前變化趨勢(shì)傳統(tǒng)的平數(shù)計(jì)算過程中,所數(shù)字的權(quán)重是一樣。但對(duì)于平均負(fù)載種實(shí)時(shí)應(yīng)用來說,實(shí)越靠近當(dāng)前時(shí)刻數(shù)值權(quán)重應(yīng)該越要一些才好。因?yàn)檫@能更好反應(yīng)近期變的趨勢(shì)。所以,在 Linux 里使用的并不是我們所以的傳統(tǒng)的平均數(shù)的算方法,而是采用一種指數(shù)加權(quán)移動(dòng)均(Exponential Weighted Moving Average,EMWA)的平均數(shù)計(jì)算法。這種數(shù)加權(quán)移動(dòng)平均數(shù)算法在深度學(xué)習(xí)中很廣泛的應(yīng)用。另股票市場(chǎng)里的 EMA 均線也是使用的是類似的方法求均的方法。該算法的學(xué)表達(dá)式是:a1 = a0 * factor + a * (1 - factor)。這個(gè)算法想理解起來有點(diǎn)復(fù)雜,感興趣的同可以 Google 自行搜索。我們只需要知道這赤鷩方法實(shí)際計(jì)算的時(shí)候只要上一個(gè)時(shí)間的平數(shù)即可,不需要保所有瞬時(shí)負(fù)載值。外就是越靠近現(xiàn)在時(shí)間點(diǎn)權(quán)重越高,夠很好地表示近期化趨勢(shì)。這其實(shí)也在時(shí)間子系統(tǒng)中定完成的,通過一種做指數(shù)加權(quán)移動(dòng)平計(jì)算的方法,計(jì)算三個(gè)平均數(shù)。我們詳細(xì)看下上圖中的行過程。時(shí)間子系將在時(shí)鐘中斷中會(huì)冊(cè)時(shí)鐘中斷的處理數(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)每次時(shí)鐘節(jié)拍到來時(shí)會(huì)調(diào)用 timer_interrupt,依次會(huì)調(diào)用到 do_timer 函數(shù)。//file:kernel/time/timekeeping.cvoid?do_timer(unsigned?long?ticks){???calc_global_load(ticks);}其中 calc_global_load 是平均負(fù)載計(jì)算的核心它會(huì)獲取系統(tǒng)當(dāng)前時(shí)負(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)前瞬時(shí)負(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);?}獲取瞬時(shí)負(fù)載比較簡(jiǎn)單就是讀取一個(gè)內(nèi)存量而已。在 calc_load 中就是采用了我們前面的指數(shù)加權(quán)移動(dòng)平法來計(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;}雖然這個(gè)算法理解起來復(fù)雜,但是代碼看來確實(shí)要簡(jiǎn)單不少計(jì)算量看起來很少而且看不懂也沒有系,只需要知道內(nèi)并不是采用的原始平均數(shù)計(jì)算方法,是采用了一種計(jì)算,且能更好表達(dá)變趨勢(shì)的算法就行。此,我們開篇提到“負(fù)載是如何計(jì)算來的?”這個(gè)問題也有結(jié)論了。Linux 定時(shí)將每個(gè) CPU 上的運(yùn)行隊(duì)列中 running 和 uninterruptible 的狀態(tài)的進(jìn)程數(shù)量匯總到一個(gè)全局?魚瞬時(shí)負(fù)載值中,然再定時(shí)使用指數(shù)加移動(dòng)平均法來統(tǒng)計(jì)去 1 分鐘、過去 5 分鐘、過去 15 分鐘的平均負(fù)載。三、平均負(fù)載 CPU 消耗的關(guān)系現(xiàn)在很多同學(xué)都平均負(fù)載和 CPU 給聯(lián)系到了一起。認(rèn)為負(fù)載高、CPU 消耗就會(huì)高,負(fù)載低,CPU 消耗就會(huì)低。在很老的 Linux 的版本里,統(tǒng)計(jì)負(fù)載的時(shí)候實(shí)是只計(jì)算了 runnable 的任務(wù)數(shù)量,這些進(jìn)程對(duì) CPU 有需求。在那個(gè)年代里,載和 CPU 消耗量確實(shí)是正相關(guān)的負(fù)載越高就表示正 CPU 上運(yùn)行,或等待 CPU 執(zhí)行的進(jìn)程越多,CPU 消耗量也會(huì)越高。但是前面我們看了,本文使用的 3.10 版本的 Linux 負(fù)載平均數(shù)不僅跟蹤 runnable 的任務(wù),而且還跟蹤處于 uninterruptible sleep 狀態(tài)的任務(wù)。而 uninterruptible 狀態(tài)的進(jìn)程其實(shí)是不占 CPU 的。所以說,負(fù)載高并一定是 CPU 處理不過來,也有可會(huì)是因?yàn)榇疟P等其資源調(diào)度不過來而得進(jìn)程進(jìn)入 uninterruptible 狀態(tài)的進(jìn)程導(dǎo)致的!為什么要么修改。我從網(wǎng)上到了遠(yuǎn)在 1993 年的一封郵件里找到了原因,以下是件原文。From:?Matthias?Urlichs?