5

当用户不用电脑的时候,运行中的电脑在做些什么?

 3 years ago
source link: https://zhuanlan.zhihu.com/p/139326786
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

当用户不用电脑的时候,运行中的电脑在做些什么?

中央处理器 (CPU)话题下的优秀回答者

当人闲下来的时候,会干什么?如果这个问题问我,那一定是躺在床上。有句老话说的好:舒服不如躺着。从进化论来讲,这是合理的。从洞穴人那里继承来的大脑,让我们尽一切可能寻找和储存食物,并节省这些来之不易的能量。哪些没事瞎“蹦跶”的原始人,也许在一个酷热的下午,已经灭绝在非洲的大草原上,没有留下一个后代。所以那些没事就去健身的人,我对他们只有羡慕嫉妒恨,这需要多大的勇气才能克服深藏在基因里的那个“懒惰的原始人”啊。

电脑曾经也没事也在全力工作,那是个野蛮发展的时代,Intel和AMD还在比拼谁的频率更高,谁有闲工夫在乎用户的电费账单呢?只有在频率竞争遇到了阻力后,慢慢地,能耗比才渐渐地重要了起来,由此以降频为代表的EIST和以关掉不用部分Clock和电力的CState才被发明并被广泛使用,那些不知疲倦的古老电脑也随之被淘汰了。这两个技术可以参考我的这两篇文章:

今天我们就一起来深入了解一下CState,也就是电脑完全不用一段时间,Windows和Linux是怎么进入CState的。

Windows的Idle进程

进入Windows,打开任务管理器,点到“详细信息”一栏。

v2-0bac26bcecfecd05bab48d0f2c9eba19_720w.jpg

当我们闲置一段时间,就会发现PID(Process ID)为0的“系统空闲进程”进程,CPU占用率为>95%以上。PID为0,意味着它是系统起来的第一个进程,是所有进程的母进程。这个所谓的Idle进程在这个时间在干什么呢?Windows的闭源让查看它比较困难,所幸我们有JTAG调试工具,我们可以Halt下来看看Windows究竟在干啥。

首先我们的目标机器有8个物理线程(两个物理CPU,各4个Core,无HT):

v2-49d75aa7066307aadd32759ed068a1a0_720w.jpg

我们halt下来,看看:

v2-cba92a6f0a96cc1607a063d28cffc48a_720w.jpg

我们点开看各个内核的程序,发现大部分在这样一段代码里面:

v2-a5cc2ba2ab94cf77b5dc1e27dd5be1c5_720w.jpg

这段代码就是典型的monitor/mwait对,关于它们的介绍可以参考完全开放的Intel IA32用户手册,这里有PDF版本下载[1]。mwait的Hint值决定了CPU进入哪个CState:

这表明这些运行这段代码的CPU实际上已经停止运行了,进入了CState,等待中断或者monitor的内容。而主CPU(BSP)则在一个另一个循环中等待:

它在读TSC,并等待触发事件。从中看出,主CPU会把读出的时间加上,计算入CPU的空闲Idle耗时。这就是为什么“系统空闲进程”CPU占有率这么高的原因。

Windows因为是闭源,看起来还不太清楚,我们来看看Linux是怎么样的。

Linux的Idle进程

Linux闲置了一段时间,大部分CPU所在的代码和Windows很相似:

也是熟悉的monitor/mwait对。而主BSP的代码和Windows也类似,也在读TSC,时间戳。

所幸,我们有Linux的代码,我们可以看看monitor/mwait对的源程序,它在intel_idle.c中:

/**
 * intel_idle
 * @dev: cpuidle_device
 * @drv: cpuidle driver
 * @index: index of cpuidle state
 *
 * Must be called under local_irq_disable().
 */
static __cpuidle int intel_idle(struct cpuidle_device *dev,
				struct cpuidle_driver *drv, int index)
{
	unsigned long ecx = 1; /* break on interrupt flag */
	struct cpuidle_state *state = &drv->states[index];
	unsigned long eax = flg2MWAIT(state->flags);
	unsigned int cstate;
	bool uninitialized_var(tick);
	int cpu = smp_processor_id();

	/*
	 * leave_mm() to avoid costly and often unnecessary wakeups
	 * for flushing the user TLB's associated with the active mm.
	 */
	if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
		leave_mm(cpu);

	if (!static_cpu_has(X86_FEATURE_ARAT)) {
		cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) &
				MWAIT_CSTATE_MASK) + 1;
		tick = false;
		if (!(lapic_timer_reliable_states & (1 << (cstate)))) {
			tick = true;
			tick_broadcast_enter();
		}
	}

	mwait_idle_with_hints(eax, ecx);

	if (!static_cpu_has(X86_FEATURE_ARAT) && tick)
		tick_broadcast_exit();

	return index;
}

它的父函数是cpuidle_enter(),它的进程是pid为1的init进程,也就是pid为0的start_kernal()的所有内核进程的守护进程,它是内核创建的第一个进程,也是所有用户级进程的祖先。

UEFI BIOS的Idle程序

也许你不会想到,UEFI BIOS也会把不用的CPU放到CState下,节省那么一丢丢电力(苍蝇也是肉啊),它的代码在Edk2\UefiCpuPkg\Library\MpInitLib\Mplib.c

      if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
        //
        // Place AP in MWAIT-loop
        //
        AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
        if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
          //
          // Check AP start-up signal again.
          // If AP start-up signal is not set, place AP into
          // the specified C-state
          //
          AsmMwait (CpuMpData->ApTargetCState << 4, 0);
        }

而原始的可以进入C1的HLT指令方式是这个代码块:

    if (CpuMpData->ApLoopMode == ApInHltLoop) {
      //
      // Save AP volatile registers
      //
      SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
      //
      // Place AP in HLT-loop
      //
      while (TRUE) {
        DisableInterrupts ();
        CpuSleep ();
        CpuPause ();
      }
    }

最最原始的傻等在这里:

      } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
        //
        // Place AP in Run-loop
        //
        CpuPause ();
      } else {

电脑不用的时候,CPU中的大部分逻辑内核都会用monitor/mwait进入省电而停止的CState,而主内核BSP也大部分在CState,偶尔会醒来统计一下数据而已。Windows是这样,Linux是这样,连BIOS也差不多是这样(BIOS BSP不在统计数据,在继续启动)。

欢迎大家关注本专栏和用微信扫描下方二维码加入微信公众号"UEFIBlog",在那里有最新的文章。

用微信扫描二维码加入UEFIBlog公众号


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK