Linux에서 CPU 사용률은 어떻게 계산됩니까?
온라인 서버에서 온라인 서비스의 실행 상태를 관찰할 때 대부분의 사람들은 현재 시스템의 전체 CPU 사용률을 확인하기 위해 top 명령을 먼저 사용하는 것을 선호합니다. 예를 들어 임의 머신의 경우 top 명령으로 표시되는 활용도 정보는 다음과 같습니다.

이 출력 결과는 말 그대로 간단하지만, 복잡하더라도 모든 것을 이해하기는 쉽지 않습니다. 예:
질문 1: 상단에서 출력되는 활용 정보는 어떻게 계산되나요?
질문 2: ni 열은 처리 시 CPU 오버헤드를 출력하는 것이 좋습니다.
질문 3: wa는 io 대기를 나타냅니다. 그러면 이 기간 동안 CPU가 사용 중입니까 아니면 유휴 상태입니까?
오늘은 CPU 사용률 통계에 대해 심층적으로 연구했습니다. 오늘의 연구를 통해 CPU 사용률 통계의 구현 세부 사항을 이해할 수 있을 뿐만 아니라 nice 및 io wait와 같은 지표에 대한 더 깊은 이해를 갖게 됩니다.
오늘은 각자의 생각부터 시작해보겠습니다!
1. 먼저 생각해보세요
Linux 구현은 제쳐두고, 다음 요구 사항이 있는 경우 4개의 프로세스가 실행되는 쿼드 코어 서버가 있는 것입니다.

전체 시스템의 CPU 사용률을 설계하고 계산할 수 있으며 top 명령과 같은 출력을 지원하며 다음 요구 사항을 충족합니다.
- CPU 사용량은 최대한 정확해야 합니다.
- 순간적인 CPU 상태를 최대한 2차 레벨에 반영하는 것이 필요합니다.
몇 분 동안 멈춰서 생각해 보세요.

좋아, 생각 끝. 곰곰이 생각해보면 간단해 보이는 이 요구 사항이 실제로는 다소 복잡하다는 것을 알게 될 것입니다.
한 가지 아이디어는 모든 프로세스의 실행 시간을 더한 다음 이를 총 시스템 실행 시간 * 4로 나누는 것입니다.

이 방법을 사용하면 장기간에 걸쳐 CPU 사용률을 계산할 수 있으며 통계도 충분히 정확합니다.
하지만 top을 사용했다면 top에 의해 출력된 CPU 사용률이 오랫동안 일정하지 않고 기본적으로 3초 단위로 동적으로 업데이트된다는 것을 알게 될 것입니다. (이 시간 간격은 -d를 사용하여 설정할 수 있습니다. ). 우리 솔루션은 전체 사용량을 반영할 수 있지만, 이러한 순간적인 상태를 반영하는 것은 어렵습니다. 3초에 1개로 셀 수 있다고 생각하실 수도 있겠네요. 그런데 이 3초의 시간은 어느 시점에서 시작되는가. 세분성은 제어하기 어렵습니다.
앞서 생각하는 질문의 핵심은 순간적인 문제를 어떻게 해결하느냐입니다. 일시적인 상태에 관해서는 다른 아이디어가 있을 수 있습니다. 그런 다음 인스턴트 샘플링을 사용하여 현재 사용 중인 코어 수를 확인합니다. 4개의 코어 중 2개가 사용 중인 경우 사용률은 50%입니다.
이런 생각도 올바른 방향이지만 두 가지 문제가 있습니다.
- 계산한 숫자는 모두 25%의 배수입니다.
- 이 순간 값으로 인해 CPU 사용량 표시가 크게 바뀔 수 있습니다.
예를 들어 아래 사진은

t1의 순간 상태에서는 시스템의 CPU 사용률이 의심할 바 없이 100%인데, t2의 관점에서는 사용률이 0%가 되었습니다. 아이디어는 올바른 방향이지만 분명히 이 조잡한 계산은 최상위 명령만큼 우아하게 작동할 수 없습니다.
이를 개선하고 위의 두 가지 아이디어를 결합하면 문제를 해결할 수 있을 것입니다. 샘플링 측면에서는 주기를 더 세밀하게 설정했지만, 계산 측면에서는 주기를 더 성기게 설정했습니다.
1ms마다 샘플링하는 등 채택 기간, 타이밍 개념을 소개합니다. 샘플링 순간에 CPU가 실행 중이면 이 1ms가 사용된 것으로 기록됩니다. 이때 순간적인 CPU 사용량을 얻어서 저장하게 됩니다.

