進程/線程上下文切換會用掉你多少CPU?

進程是操作系統的偉大發明之一,對應用程序屏蔽了CPU調度、內存管理等硬件細節,而抽象出一個進程的概念,讓應用程序專心于實現自己的業務邏輯既可,而且在有限的CPU上可以“同時”進行許多個任務。但是它為用戶帶來方便的同時,也引入了一些額外的開銷。如下圖,在進程運行中間的時間里,雖然CPU也在忙于干活,但是卻沒有完成任何的用戶工作,這就是進程機制帶來的額外開銷。

圖1 進程上下文切換

在進程A切換到進程B的過程中,先保存A進程的上下文,以便于等A恢復運行的時候,能夠知道A進程的下一條指令是啥。然后將要運行的B進程的上下文恢復到寄存器中。這個過程被稱為上下文切換。上下文切換開銷在進程不多、切換不頻繁的應用場景下問題不大。但是現在Linux操作系統被用到了高并發的網絡程序后端服務器。在單機支持成千上萬個用戶請求的時候,這個開銷就得拿出來說道說道了。因為用戶進程在請求Redis、Mysql數據等網絡IO阻塞掉的時候,或者在進程時間片到了,都會引發上下文切換。

圖2 進程狀態轉化圖

一個簡單的進程上下文切換開銷測試實驗

廢話不多說,我們先用個實驗測試一下,到底一次上下文切換需要多長的CPU時間!實驗方法是創建兩個進程并在它們之間傳送一個令牌。其中一個進程在讀取令牌時就會引起阻塞。另一個進程發送令牌后等待其返回時也處于阻塞狀態。如此往返傳送一定的次數,然后統計他們的平均單次切換時間開銷。
具體的實驗代碼參見test04

# gcc main.c -o main
# ./main./main
Before Context Switch Time1565352257 s, 774767 us
After Context SWitch Time1565352257 s, 842852 us

每次執行的時間會有差異,多次運行后平均每次上下文切換耗時3.5us左右。當然了這個數字因機器而異,而且建議在實機上測試。

前面我們測試系統調用的時候,最低值是200ns。可見,上下文切換開銷要比系統調用的開銷要大。系統調用只是在進程內將用戶態切換到內核態,然后再切回來,而上下文切換可是直接從進程A切換到了進程B。顯然這個上下文切換需要完成的工作量更大。

進程上下文切換開銷都有哪些

那么上下文切換的時候,CPU的開銷都具體有哪些呢?開銷分成兩種,一種是直接開銷、一種是間接開銷。

直接開銷就是在切換時,cpu必須做的事情,包括:

  • 1、切換頁表全局目錄
  • 2、切換內核態堆棧
  • 3、切換硬件上下文(進程恢復前,必須裝入寄存器的數據統稱為硬件上下文)
    • ip(instruction pointer):指向當前執行指令的下一條指令
    • bp(base pointer): 用于存放執行中的函數對應的棧幀的棧底地址
    • sp(stack poinger): 用于存放執行中的函數對應的棧幀的棧頂地址
    • cr3:頁目錄基址寄存器,保存頁目錄表的物理地址
    • ......

  • 4、刷新TLB
  • 5、系統調度器的代碼執行

間接開銷主要指的是雖然切換到一個新進程后,由于各種緩存并不熱,速度運行會慢一些。如果進程始終都在一個CPU上調度還好一些,如果跨CPU的話,之前熱起來的TLB、L1、L2、L3因為運行的進程已經變了,所以以局部性原理cache起來的代碼、數據也都沒有用了,導致新進程穿透到內存的IO會變多。 其實我們上面的實驗并沒有很好地測量到這種情況,所以實際的上下文切換開銷可能比3.5us要大。

想了解更詳細操作過程的同學請參考《深入理解Linux內核》中的第三章和第九章。

一個更為專業的測試工具-lmbench

lmbench用于評價系統綜合性能的多平臺開源benchmark,能夠測試包括文檔讀寫、內存操作、進程創建銷毀開銷、網絡等性能。使用方法簡單,但就是跑有點慢,感興趣的同學可以自己試一試。
這個工具的優勢是是進行了多組實驗,每組2個進程、8個、16個。每個進程使用的數據大小也在變,充分模擬cache miss造成的影響。我用他測了一下結果如下:

