운영체제 개념을 배우려고 합니다. 다음은 두 가지 간단한 Python 코드입니다.
while True:
pass
이:
from time import sleep
while True:
sleep(0.00000001)
질문: 왜 첫 번째 코드를 실행할 때는 CPU 사용량이 100%인데, 두 번째 코드를 실행할 때는 1~2% 정도인가요? 어리석게 들릴 수도 있다는 걸 알지만 왜 sleep
수면 시스템 호출을 사용하지 않고 사용자 공간 모드와 같은 것을 구현할 수 없습니까?
참고: 저는 수면을 이해하려고 노력하고 있습니다.Linux 커널의 시스템 호출하지만 솔직히 말해서 거기에서 무슨 일이 일어나고 있는지 이해가 되지 않습니다. 또한 NOP 어셈블리 코드를 검색해 본 결과 실제로 작동하지 않는 것으로 나타났습니다.아무것도 없다하지만 쓸모없는 일(예: xchg eax, eax)을 수행하면 CPU 사용량이 100%가 되는 것 같습니다. 하지만 잘 모르겠습니다.
사용자 공간 모드에서 실행할 수 없는 절전 시스템 호출의 어셈블리 코드는 무엇입니까? HLT와 비슷한가요?
또한 다음과 같이 코드에서 어셈블리를 사용해 보았습니다 HLT
.
section .text
global _start
_start:
hlt
halter:
jmp _start
section .data
msg db 'Hello world',0xa
len equ $ - msg
하지만 이 코드를 실행한 후 다음과 같은 커널 일반 보호 오류가 표시됩니다.
[15499.991751] traps: hello[22512] general protection fault ip:401000 sp:7ffda4e83980 error:0 in hello[401000+1000]
어쩌면 뭔가 관련이 있을지도 모르겠지만보호 링아니면 내 코드가 잘못된 걸까요? 여기서 또 다른 질문은 운영 체제가 시스템 호출에서 HLT
또는 기타 보호된 어셈블리 명령을 사용합니까 sleep
?
답변1
첫 번째 코드를 실행할 때 CPU 사용량이 100%인데 두 번째 코드를 실행할 때 약 1~2%인 이유는 무엇입니까?
첫 번째는 "사용 중 루프"이기 때문에 항상 코드를 실행하고 있습니다. 두 번째는 운영 체제에 이 특정 프로세스가 일시 중지(휴면)되기를 원한다고 알려주므로 운영 체제는 프로세스의 일정을 취소하고 CPU를 사용하는 다른 프로세스가 없으면 CPU는 유휴 상태가 됩니다.
또한 NOP 어셈블리 코드를 검색한 결과 실제로는 아무 작업도 수행하지 않는 것으로 나타났습니다.
NOP = 작업 없음: 아무런 효과가 없는 코드를 적극적으로 실행하고 있습니다. 이를 사용하여 코드를 채울 수 있지만 CPU를 저전력 상태로 전환할 수는 없습니다.
사용자 공간 모드에서 실행할 수 없는 절전 시스템 호출의 어셈블리 코드는 무엇입니까?
x86 CPU의 최신 운영 체제는 mwait
.다른 CPU 아키텍처는 다른 명령을 사용합니다.
하지만 이 코드를 실행한 후에는 다음과 같은 커널 일반 보호 오류가 표시됩니다.
이는 운영 체제가 관리자 모드에서 이 작업을 수행하도록 되어 있기 때문입니다. 위에서 쓴 것처럼 운영체제는 프로세스의 스케줄을 유지할 수 있어야 하므로 프로세스 자체가 CPU를 유휴 모드로 전환하는 것을 허용하지 않습니다.
여기서 또 다른 문제는 운영 체제가 절전 시스템 호출에서 HLT 또는 기타 보호된 어셈블리 명령을 사용한다는 것입니다.
네, 그렇습니다. Sleep Call 중에는 실행되지 않지만 스케줄러 루프 내에서 스케줄러가 실행할 프로세스가 없음을 감지하면 실행됩니다.
1부에 대한 질문입니다. 몇 가지 기간을 사용하는 경우, 즉
sleep(0.0000000000000001)
스케줄러가 여전히 다음 프로세스로 이동합니까?
실제 운영 체제 호출에 대해서는 man 3 sleep
(초 단위 해상도), man usleep
(마이크로초 단위 해상도) 및 man nanosleep
(나노초 단위 해상도)를 참조하세요.
Python 코드에서 어떤 부동 소수점을 사용하든 Python이 사용하는 시스템 호출보다 더 나은 해상도를 얻을 수는 없습니다(변형이 무엇이든 관계 없음).
맨페이지에는 "(적어도) usec 마이크로초 동안 호출 스레드의 실행을 일시 중지합니다"라고 나와 있습니다. 등등이므로 지연이 0이더라도(그리고 즉시 일정이 변경되더라도) 일정이 취소될 것이라고 가정합니다. 하지만 저는 이것을 테스트하지도 않았고 커널 코드도 읽지 않았습니다. .
답변2
운영 체제의 "CPU 사용량" 측정은 사용자 공간 프로세스/스레드(작업)가 CPU에서 실행되고 있는지 여부를 기반으로 합니다. 비록 해당 명령이 단지 시간 낭비일 뿐이더라도 마찬가지입니다. 작업이 CPU 시간을 사용하지 않는 경우 운영 체제가 다른 작업을 실행 중일 수 있음을 의미합니다.
CPU를 강제로 저전력 상태로 만들 수 있더라도 사용자 공간이 바쁘게 기다리는 경우에는 그렇지 않습니다. marcelm이 언급한 것처럼 CPU 전원 상태는 중요하지 않습니다. 중요한 것은 작업이 절전 모드로 전환되어야 한다고 OS에 알리는지 여부입니다. 운영 체제는 CPU를 절전 모드로 전환할 수 있습니다.만약에다른 작업은 없습니다.
x86 pause
명령어 도하지 마십시오운영 체제CPU에서 다양한 작업 예약. CPU를 C0.1 또는 C0.2 절전 상태로 전환할 수 있지만 최신 제품 tpause
도 마찬가지 umonitor
입니다 .umwait
또한 백엔드 실행 단위가 없는 x86-64의 nop
진정한 NOP 입니다. xchg eax,eax
64비트 모드의 NOP가 아니라 EAX를 RAX로 0 확장하므로 0x90
64비트 모드에서는 인코딩을 사용할 수 없으며 16비트 또는 32비트 모드에서만 사용할 수 있습니다. 그렇기 nop
때문에자신의 항목인텔 매뉴얼에 있습니다. 물론 32비트 모드에서도 최신 CPU는 0x90
이를 다른 긴 nop opcode와 함께 no-op 및 특수 사례로 인식합니다.
하지만 다시 말하지만, 그건 관련성이 없습니다.CPU 사용량은 CPU가 절전 상태로 들어가거나 다른 작업을 실행할 수 있는지 여부를 나타냅니다.핵심이 프로세스에는 실행할 것이 없습니다.
hlt
특권 명령어입니다(CPL=0이라고도 알려진 링 0에서만 유효합니다.인텔 수동 입력예외:현재 권한 수준이 0이 아닌 경우 #GP(0)입니다.
사용자 공간은 다음 인터럽트가 도착할 때까지 CPU를 절전 모드로 전환할 수 없으며 오직 커널만이 이를 수행할 수 있습니다(스케줄러가 해당 사용자 공간 작업 실행 중에 수행할 다른 작업이 없다고 결정한 경우 sleep
).
또는 WAITPKG CPU 기능(Tremont 및 Alder Lake)이 나올 때까지umwait
커널이 사용자 공간에서 시작된 절전 모드에 대한 기간 제한을 설정하여 운영 체제가 사용자 공간 절전 모드를 그렇게 길지 않도록 제한할 수 있도록 합니다. 그리고 수면 깊이는 hlt
(C1)보다 더 얕아 제한되어 있으며 이는 각성 대기 시간에 중요합니다. 아마도 실시간 운영 체제는 중요한 인터럽트가 다가오고 있음을 알고 CPU가 추가적인 웨이크업 지연을 갖지 않기를 원할 것입니다. 또는 CPU를 절전 모드로 전환하는 것을 원하지 않습니다. ( umwait
컨트롤은 커널이 설정하기를 원한다는 것을 알고 있지만 hlt
그렇지 않습니다.)
그러나 사용자 공간은 다음 인터럽트까지 CPU 시간을 낭비할 수 있으며, 이는 사용자 공간에서 시스템 호출이나 CPU 예외가 발생하지 않는 한 선점형 멀티태스킹 커널이 CPU 제어권을 다시 얻을 수 있는 유일한 방법입니다. (아마도 이와 같은 시스템 호출은 yield()
운영 체제가 여유 CPU 코어를 기다리는 다른 작업으로 전환하도록 컨텍스트를 지정하도록 설계되었을 수 있습니다.)
사이트 간 복제:
관련 질문과 답변:
https://stackoverflow.com/questions/58386042/multiple-nop-instructions-do-not-contentionly-take-longer-than-a-single-nop-inst(NOP는 고정된 시간을 소비하지 않습니다. 순서가 잘못된 슈퍼스칼라 CPU는 선형 추가 명령마다 별도의 비용이 발생하지 않습니다.)
https://stackoverflow.com/questions/1719071/how-is-sleep-implemented-at-the-os-level
이 질문 IMO는 [어셈블리][운영 체제][x86][CPU 아키텍처] 태그가 있는 스택 오버플로에 속합니다. 적어도 거기에는 더 나은 적합성이 있습니다. SE는 대부분에 관한 것입니다.사용운영 체제 이론/개념이 아닌 것입니다.
가능하다면 작은 절전 모드를 많이 사용하지 말고 대신 파일 설명자에서 활동을 사용 poll
하거나 기다리십시오. select
그러면 프로세스(및 CPU)는 다른 시스템 호출을 위해 계속 깨어나는 대신 잠자기 상태를 유지할 수 있습니다.
기다리느라 바쁠 경우 해당 루프에 절전 모드를 넣으면 덜 나쁘지만 절전 모드나 할 일이 있을 때 OS에서 깨우는 위치를 차단하는 것과 비교하면 여전히 좋지 않습니다.
비유하자면 사람들이 은행에서 줄을 서서 기다리고 있다고 상상해 보세요. 은행원은 CPU이며 고객(프로세스)의 요청을 실행합니다.
sleep()
창구 직원을 떠나 지정된 시간 후에 다시 줄을 서기 위해 의자에 앉는 것과 같습니다. (대부분의 사람들이 이렇게 하면 일반적으로 행이 비어 있습니다. CPU가 유휴 상태이므로 새 작업이 즉시 실행될 수 있습니다.)- NOP를 반복적으로 실행하는 것은 날씨에 대해 이야기하면서 창구 직원에게 할 일을 제공하지만 은행 업무를 수행하지 않는 것과 같습니다. 계산원은 다른 고객을 유휴 상태로 두기 때문에 서비스를 제공할 수 없습니다.
(실제 은행과 달리 선점형 멀티태스킹에는 창구 직원이 고객이 원하는 모든 작업을 수행하지 않았더라도 고객이 줄 뒤로 가도록 강제하는 것이 포함됩니다.)
답변3
방금 dirkt에 추가되었습니다. 할 수 있는 것, 해야 할 것, 하지 말아야 할 것에 대한 좋은 답변입니다:
일정 기간 동안 코드가 아무 작업도 수행하지 않도록 하는 두 가지 주요 방법이 있습니다.
ㅏ/타이머를 프로그래밍하고 다른 활동을 위해 CPU를 확보하여 코드가 깨어나고 타이머 인터럽트를 계속 따라갈 수 있을 것으로 기대합니다.
이는 확실히 공유 시간 멀티태스킹 시스템에서 코딩된 프로그램을 실행할 때 따라야 할 가장 공정한 접근 방식입니다(특히 작업이 SCHED_OTHER 예약 정책에 따라 실행되도록 설계된 CFS와 관련하여).
두번째/CPU를 예약하는 것 외에는 아무것도 하지 마십시오. 타이머 인터럽트에 의해 깨어나기를 기대하는 것은 기대이기 때문입니다. 어떤 상황에서도 보장되지 않습니다. 인터럽트가 트리거되면 시스템이 사용 중일 수 있습니다.
- 실시간 일정 정책에 따라 일부 작업을 실행합니다.
- 모든 인터럽트 또는 인터럽트할 수 없는 커널 코드의 일부를 마스크하는 일부 인터럽트 핸들러를 실행하십시오(소위 선점형 Linux 커널에도 여전히 일부 인터럽트 핸들러가 있습니다).
- 선택한 타이머 시스템에 따라 인터럽트가 전혀 실행되지 않을 수도 있다는 말은 아닙니다.
그럼에도 불구하고 코드가 다시 실행될 것으로 예상되는 순간과 실제로 다시 실행되는 순간 사이의 지연(시간적 차이)은 전혀 예측할 수 없습니다.
이는 어떤 상황에서는 분명히 용납될 수 없습니다.
일부 장치와 통신(장치 메모리 주소에 쓰기)할 때 두 개의 연속 작업 간에 엄격한 최소 타이밍이 보장되어야 하며, 잠재적인 언더런이나 최소한 허용할 수 없는 지연이 발생하지 않는 한 엄격한 최대 타이밍이 보장되어야 한다고 상상해 보세요.
물론, 이 접근 방식을 따르면 대부분의 커널 코드의 효율성이 쉽게 깨질 수 있으므로 소위 말하는 코드만 사용해야 합니다.원자적 맥락특수 커널 기능을 실행하므로 사용자 공간이 제한되고 권한이 있는 것으로 표시된 특정 CPU opcode를 직접 사용할 수 없습니다. (HLT와 유사)
그건 그렇고 그리고이제 제목에 표현된 실제 질문에 답해 보겠습니다., 매우 정확한 수량을 기다려야 할 때 가끔 NOP에 의존했던 기억이 납니다.CPU 주기. (이것은 opcode에서 확인할 수 있는 유일한 것입니다.) 최신 아키텍처에서는 메모리, 장치가 버스에 있고 CPU와 비교하여 서로 다른(때로는 관련되지 않은) 클럭 주파수에서 작동하기 때문에 이 접근 방식은 결과가 좋지 않습니다. 이식 가능하고 디버그하기 어려운 코드. 이것은 분명히 더 이상 올바른 길이 아닙니다.
중단점 설정을 위해 NOP를 유지하는 것이 좋습니다.
답변4
NOP는 무작동(no-op)으로 생각하는 것이 더 나을 수도 있습니다. 적어도 이론적으로는 뭔가를 수행하지만 프로그램 카운터를 제외하고는 아무것도 변경하지 않습니다.
이는 특히 일부 하드웨어가 준비될 때까지 클록 주기를 기다리는 구형 시스템이나 분기하려는 경우 다음 명령을 실행해야 하는 SPArc와 같은 실행 후 분기 시스템에서 많은 용도로 사용됩니다. 분기하지 않으면 실행됩니다! 컴퓨터를 교체하기 전에 해야 할 중요한 일이 없나요? NOP만 추가하면 됩니다!