위 그림의 t1 및 t2 시간 범위와 같이 3초 이내의 CPU 사용량을 계산할 때. 그런 다음 이 기간 동안의 모든 순간 값을 더하고 평균값을 취합니다. 이를 통해 위의 문제를 해결할 수 있고, 통계가 비교적 정확하며, 순시값이 격렬하게 진동하고 너무 거칠게(25% 단위로만 변경 가능) 발생하는 문제를 피할 수 있습니다.
아래 그림과 같이 두 샘플링 사이에 CPU가 변경되면 어떻게 되는지 궁금해하는 학생들도 있습니다.

현재 샘플링 지점에 도달하면 프로세스 A가 잠시 동안 실행을 마쳤으며 이전 샘플링 지점에서도 계산되지 않았으며 이번에도 계산될 수 없습니다. 프로세스 B의 경우 실제로는 짧은 시간 동안만 시작되었으므로 1ms를 모두 기록하기에는 좀 무리인 것 같습니다.
이 문제는 존재하지만 우리 샘플링은 한 번 1ms이고 실제로 확인하고 사용할 때 적어도 수천 개의 샘플링 지점의 정보를 포함하는 두 번째 수준이므로 이 오류는 발생하지 않습니다. 전반적인 상황을 파악하는 데 영향을 미칩니다.
실제로 Linux에서 시스템 CPU 사용률을 계산하는 방법은 다음과 같습니다. 비록 오류가 있을 수 있지만 통계자료로 활용하기에는 충분합니다. 구현 측면에서 리눅스는 실제로 순간 데이터의 많은 사본을 저장하는 것이 아니라 모든 순간 값을 특정 데이터에 축적합니다.
다음으로 Linux에 들어가서 시스템 CPU 사용률 통계의 구체적인 구현을 살펴보겠습니다.
2. top 명령어 사용 데이터는 어디에 있나요
이전 섹션에서 언급한 Linux의 구현은 순간적인 값을 특정 데이터에 누적하는 것입니다. 이 값은 /proc/stat 의사 파일을 통해 커널에 의해 사용자 상태에 노출됩니다. Linux는 시스템 CPU 사용률을 계산할 때 이를 사용합니다.
전체적으로 최고 사령부 작업의 내부 세부 사항은 아래 그림과 같습니다.

top 명령은 /proc/stat에 액세스하여 다양한 CPU 사용률 값을 얻습니다.
-
커널은 /proc/stat에 대한 액세스를 처리하기 위해 stat_open 함수를 호출합니다.
-
커널에서 액세스하는 데이터는 kernel_cpustat 배열에서 제공되며 요약됩니다.
- 사용자 모드로 출력을 인쇄합니다.
strace를 사용하여 top 명령의 다양한 시스템 호출을 추적하면 파일에 대한 호출을 볼 수 있습니다.
으아악
커널은 각 의사 파일에 대한 처리 기능을 정의합니다. /proc/stat 파일의 처리 방법은 proc_stat_Operations입니다.“
/proc/stat 외에도 각 프로세스별로 분류된 /proc/{pid}/stat도 있으며, 이는 각 프로세스의 CPU 사용률을 계산하는 데 사용됩니다.
”
으아악
proc_stat_Operations에는 이 파일에 해당하는 작업 방법이 포함되어 있습니다. /proc/stat 파일이 열리면 stat_open이 호출됩니다. stat_open은 Single_open_size와 show_stat를 차례로 호출하여 데이터 내용을 출력합니다. 코드를 살펴보겠습니다:으아악
위 코드에서 for_each_possible_cpu는 CPU 사용량 데이터를 저장하는 kcpustat_cpu 변수를 순회합니다. 이 변수는 각 논리 코어에 대한 배열 요소를 준비하는 percpu 변수입니다. user, nice, system, idel, iowait, irq, softirq 등 현재 코어에 해당하는 다양한 이벤트를 저장합니다.이 루프에서는 각 코어의 각 사용량을 더합니다. 마지막으로 seq_put_decimal_ull을 통해 데이터가 출력된다.