-------------------------------------------------------------------------
Host                 OS  2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K  ctxsw  ctxsw  ctxsw ctxsw  ctxsw   ctxsw   ctxsw  
--------- ------------- ------ ------ ------ ------ ------ ------- -------  
bjzw_46_7 Linux 2.6.32- 2.7800 2.7800 2.7000 4.3800 4.0400 4.75000 5.48000

lmbench顯示的進程上下文切換耗時從2.7us到5.48之間。

線程上下文切換耗時

前面我們測試了進程上下文切換的開銷,我們再繼續在Linux測試一下線程。看看究竟比進程能不能快一些,快的話能快多少。

在Linux下其實本并沒有線程,只是為了迎合開發者口味,搞了個輕量級進程出來就叫做了線程。輕量級進程和進程一樣,都有自己獨立的task_struct進程描述符,也都有自己獨立的pid。從操作系統視角看,調度上和進程沒有什么區別,都是在等待隊列的雙向鏈表里選擇一個task_struct切到運行態而已。只不過輕量級進程和普通進程的區別是可以共享同一內存地址空間、代碼段、全局變量、同一打開文件集合而已。

同一進程下的線程之所有getpid()看到的pid是一樣的,其實task_struct里還有一個tgid字段。 對于多線程程序來說,getpid()系統調用獲取的實際上是這個tgid,因此隸屬同一進程的多線程看起來PID相同。

我們用一個實驗來測試一下test06。其原理和進程測試差不多,創建了20個線程,在線程之間通過管道來傳遞信號。接到信號就喚醒,然后再傳遞信號給下一個線程,自己睡眠。 這個實驗里單獨考慮了給管道傳遞信號的額外開銷,并在第一步就統計了出來。

# gcc -lpthread main.c -o main
0.508250  
4.363495

每次實驗結果會有一些差異,上面的結果是取了多次的結果之后然后平均的,大約每次線程切換開銷大約是3.8us左右。從上下文切換的耗時上來看,Linux線程(輕量級進程)其實和進程差別不太大

Linux相關命令

既然我們知道了上下文切換比較的消耗CPU時間,那么我們通過什么工具可以查看一下Linux里究竟在發生多少切換呢?如果上下文切換已經影響到了系統整體性能,我們有沒有辦法把有問題的進程揪出來,并把它優化掉呢?

# vmstat 1  
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----  r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st  2  0      0 595504   5724 190884    0    0   295   297    0    0 14  6 75  0  4  5  0      0 593016   5732 193288    0    0     0    92 19889 29104 20  6 67  0  7  3  0      0 591292   5732 195476    0    0     0     0 20151 28487 20  6 66  0  8  4  0      0 589296   5732 196800    0    0   116   384 19326 27693 20  7 67  0  7  4  0      0 586956   5740 199496    0    0   216    24 18321 24018 22  8 62  0  8

或者是

# sar -w 1  
proc/s  Total number of tasks created per second.  
cswch/s  Total number of context switches per second.  
11:19:20 AM    proc/s   cswch/s  
11:19:21 AM    110.28  23468.22  
11:19:22 AM    128.85  33910.58  
11:19:23 AM     47.52  40733.66  
11:19:24 AM     35.85  30972.64  
11:19:25 AM     47.62  24951.43  
11:19:26 AM     47.52  42950.50  
......

上圖的環境是一臺生產環境機器,配置是8核8G的KVM虛機,環境是在nginx+fpm的,fpm數量為1000,平均每秒處理的用戶接口請求大約100左右。其中cs列表示的就是在1s內系統發生的上下文切換次數,大約1s切換次數都達到4W次了。粗略估算一下,每核大約每秒需要切換5K次,則1s內需要花將近20ms在上下文切換上。要知道這是虛機,本身在虛擬化上還會有一些額外開銷,而且還要真正消耗CPU在用戶接口邏輯處理、系統調用內核邏輯處理、以及網絡連接的處理以及軟中斷,所以20ms的開銷實際上不低了。

那么進一步,我們看下到底是哪些進程導致了頻繁的上下文切換?

# pidstat -w 1  
11:07:56 AM       PID   cswch/s nvcswch/s  Command
11:07:56 AM     32316      4.00      0.00  php-fpm  
11:07:56 AM     32508    160.00     34.00  php-fpm  
11:07:56 AM     32726    131.00      8.00  php-fpm  
......

