时间片 线程切换 指令周期 流水线 TPS的初步了解

发布时间 2023-04-13 21:30:39作者: 济南小老虎

时间片 线程切换 指令周期 流水线 TPS的初步了解


情况说明

Redis 单线程提供服务, 可以支撑十万级别的TPS
通过以个非常简单的测试
redis-benchmark -c 50 -n 50000 ping 
Intel 8369HB 3.3Ghz    14万TPS
阿里 倚天710  2.7Ghz    16万TPS
AMD 9T34     3.4Ghz    22万TPS 

可以推测, Redis执行一次ping到客户端, 在本地的情况下大概耗时
1S/20万 约等于 5微秒

认为: redis可以在 5 微秒之内 完成 客户端连接-命令执行-推送结果到客户端
如果是在不同机器上面, 那么时间差异可能会比较大一些. 因为有网络层的延迟与交互. 

想基于这个数据, 进行一些简单的分析与判断. 

CPU与操作系统时间片

在多核CPU之前,PC以及一些简单的服务器一般只有一颗CPU
这种情况下. 实现多用户,多任务的处理都是通过时间片的概念来进行. 

CPU将自己的处理时间分为一定大小的时间片,给不同的任务进行处理. 
任务之间如果时间片到了需要让出时间片, 交由其他任务进行. 

linux的发行版的时间片是20ms到800ms不等. 
时间片的让出有 主动让出, 也有被动让出.
不管哪种让出都需要考虑 线程切换, 上下文切换. 

线程切换, 进程切换, 系统调用, 中断 都会导致上线文切换.

上下文切换 需要CPU 保存当前在运行进程的TLB,以及寄存器, 指令位置等信息
等待当前任务有了时间片时在加载进内存. 

需要说明一点: 
线程切换的成本比较高. 可能需要 1000-2000个质量周期, 耗时可能有1微秒甚至更多. 

回到刚才的例子, redis 在执行时面对不同的client 可能需要进行一次上下文切换,用于返回给特定的client信息.
一进一出, 损耗可能就有 2微秒, 加上一些协议开销. 理论上 redis执行一条指令 核心进程只需要 1微秒左右. 

理论上redis可以拿到百万级别的 TPS. 但是因为各种开销, 导致可能无法达到这个上限. 

指令周期和流水线

CPU执行一条指令的时间, 可以大概的认为是指令周期.
一般2Ghz的CPU  他执行一条uop的时间可以简单理解为是 0.5纳秒.

但是需要注意的一点是: 虽然现在x86号称是CISC, 但是在x86CPU的指令解析和发射的部分其实是使用的RISC的技术.
他将复杂指令解析成一个一个微笑的 uop 才进入流水线进行调度. 

虽然将macro的op拆解成了一个一个minor op, 看起来会导致指令使用的周期变多. 
但是因为流水线和多发射超标量的存在, 一个周期可以发射6-8个指名. 并且多级流水线的存在同时运行的命令要更加多
会带来更多的性能收益. 

流水线里面将复杂的命令拆解到不通的周期中去执行. 
在遇到流水线毛线,或者是指令等待或者是冲突时, CPU会设计多种方式进行避免和提速. 

国产信创CPU可以做到多核心高频率, 但是很难在流水线和指令集并行部分达到Intel和AMD的水平, 
所以看机器的性能不能全看主频和核数, 还要看很细节的 指令流水和多发射相关信息. 

看量化分析性能的书时, 最近这些年性能的提升很多在用乱序指令集的一些优化.
Intel有几百个OOB的缓存, 可以都执行指令后统一进行排序返回和回写, 尽可能的提升性能. 

TPS

TPS = 工作线程数/响应时间
所以提高TPS的方法就是 提高工作线程数和降低响应时间.

但是提供了工作线程, 会导致上下文切换增多好耗费更多的寄存器和内存来保存线程的状态. 超过一定限度, 线程切换的成本会极具上升. 

响应时间的提高不仅可以提升客户感受还能够尽快的完成任务. 
现在我们发现, 国产设备不够优秀的地方就在于响应时间. 
他的核心数足够多, 可以实现很多线程进行工作, 但是每个线程的相应时间却比较大, 到执客户反映不好用. 

虽然很多国产CPU的主频和核心数较多, 但是他们的指令集, 流水线, 乱序,以及架构等部分不如国际厂商先进.

所以很多时候不能单纯看核心和主频,还要看厂商和型号.