이 변수의 데이터가 언제 추가되는지 살펴보겠습니다.
三、统计数据怎么来的
前面我们提到内核是以采样的方式来统计 cpu 使用率的。这个采样周期依赖的是 Linux 时间子系统中的定时器。
Linux 内核每隔固定周期会发出 timer interrupt (IRQ 0),这有点像乐谱中的节拍的概念。每隔一段时间,就打出一个拍子,Linux 就响应之并处理一些事情。

一个节拍的长度是多长时间,是通过 CONFIG_HZ 来定义的。它定义的方式是每一秒有几次 timer interrupts。不同的系统中这个节拍的大小可能不同,通常在 1 ms 到 10 ms 之间。可以在自己的 Linux config 文件中找到它的配置。
# grep ^CONFIG_HZ /boot/config-5.4.56.bsk.10-amd64 CONFIG_HZ=1000
从上述结果中可以看出,我的机器每秒要打出 1000 次节拍。也就是每 1 ms 一次。
每次当时间中断到来的时候,都会调用 update_process_times 来更新系统时间。更新后的时间都存储在我们前面提到的 percpu 变量 kcpustat_cpu 中。

我们来详细看下汇总过程 update_process_times 的源码,它位于 kernel/time/timer.c 文件中。
//file:kernel/time/timer.c void update_process_times(int user_tick) { struct task_struct *p = current; //进行时间累积处理 account_process_tick(p, user_tick); ... }
这个函数的参数 user_tick 指的是采样的瞬间是处于内核态还是用户态。接下来调用 account_process_tick。
//file:kernel/sched/cputime.c void account_process_tick(struct task_struct *p, int user_tick) { cputime = TICK_NSEC; ... if (user_tick) //3.1 统计用户态时间 account_user_time(p, cputime); else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) //3.2 统计内核态时间 account_system_time(p, HARDIRQ_OFFSET, cputime); else //3.3 统计空闲时间 account_idle_time(cputime); }
在这个函数中,首先设置 cputime = TICK_NSEC
, 一个 TICK_NSEC 的定义是一个节拍所占的纳秒数。接下来根据判断结果分别执行 account_user_time、account_system_time 和 account_idle_time 来统计用户态、内核态和空闲时间。
3.1 用户态时间统计
//file:kernel/sched/cputime.c void account_user_time(struct task_struct *p, u64 cputime) { //分两种种情况统计用户态 CPU 的使用情况 int index; index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER; //将时间累积到 /proc/stat 中 task_group_account_field(p, index, cputime); ...... }
account_user_time 函数主要分两种情况统计:
- 如果进程的 nice 值大于 0,那么将会增加到 CPU 统计结构的 nice 字段中。
- 如果进程的 nice 值小于等于 0,那么增加到 CPU 统计结构的 user 字段中。
看到这里,开篇的问题 2 就有答案了,其实用户态的时间不只是 user 字段,nice 也是。之所以要把 nice 分出来,是为了让 Linux 用户更一目了然地看到调过 nice 的进程所占的 cpu 周期有多少。
我们平时如果想要观察系统的用户态消耗的时间的话,应该是将 top 中输出的 user 和 nice 加起来一并考虑,而不是只看 user!
接着调用 task_group_account_field 来把时间加到前面我们用到的 kernel_cpustat 内核变量中。
//file:kernel/sched/cputime.c static inline void task_group_account_field(struct task_struct *p, int index, u64 tmp) { __this_cpu_add(kernel_cpustat.cpustat[index], tmp); ... }
3.2 内核态时间统计
我们再来看内核态时间是如何统计的,找到 account_system_time 的代码。
//file:kernel/sched/cputime.c void account_system_time(struct task_struct *p, int hardirq_offset, u64 cputime) { if (hardirq_count() - hardirq_offset) index = CPUTIME_IRQ; else if (in_serving_softirq()) index = CPUTIME_SOFTIRQ; else index = CPUTIME_SYSTEM; account_system_index_time(p, cputime, index); }
内核态的时间主要分 3 种情况进行统计。
- 如果当前处于硬中断执行上下文, 那么统计到 irq 字段中;
- 如果当前处于软中断执行上下文, 那么统计到 softirq 字段中;
- 否则统计到 system 字段中。
判断好要加到哪个统计项中后,依次调用 account_system_index_time、task_group_account_field 来将这段时间加到内核变量 kernel_cpustat 中。
//file:kernel/sched/cputime.c static inline void task_group_account_field(struct task_struct *p, int index, u64 tmp) { __this_cpu_add(kernel_cpustat.cpustat[index], tmp); }
3.3 空闲时间的累积
没错,在内核变量 kernel_cpustat 中不仅仅是统计了各种用户态、内核态的使用时间,空闲也一并统计起来了。
如果在采样的瞬间,cpu 既不在内核态也不在用户态的话,就将当前节拍的时间都累加到 idle 中。
//file:kernel/sched/cputime.c void account_idle_time(u64 cputime) { u64 *cpustat = kcpustat_this_cpu->cpustat; struct rq *rq = this_rq(); if (atomic_read(&rq->nr_iowait) > 0) cpustat[CPUTIME_IOWAIT] += cputime; else cpustat[CPUTIME_IDLE] += cputime; }
在 cpu 空闲的情况下,进一步判断当前是不是在等待 IO(例如磁盘 IO),如果是的话这段空闲时间会加到 iowait 中,否则就加到 idle 中。从这里,我们可以看到 iowait 其实是 cpu 的空闲时间,只不过是在等待 IO 完成而已。
看到这里,开篇问题 3 也有非常明确的答案了,io wait 其实是 cpu 在空闲状态的一项统计,只不过这种状态和 idle 的区别是 cpu 是因为等待 io 而空闲。
四、总结
本文深入分析了 Linux 统计系统 CPU 利用率的内部原理。全文的内容可以用如下一张图来汇总:

