에 따르면 거의 모든 프로세스가 절전 모드에 있어야 함에도 불구하고 최근 임베디드 시스템의 로드 평균이 약 1.5에 달하는 것을 확인했습니다 htop
.
이 시스템은 buildroot를 사용하여 구축된 라이브 Linux 커널(4.14.126)을 실행하는 듀얼 코어 Cortex-A9입니다. 우리는 initramfs를 루트 파일 시스템으로 사용하고 스왑이 없으므로디스크 I/O 없음정상 작동 중.
약간의 조사 끝에 우리는 다음과 같은 프로그램에 의해 로드가 발생했다는 것을 발견했습니다.고쳐 쓰다, 이는 소프트웨어 업데이트를 위한 편리한 웹 인터페이스를 제공합니다(우리는 이를 계속 사용하고 싶습니다).
time
응용 프로그램의 평균 CPU 사용량을 추정 할 때 (계산하여)(사용자+시스템)/실제), 내가 얻는 값은 약 1%에 불과하며, 이는 로드 평균 1.5를 고려하면 큰 의미가 없습니다.
TASK_UNINTERRUPTIBLE
로드 평균 에는 CPU 사용량에 영향을 주지 않는 해당 상태의 프로세스 도 포함된다는 것을 이해합니다 . 내가 이해하지 못하는 것은 애플리케이션의 스레드/프로세스가 왜 그 상태에 있는지입니다.
상황을 더 자세히 분석하기 위해 다음을 사용하여 커널 추적을 캡처했습니다.LNGswupdate가 수행하는 유일한 작업은 다음과 같습니다(50밀리초마다).
보시다시피 소켓 기반 IPC로 보이는 것이 있고 선택을 기다리는 것이 있습니다.무엇. IPC의 경우 한 스레드는 주로 에서 차단하고 nanosleep()
다른 스레드는 에서 차단하는 것으로 보이며 accept()
, 내가 아는 한 두 스레드 모두 시스템 리소스를 소비해서는 안 됩니다.
참고: 두 스크린샷의 시간축은 동일하며 IPC에는 약 1분이 소요됩니다. 총 500-600μs(50ms 간격을 고려하면 관찰된 1% CPU 사용량과 매우 일치함)
그렇다면 여기서 부하가 발생하는 원인은 무엇입니까?
답변1
R 상태와 D 상태의 작업은 모두 Linux 로드를 증가시키기 때문에 시스템에서 이 두 상태 중 하나에 있는 모든 스레드를 샘플링할 수 있습니다. 예를 들어:
for x in {1..100} ; do ps -aeos,user,comm,wchan | grep "^[RD]" ; sleep 0.1 ; done | sort | uniq -c | sort -nbr | head -20
아래 출력 예에서는 자체 ps
프로세스가 항상 활성 상태임을 보여주는 첫 번째 줄을 무시해야 합니다. 모든 샘플링을 수행하는 프로세스이기 때문입니다.
# for x in {1..100} ; do
> ps -aeos,user,comm,wchan | grep "^[RD]"
> sleep 0.1
> done | sort | uniq -c | sort -nbr | head -20
100 R root ps -
3 R oracle oracle_14047_li -
2 R root rcu_sched rcu_gp_kthread
2 R root rcu_sched -
2 R root kworker/1:2-eve -
2 R oracle perl -
2 R oracle ora_vktm_lin19c hrtimer_nanosleep
2 D root md10_raid10 md_super_wait
2 D oracle ora_ckpt_linprd md_write_start
1 R redis redis-server -
1 R oracle ora_vktm_linprd hrtimer_nanosleep
1 R oracle ora_m001_linprd -
1 D root xfsaild/dm-18 rq_qos_wait
1 D oracle ora_mz00_lin19c x64_sys_io_destroy
1 D oracle ora_lg00_lin19c inode_dio_wait
1 D oracle ora_dbrm_lin19c msleep
이전 커널에서 실행하지 않는 한, 새 커널은 다른 사용자 프로세스에 대해 WCHAN 값을 마스크하므로 루트로 실행해야 합니다.
그보다 더 깊이 들어갈 수 있으며(ps를 사용하지 않음) 시스템 호출 및 커널 스택 추적 정보를 샘플링 /proc/PID/syscall
하고 얻을 수도 있습니다. 이를 위해 Linux Process Snapper( )라는 도구를 /proc/PID/stack
작성했기 psn
때문에 커널 추적에 의존하지 않고도 이와 같은 성능 문제에 대해 상당히 진보된 심층 연구를 수행할 수 있습니다.
[tanel@linux01 ~]$ sudo psn -G syscall,wchan
Linux Process Snapper v0.18 by Tanel Poder [https://0x.tools]
Sampling /proc/syscall, stat, wchan for 5 seconds... finished.
=== Active Threads ==========================================================================================
samples | avg_threads | comm | state | syscall | wchan
-------------------------------------------------------------------------------------------------------------
511 | 255.50 | (kworker/*:*) | Disk (Uninterruptible) | [kernel_thread] | blkdev_issue_flush
506 | 253.00 | (oracle_*_l) | Disk (Uninterruptible) | pread64 | do_blockdev_direct_IO
28 | 14.00 | (oracle_*_l) | Running (ON CPU) | [running] | 0
1 | 0.50 | (collectl) | Running (ON CPU) | [running] | 0
1 | 0.50 | (mysqld) | Running (ON CPU) | [running] | 0
1 | 0.50 | (ora_lgwr_lin*c) | Disk (Uninterruptible) | io_submit | inode_dio_wait
1 | 0.50 | (oracle_*_l) | Disk (Uninterruptible) | pread64 | 0
1 | 0.50 | (oracle_*_l) | Running (ON CPU) | [running] | SYSC_semtimedop
1 | 0.50 | (oracle_*_l) | Running (ON CPU) | [running] | read_events
1 | 0.50 | (oracle_*_l) | Running (ON CPU) | read | 0
1 | 0.50 | (oracle_*_l) | Running (ON CPU) | semtimedop | SYSC_semtimedop
이보다 더 자세히 알아볼 수 있습니다. 관련 블로그 항목은 다음과 같습니다.
답변2
CPU 사용량과 로드는 서로 다른 측정항목입니다. 실제로 로드는 1보다 높을 수 있습니다. CPU는 실시간 CPU 사용량이므로 항상 100% 미만이어야 합니다(단, 다중 코어/CPU에서는 이해가 되실 겁니다). 로드는 로드를 나타냅니다. 즉, 실행 중이고 실행을 기다리는 프로세스 수입니다.
(질문에 대한 논의에서) 아시다시피 I/O는 일반적으로 이러한 대기 중 하나이므로 로드가 추가됩니다. 그러나 I/O를 수행하지 않는 프로세스로 인해 대기가 발생할 수 있는 신호/세마포어/잠금이 있을 수도 있습니다. 예를 들어, 프로세스가 초당 한 번씩 깨어나고 해당 프로세스의 데이터를 기다리는 프로세스가 많으면 로드가 더 높아집니다(대기 중인 프로세스 수와 동일).
파이프는 I/O로 간주할 수 있지만 mmap과 잠금은... 이를 IO로 분류하시겠습니까? 바이오(블록 I/O)에는 표시되지 않으므로 많은 로드 통계에서는 표시되지 않을 수 있습니다.
일반적으로 이를 알아내는 가장 쉬운 방법은 프로세스를 차단하고 프로세스가 어디에 있는지 확인하는 것입니다. 이 작업을 여러 번 수행하면 하나의 함수가 차단되는 것을 볼 수 있습니다(다른 함수보다 더 자주 발견될 수도 있음).
답변3
약 450MHz로 i.MX28에서 실행되는 임베디드 시스템에서도 동일한 문제가 발생했습니다.
htop
CPU 사용량이 계속 50%로 표시되는데, 이는 전적으로 작업 중 하나로 인해 swupdate
발생합니다 .
100ms 관찰을 탐색하는 동안 mongoose_interface.c
다음을 읽으면 실행하십시오 start_mongoose()
.
mg_mgr_poll(&mgr, 100);
실험적으로 100을 1000으로 변경해 보았는데, 다시 컴파일하고 재시작한 후에 swupdate
는 htop
.
언급한 바와 같이, 숫자가 너무 우연적이라고 생각하기 때문에 이것은 실험적입니다. 부작용이 발생하는지 조사하지 않았습니다.