由于fpm是同步阻塞的模式,每當請求Redis、Memcache、Mysql的時候就會阻塞導致cswch/s自愿上下文切換,而只有時間片到了之后才會觸發nvcswch/s非自愿切換。可見fpm進程大部分的切換都是自愿的、非自愿的比較少。

如果想查看具體某個進程的上下文切換總情況,可以在/proc接口下直接看,不過這個是總值。

grep ctxt /proc/32583/status  
voluntary_ctxt_switches:        573066  
nonvoluntary_ctxt_switches:     89260

本節結論

上下文切換具體做哪些事情我們沒有必要記,只需要記住一個結論既可,測得作者開發機上下文切換的開銷大約是2.7-5.48us左右,你自己的機器可以用我提供的代碼或工具進行一番測試。
lmbench相對更準確一些,因為考慮了切換后Cache miss導致的額外開銷。

個人公眾號“開發內功修煉”,打通理論與實踐的任督二脈。

參考文獻

  • 進程上下文切換,殘酷的性能殺手
  • 測試上下文切換開銷
  • 進程上下文切換導致Load過高
  • CPU上下文切換的次數和時間
  • Linux操作系統測試工具
  • lmbench官方文檔
  • lmbench安裝與使用

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40049.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40049.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40049.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

嵌入式Linux Qt5 (C++)開發欄目概述

本欄目開始介紹Linux系統下的Qt C程序開發,資源是以嵌入式為切入點(現在Linux系統下的Qt C程序開發好像就是應用于嵌入式),那就跟著一起學習Linux系統下的Qt C程序開發知識,再擴展一下嵌入式的知識吧。我這里默認已經熟…

php初解

php是什么? PHP,全稱 Hypertext Preprocessor ,中文翻譯“超文本預處理器”。 PHP是一種被廣泛應用的開源通用腳本語言,尤其適用于 Web 開發。 擁有快速,靈活,實用的特點,PHP能做任何事&#xf…

ORACLE中UNION、UNION ALL、MINUS、INTERSECT學習

1、UNION和UNION ALL的使用與區別 如果我們需要將兩個select語句的結果作為一個整體顯示出來,我們就需要用到union或者union all關鍵字。union的作用是將多個結果合并在一起顯示出來。 union和union all的區別是union會自動壓縮多個結果集合中的重復結果&#xff…

高速下載VisualGLM模型文件的解決方案

大家好,我是愛編程的喵喵。雙985碩士畢業,現擔任全棧工程師一職,熱衷于將數據思維應用到工作與生活中。從事機器學習以及相關的前后端開發工作。曾在阿里云、科大訊飛、CCF等比賽獲得多次Top名次。現為CSDN博客專家、人工智能領域優質創作者。喜歡通過博客創作的方式對所學的…

GO語言自底向上優化

Go Ballast(通過嘗試降低 GC 頻率以提高整體性能,針對所有 Go應用都適用) 首先我們明白GO語言GC觸發條件是由比例來觸發的。例如,當前存活內存10GB,觸發比例是100%,因此下次觸發GC的時候是當內存達到20GB的時候觸發GC。這種機制在…

碎片筆記|圖數據與圖神經網絡基礎介紹

前言:前段時間了解了一下圖神經網絡,本篇博客記錄一下相關知識,以備不時之需。 強烈推薦這篇博客(作者來自 Google Research),個人認為是圖神經網絡基礎入門的不二選擇! 目錄 一、圖數據1.1 定義…

Windows上使用FFmpeg實現本地視頻推送模擬海康協議rtsp視頻流

場景 Nginx搭建RTMP服務器FFmpeg實現海康威視攝像頭預覽: Nginx搭建RTMP服務器FFmpeg實現海康威視攝像頭預覽_nginx rtmp 海康攝像頭_霸道流氓氣質的博客-CSDN博客 上面記錄的是使用FFmpeg拉取海康協議攝像頭的rtsp流并推流到流媒體服務器。 如果在其它業務場景…

TCP/IP協議組

TCP/IP通信協議是目前最完整、使用最廣泛的通信協議。它的魅力在于可使不同硬件結構、不同操作系統的計算機相互通信。TCP/IP協議既可用于廣域網,也可用于局域網,它是Internet/Intranet的基石。TCP/IP通信協議事實上是一組協議。 TCP/IP協議可分為5層也可…

使用 Redis 實現共享 Session 的高效解決方案

