最近笔者一直尝试获得一些关于一个内核上下文切换(context switch)所需时间的信息。你也许会问,上下文切换是什么?我试图找出的是,如果你正在运行一个应用并且让系统调用I/O请求,那么如果所有核心在运行所有核心类型所支持的线程并运行用户应用的话,完成这个请求需要多长时间呢?如果所有核心都没有运行用户应用,那么核心中运行一个内核的话,会怎样呢?
之所以问这些问题,是因为答案对于一个线程可以完成多少I/O请求是有影响的。这很重要,因为这里存在着固态盘厂商之间的竞争。厂商们都希望做出 IOPS更高的固态盘。有谁真的需要一个IOPS达到100万、200万甚至更高的IOPS来解决自己问题的固态盘?如果针对find或者fsck这样的命令,加速文件系统元数据所带来的性能问题不是并行请求的话(某些文件系统例外),将会有一个预读的过程。让固态盘来承担大量IOPS有意义吗,或者支持少量IOPS的固态盘能否提供接近的性能?
从一定程度上说,IOPS性能的确重要,如果你的核心数充足,而且你有很多运行或者完成I/O请求的用户应用。另一方面,如果你要求一个应用线程做大量的I/O请求,那么I/O问题就会出在数据路径中的延迟,包括从应用到内核的时间;在内核、文件系统和驱动程序堆栈中的时间;到固态盘的时间(到 PCIe设备的时间或者到SAS/SATA设备的时间,包括线缆传输时间)以及在固态盘中的时间。如果你做同步读取I/O请求的话,那么你需要等待I /O,整个路径上的延迟(包括固态盘)将是有限的,要看你可以发送多少I/O请求。
对于同步写入来说,在发送下一个I/O请求之前要运行请求,并等待确认。延迟很重要,因为在得到确认之前你无法返回对程序的控制。如果I/O缓冲在内存中的话会很快,但是获得所有到存储设备的路径需要花费大量时间。你不用等待一直到应用询问同步I/O请求。这就是aioread和aiowrite发生的情况,在系统调用中指定到内核的I/O请求列表。此外,你可以做异步I/O,很多是通过利用多个线程来做I/O,以模拟异步I/O。
所以我们开始发出请求看看从进到出内核、当内核运行在核心内和内核必须迁移到核心内时运行I/O请求的时间,我希望这个时间是以每个CPU系统类型的时钟周期所表示的。这个要求过分吗?很多人告诉我的另一件事是,不同的芯片做上下文切换所需的时间是不同的。如果一个芯片的寄存器越多,那么与另一个应用进行上下文切换的时间就越长。这一点很有趣,因为我从未想过这个问题。这也是阿姆达尔定律(Amdahl's Law)的另一个例子,这个定律告诉我们,当只有一项系统性能改善的时候,最高预期性能就会有所提升。
在Google上搜索我们会发现很多不同的数据。还有其他一些点:我比较关注Linux上下文切换时间——不是Windows、不是AIX、不是Solaris、也不是其他任何操作系统。我猜测,上下文切换时间在这些操作系统中可能会更长,不太可能缩短太多。
#p#副标题#e#最后两个例子的中断开销与前两个例子相近。笔者有一位为大型企业开发Linux驱动程序的朋友称,采用Nehalem-EX CPU的数字要更高一些。
首先是最高的数字:
其次是最低的数字:
关于数字:
1、I/O在内核中的最短时间只是猜测,而且文章中也没有讨论做I/O需要的时间。我认为这是一个非常低的数字。
2、最长时间是根据笔者朋友的说法。
总结
如果你做的是单线程操作,那么用户和内核之间的I/O交换时间可能会成为一个限制因素。对于像find和fsck这样的文件系统操作来说,我认为一 块10万IOPS固态盘和一块100万IOPS固态盘的区别已经不重要了。当然,如果多个用户发出find命令的话IOPS性能就很重要了,但是有一个阻 碍是根据文件系统和内核情况的,因为你不能做那么多的操作,即使你有一块100万IOPS的固态盘。阿姆达尔定律早就证明了这一点,我们似乎忘记了限制硬 件性能可能带来的影响。问题是,你的应用可以发出多少IOPS?如果应用不能利用异步I/O,那么显然进出操作系统的速度就是一个阻碍,尤其是当用户应用 运行在所有这些核心上。固态盘是个好东西,我估计在不久的将来我们会看到操作系统发生变化,让固态盘能够发挥它的优势。这是我们一直在做的,可以说,没有 新的工程问题,只有新的工程师在解决老问题。