Linux 中的定时器会以某个固定节拍,比如 1 ms 一次采样各个 cpu 核的使用情况,然后将当前节拍的所有时间都累加到 user/nice/system/irq/softirq/io_wait/idle 中的某一项上。
top 命令是读取的 /proc/stat 中输出的 cpu 各项利用率数据,而这个数据在内核中是根据 kernel_cpustat 来汇总并输出的。
回到开篇问题 1,top 输出的利用率信息是如何计算出来的,它精确吗?
/proc/stat 文件输出的是某个时间点的各个指标所占用的节拍数。如果想像 top 那样输出一个百分比,计算过程是分两个时间点 t1, t2 分别获取一下 stat 文件中的相关输出,然后经过个简单的算术运算便可以算出当前的 cpu 利用率。
再说是否精确。这个统计方法是采样的,只要是采样,肯定就不是百分之百精确。但由于我们查看 cpu 使用率的时候往往都是计算 1 秒甚至更长一段时间的使用情况,这其中会包含很多采样点,所以查看整体情况是问题不大的。
另外从本文,我们也学到了 top 中输出的 cpu 时间项目其实大致可以分为三类:
第****一类:用户态消耗时间,包括 user 和 nice。如果想看用户态的消耗,要将 user 和 nice 加起来看才对。
第二类:内核态消耗时间,包括 irq、softirq 和 system。
第三类:空闲时间,包括 io_wait 和 idle。其中 io_wait 也是 cpu 的空闲状态,只不过是在等 io 完成而已。如果只是想看 cpu 到底有多闲,应该把 io_wait 和 idle 加起来才对。
위 내용은 Linux에서 CPU 사용률은 어떻게 계산됩니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Linux는 서버, 개발 환경 및 임베디드 시스템에 적합합니다. 1. 서버 운영 체제로서 Linux는 안정적이고 효율적이며 종종 고 대전성 애플리케이션을 배포하는 데 사용됩니다. 2. 개발 환경으로서 Linux는 효율적인 명령 줄 도구 및 패키지 관리 시스템을 제공하여 개발 효율성을 향상시킵니다. 3. 임베디드 시스템에서 Linux는 가볍고 사용자 정의 가능하며 자원이 제한된 환경에 적합합니다.