系列文章目錄 文章目錄 系列文章目錄前言一、為什么需要共享 Session?二、使用 Redis 實現共享 Session1.安裝和配置 Redis2.實現 Session 存取操作3.使用 Session 數據三、測試共享 Session四、注意事項總結前言 在分布式系統中,實現共享 Session 是一個重要的問題。本文將…

GT Code - 圖譯算法編輯器(集成QT、C++、C、Linux、Git、java、web、go、高并發、服務器、分布式、網絡編程、云計算、大數據項目)

目錄 項目概述 發文意義 項目介紹 功能分析 設計概要 功能展示 項目文檔 項目概述 “GT Code 圖譯算法編輯器”是一款跨平臺、輕量級的代碼編輯器,主要面向軟件開發人員,它實現了編輯、編譯、繪制代碼流程圖、生成調試演示動畫等功能,以…

go版本glog/klog 參數使用方法心得

問題 glog很好用,但是官方文檔卻很爛,對于很多參數并沒有做詳細說明,于是通過看源碼測試,總結出以下使用方法 可選參數 flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error in…

空間分析專屬 Python 學習資料

空間數據分析能夠幫助我們更好地理解地理空間中的模式和關系,從而為決策提供支持。例如,城市規劃者可以使用空間數據分析來確定城市發展的最佳方向,環境科學家可以使用空間數據分析來評估污染的影響,而商業分析師可以使用空間數據…

react go實現用戶歷史登錄列表頁面

refer: http://ip-api.com/ 1.首先需要創建一個保存用戶歷史的登錄的表,然后連接go 2.在用戶登錄的時候,獲取用戶的IP IP位置,在后端直接處理數據即可(不需要在前端傳遞數據) (1)增加路由&am…

使用Java服務器實現UDP消息的發送和接收(多線程)

目錄 簡介:1. 導入必要的庫2. 創建服務器端代碼3. 創建客戶端代碼4. 實現多線程處理5. 測試運行示例代碼:函數說明服務器端代碼說明:客戶端代碼說明: 總結: 簡介: 在本篇博客中,我們將介紹如何…

genism word2vec方法

文章目錄 概述使用示例模型的保存與使用訓練參數詳解([原鏈接](https://blog.csdn.net/weixin_44852067/article/details/130221655))語料庫訓練 概述 word2vec是按句子來處理的Sentences(句子們) 使用示例 from gensim.models import Word2Vec #sent…

《起風了》C++源代碼

使用方法 Visual Studio、Dev-C、Visual Studio Code等C/C創建一個 .cpp 文件&#xff0c;直接粘貼賦值即可。 #include <iostream> #include <Windows.h> #pragma comment(lib,"winmm.lib") using namespace std; enum Scale {Rest 0, C8 108, B7 …

目錄——車載網絡安全

本文主要匯總車載網絡安全專欄文章,以方便各位讀者閱讀。 ISO21434 概述(一) ISO21434 組織網絡安全管理(二) ISO21434 項目網絡安全管理(三) ISO21434 分布式網絡安全(四) SO21434 持續進行的網絡安全(五) ISO21434 概念階段網絡安全(六)

線性代數(四) 特征值相似矩陣

前言 前面主要講述的是方程組和矩陣的關系&#xff0c;現在了解下矩陣和矩陣的關系 方陣的特征值與特征向量 假設A為n階方陣&#xff0c;對于一個數 λ \lambda λ 若存在&#xff1a;非零列向量 α \alpha α&#xff0c;使得&#xff1a; A α ? λ α ? A\vec{\alp…

2022年電賽C題——小車跟隨行駛系統——做題記錄以及經驗分享

前言 自己打算將做過的電賽真題&#xff0c;主要包含控制組的&#xff0c;近幾年出現的小車控制題目&#xff0c;自己做過的真題以及在準備電賽期間刷真題出現的問題以及經驗分享給大家 這次帶來的是22年電賽C題——小車跟隨行駛系統&#xff0c;這道題目指定使用的是TI的單片…

spring ico容器 spring注入方式 spring與tomcat整合

一、簡介 1、什么是spring&#xff1f; Spring是一個開源的輕量級Java應用開發框架&#xff0c;它提供了一種簡單、高效、靈活的方式來構建企業級應用程序。Spring框架的核心特點是依賴注入&#xff08;Dependency Injection&#xff09;和面向切面編程&#xff08;Aspect-Ori…