从 TTY 使用时程序运行速度明显变慢

从 TTY 使用时程序运行速度明显变慢

所以我有一个用 C++ 编写的程序。

它可以告诉我完成所有计算需要多长时间,并且它进行了大量相当繁重的多线程计算。

我刚刚注意到,如果我在同一台机器上运行该程序,如果从 TTY 启动,则需要大约 20-21 秒才能完成所有计算,而如果我从 GNOME 终端启动,则仅需要大约 0.2 秒。

这是什么原因造成的?这实际上是同一台机器上的同一个文件。

答案1

一些背景理论

好吧,您所使用的CTRL++ALTF1GNOME 终端都是同一概念的不同实现:模仿所谓的全屏终端。

前者在 Linux 中称为虚拟终端 (VT),通常简称为“控制台”。它使用一种特殊的“纯文本”视频模式,该模式仍由 x86 兼容平台(即“IBM PC”传承的平台)上的硬件视频卡提供。后者是一个 GUI 应用程序。

两者都为在其帮助下运行的应用程序提供了一系列此类应用程序所期望的“终端设备”功能(更多详细信息和进一步的提示 -这里)。

当前的问题

好的,现在让我们来讨论一下感知到的缓慢程度。

我确信问题的关键在于你的程序执行了所谓的“阻塞” I/O。也就是说,每次你执行类似以下操作时

std::cout << "Hello, world" << endl;

在你的代码中,首先链接到你的应用程序的 C++ 标准库的代码开始运行,并处理发送到指定溪流。

经过某些处理(通常是一些缓冲)后,这些数据必须真正离开程序的运行过程,并实际输出到程序将其输出发送到的任何媒体。在 Linux(和其他与 Unix 兼容的系统)上,这需要调用内核——通过一个专用系统调用(或者系统调用简称)write()

因此,C++ stdlib 最终会执行该write()系统调用,然后等待它完成 - 也就是说,它等待内核回复“好的,数据接收者告知它已获取它”。

您可以推断,程序输出的数据的接收者是运行程序的终端(模拟器)——Linux VT 或测试中的 GNOME 终端实例。(整个情况更加复杂,因为内核不会将数据直接发送到正在运行的终端模拟器中,但我们不要使描述复杂化。)

因此,该系统调用的完成速度在write()很大程度上取决于数据接收方处理数据的速度!就您而言,GNOME 终端的速度更快。

我认为两者的区别在于,VT 驱动程序会忠实地呈现发送给它的所有数据,并对其进行滚动等,而 GNOME 终端会通过仅呈现数据的尾部(无论是否适合终端的屏幕尺寸)来优化突发传入数据,并将其余部分放在大多数 GUI 终端仿真器所具有的所谓“滚动缓冲区”中。

需要做的

要注意的关键是,一旦您的程序执行任何 I/O 和计算,并且您使用“挂钟”计时器测量程序的计算速度,您通常可能会测量该 I/O 的速度,而不是计算的速度。

请注意,I/O 是棘手的:您的流程可能被抢占每当操作系统等待某些 I/O 资源(例如硬盘驱动器)可供写入时,它都会停止(并将其资源移交给另一个进程)。

因此,衡量计算“原始”性能的可靠方法是在程序中提供一些功能来禁用所有 I/O。如果这不可能或实施起来太难看,至少尝试将所有输出定向到所谓的“空设备”,方法是/dev/null运行程序,如下所示

$ ./program >/dev/null

空设备只是丢弃传递给它的所有数据。所以是的,C++ stdlib 执行的每轮 I/O 仍将影响内核,但至少您将拥有几乎恒定(几乎是即时)的写入速度。

如果你需要两种措施生成的数据,考虑创建一个所谓的 RAM 磁盘并将输出重定向到位于那里的文件。

关于测量还有一点:请注意,即使在看似空闲的系统上运行商用操作系统(例如您的 Ubuntu 或其他操作系统),CPU 也永远不会休眠 — 总是有一些任务在后台执行。这意味着即使没有任何 I/O 或某种“禁用”的 I/O(如上所述),测量计算性能在每次运行时仍会产生不同的结果。

为了弥补这一点,良好的基准测试意味着使用相同的输入数据进行数千次计算,并对多次运行的结果取平均值。

相关内容