Apache를 시작하는 단계는 다음과 같습니다. Apache 설치 (명령 : Sudo apt-get Apache2를 설치하거나 공식 웹 사이트에서 다운로드) 시작 apache (linux : sudo systemctl start : windes (선택 사항, Linux : Sudo SystemCtl

Apache 80 포트가 점유되면 솔루션은 다음과 같습니다. 포트를 차지하고 닫는 프로세스를 찾으십시오. 방화벽 설정을 확인하여 Apache가 차단되지 않았는지 확인하십시오. 위의 방법이 작동하지 않으면 Apache를 재구성하여 다른 포트를 사용하십시오. Apache 서비스를 다시 시작하십시오.

Oracle 청취자를 시작하는 단계는 다음과 같습니다. Windows의 리스너 상태 (LSNRCTL 상태 명령 사용)를 확인하고 Linux 및 UNIX의 Oracle Services Manager에서 "TNS 리스너"서비스를 시작하고 LSNRCTL 시작 명령을 사용하여 리스너가 LSNRCTL 명령을 사용하여 리스너가 시작되었음을 확인하십시오.

이 기사에서는 데비안 시스템에서 NGINX 서버의 SSL 성능을 효과적으로 모니터링하는 방법에 대해 설명합니다. NginxOxporter를 사용하여 Nginx 상태 데이터를 프로 메테우스로 내보낸 다음 Grafana를 통해 시각적으로 표시합니다. 1 단계 : nginx 구성 먼저 Nginx 구성 파일에서 stub_status 모듈을 활성화하여 nginx의 상태 정보를 얻어야합니다. nginx 구성 파일에 다음 스 니펫을 추가하십시오 (일반적으로 /etc/nginx/nginx.conf에 있거나 포함 파일에 위치) : location/nginx_status {stub_status

이 기사는 데비안 시스템에서 재활용 빈을 구성하는 두 가지 방법 인 그래픽 인터페이스와 명령 줄을 소개합니다. 방법 1 : Nautilus 그래픽 인터페이스를 사용하여 파일 관리자를 엽니 다. 데스크탑 또는 응용 프로그램 메뉴에서 Nautilus 파일 관리자 (일반적으로 "파일")를 찾아 시작하십시오. Recycle Bin 찾기 : 왼쪽 탐색 표시 줄에서 재활용 빈 폴더를 찾으십시오. 찾을 수없는 경우 검색하려면 "기타 위치"또는 "컴퓨터"를 클릭하십시오. 재활용 빈 속성을 구성하십시오 : "Recycle Bin"을 마우스 오른쪽 버튼으로 클릭하고 "속성"을 선택하십시오. 속성 창에서 다음 설정을 조정할 수 있습니다. 최대 크기 : 재활용 빈에서 사용 가능한 디스크 공간을 제한하십시오. 유지 시간 : 재활용 쓰레기통에서 파일이 자동으로 삭제되기 전에 보존을 설정합니다.

Debian Systems에서 ReadDir 시스템 호출은 디렉토리 내용을 읽는 데 사용됩니다. 성능이 좋지 않은 경우 다음과 같은 최적화 전략을 시도해보십시오. 디렉토리 파일 수를 단순화하십시오. 대규모 디렉토리를 가능한 한 여러 소규모 디렉토리로 나누어 읽기마다 처리 된 항목 수를 줄입니다. 디렉토리 컨텐츠 캐싱 활성화 : 캐시 메커니즘을 구축하고 정기적으로 캐시를 업데이트하거나 디렉토리 컨텐츠가 변경 될 때 캐시를 업데이트하며 readDir로 자주 호출을 줄입니다. 메모리 캐시 (예 : Memcached 또는 Redis) 또는 로컬 캐시 (예 : 파일 또는 데이터베이스)를 고려할 수 있습니다. 효율적인 데이터 구조 채택 : 디렉토리 트래버스를 직접 구현하는 경우 디렉토리 정보를 저장하고 액세스하기 위해보다 효율적인 데이터 구조 (예 : 선형 검색 대신 해시 테이블)를 선택하십시오.

Apache 서버를 다시 시작하려면 다음 단계를 따르십시오. Linux/MacOS : Sudo SystemCTL 실행 Apache2를 다시 시작하십시오. Windows : Net Stop Apache2.4를 실행 한 다음 Net Start Apache2.4를 시작하십시오. Netstat -A |를 실행하십시오 서버 상태를 확인하려면 Findstr 80.
