文档章节

context switch 研究

-10
 -10
发布于 2015/02/04 18:03
字数 1388
阅读 19
收藏 0

http://hushi55.github.io/2015/01/08/context-switch

问题

不知道是不是大家都有用过 ajax 来获取数据的经验,一般的使用场景就是比如定时刷新看是否有新的数据。那不知道大家是否有运维过这样的应用。我的经验是当用户量上去以后,系统的 cpu load 会居高不下。我有一次这样的排查经验,系统的 cpu load 非常高,达到 3000%,一直找不到问题所在,经过排查,找出来问题所在是前端 ajax 请求太频繁,设置了 5 秒轮训,导致 linux 服务器大量的 context switch,消耗了大量的 cpu。

实验

我们来看下面这段代码:

<pre> import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; public final class ContextSwitchTest { static final int RUNS = 3; static final int ITERATES = 1000000; static AtomicReference<Thread> turn = new AtomicReference<Thread>(); static final class WorkerThread extends Thread { volatile Thread other; volatile int nparks; public void run() { final AtomicReference<Thread> t = turn; final Thread other = this.other; if (turn == null || other == null) throw new NullPointerException(); int p = 0; for (int i = 0; i < ITERATES; ++i) { while (!t.compareAndSet(other, this)) { LockSupport.park(); ++p; } LockSupport.unpark(other); } LockSupport.unpark(other); nparks = p; System.out.println("parks: " + p); } } static void test() throws Exception { WorkerThread a = new WorkerThread(); WorkerThread b = new WorkerThread(); a.other = b; b.other = a; turn.set(a); long startTime = System.nanoTime(); a.start(); b.start(); a.join(); b.join(); long endTime = System.nanoTime(); int parkNum = a.nparks + b.nparks; System.out.println("Average time: " + ((endTime - startTime) / parkNum) + "ns"); } public static void main(String[] args) throws Exception { for (int i = 0; i < RUNS; i++) { test(); } } } </pre>

我们先来看看系统的负载

<pre class="nowordwrap"> [root@centos101 ~]# vmstat -w 1 procs -------------------memory------------------ ---swap-- -----io---- --system-- -----cpu------- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 646344 1293172 2660988 44481292 0 0 1 15 0 0 2 0 98 0 0 0 0 646344 1292920 2660988 44481292 0 0 0 40 1550 1789 0 0 100 0 0 1 0 646344 1293044 2660988 44481292 0 0 0 44 1456 2060 0 0 100 0 0 0 0 646344 1293040 2660988 44481292 0 0 0 0 1802 2028 0 0 100 0 0 3 0 646344 1293224 2660988 44481292 0 0 0 4 1930 2332 1 0 99 0 0 1 0 646344 1292596 2660988 44481308 0 0 0 76 1766 2681 1 0 99 0 0 2 0 646344 1292844 2660988 44481308 0 0 0 4 1324 1774 0 0 100 0 0 1 0 646344 1293620 2660988 44481308 0 0 0 76 1560 2171 0 0 99 0 0 </pre>

现在我们运行上面的程序:

<pre> [root@centos101 hushi]# java ContextSwitchTest </pre>

现在的系统负载为:

<pre class="nowordwrap"> [root@centos101 ~]# vmstat -w 1 procs -------------------memory------------------ ---swap-- -----io---- --system-- -----cpu------- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 646316 1432056 2663212 44338940 0 0 1 15 0 0 2 0 98 0 0 1 0 646316 1431660 2663212 44338940 0 0 0 0 2959 213549 1 2 97 0 0 2 0 646316 1431668 2663212 44338940 0 0 0 4 2862 211135 1 2 97 0 0 1 0 646316 1431760 2663212 44338940 0 0 0 16 2931 211029 1 2 97 0 0 3 0 646316 1431908 2663212 44338940 0 0 0 172 2835 209765 1 2 97 0 0 2 0 646316 1431908 2663212 44338940 0 0 0 0 2577 241335 1 2 97 0 0 3 0 646316 1431624 2663212 44338944 0 0 0 4 3114 279214 2 1 97 0 0 4 0 646316 1431436 2663212 44338944 0 0 0 0 2550 278861 2 1 97 0 0 </pre>

请注意 vmstat 结果中的 cs 列,它的意思就是系统的 context switch 的次数。从两次数据可以看出 context switch 从 2000 左右激增到 200000 左右,增加了 100 倍。 运行后的结果为:

<pre> [root@centos101 hushi]# java ContextSwitchTest parks: 960929 parks: 960085 Average time: 8177ns parks: 937288 parks: 937248 Average time: 8265ns parks: 875644 parks: 876710 Average time: 7738ns [root@centos101 hushi]# </pre>

现在我们绑定这个程序到某一个 cpu 上,看看执行结果会是怎么样的。

<pre> [root@centos101 hushi]# taskset -c 2 java ContextSwitchTest parks: 988759 parks: 1000000 Average time: 2634ns parks: 999242 parks: 998704 Average time: 2593ns parks: 1000001 parks: 986989 Average time: 2634ns [root@centos101 hushi]# </pre>

vmstat 监控到的数据为:

<pre class="nowordwrap"> [root@centos101 ~]# vmstat -w 1 procs -------------------memory------------------ ---swap-- -----io---- --system-- -----cpu------- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 646408 1340460 2663304 44347108 0 0 1 15 0 0 2 0 98 0 0 1 0 646408 1340728 2663304 44347108 0 0 0 0 2658 393339 1 2 97 0 0 1 0 646408 1341392 2663304 44347108 0 0 4 124 3042 391449 1 2 97 0 0 4 0 646408 1339848 2663304 44347108 0 0 0 0 2844 395311 1 2 97 0 0 2 0 646408 1337472 2663304 44347108 0 0 0 4 2988 392845 1 3 97 0 0 3 0 646408 1337212 2663304 44347108 0 0 0 4 3096 396890 1 2 97 0 0 2 0 646408 1337384 2663304 44347108 0 0 0 4 2963 396925 1 3 97 0 0 </pre>

什么是 context switch

context 就是我们常说的上线文,switch 必然设计到 2 个 context。过程如下图:

那 context 具体是什么什么,其实就是 process control block,如下图:

具体包括:

  • 进程号
  • 进程状态:new, ready, running, waiting, halted...
  • 程序计数器
  • 寄存器:通用register, stack pointer, PSW等
  • CPU 调度信息:进程优先级, 在ready queue中的PCB指针,调度参数。
  • 内存管理信息:用了多少CPU time, 使用CPU的Max time, Quantumpage tables, segment tables. Base/limit register, page table(if paging 内存管理)
  • I/O 状态信息:分配给进程的驱动,打开的文件列表,未完成的I/O request,在I/O queue中的等待编号

引起 context switch 的原因

  • 当前执行任务的时间片用完之后, 系统CPU正常调度下一个任务
  • 当前执行任务碰到IO阻塞, 调度器将挂起此任务, 继续下一任务
  • 多个任务抢占锁资源, 当前任务没有抢到,被调度器挂起, 继续下一任务
  • 用户代码挂起当前任务, 让出CPU时间
  • 硬件中断

context switch 的影响

上下文切换会带来直接和间接两种因素影响程序性能的消耗

  • 直接消耗包括: CPU寄存器需要保存和加载,系统调度器的代码需要执行,TLB实例需要重新加载,CPU 的pipeline需要刷掉
  • 间接消耗指的是多核的cache之间得共享数据,间接消耗对于程序的影响要看线程工作区操作数据的大小

© 著作权归作者所有

-10

-10

粉丝 10
博文 10
码字总数 14996
作品 0
深圳
高级程序员
私信 提问
day69-20180827-流利阅读笔记

当机器人求你别关掉它,你还忍心按下 turn off 吗? Lala 2018-08-27 1.今日导读 能与人类进行社交互动的机器人正日益增多,他们以餐厅服务员、接待员、导游等角色出现在我们身边,似乎已成为...

飞鱼说编程
2018/08/27
152
0
getSystemService方法实现的详解研究?

getSystemService在哪实现的有谁研究过? 看过一句话“getSystemService这个方法基于context,只有存在TextView控件的窗体中这个方法才会被激活”这句话怎么理解? 研究一晚上没看到getSystem...

淘易通D
2016/05/04
208
0
【汇编】C++选择结构switch分析

C++允许程序员使用高级选择控制结构来处理不同的值。 其语法结构如下: switch (expression) { case constant1: block of instructions 1 break; case constant2: block of instructions 2 b...

Micooz
2013/07/24
47
0
《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]--第五章 深入理解WifiService

首先感谢各位兄弟姐妹们的耐心等待。本书预计在3月中旬上市发售。从今天开始,我将在博客中连载此书的一些内容。注意,此处连载的是未经出版社编辑的原始稿件,所以样子会有些非专业。 注意,...

邓凡平
2014/03/19
861
1
内置组件、和

第一部分:源码 AbstractLink.java // Copyright 2007, 2008, 2009 The Apache Software Foundation//// Licensed under the Apache License, Version 2.0 (the "License");// you may not u......

阎王他爹
2011/04/05
682
0

没有更多内容

加载失败,请刷新页面

加载更多

官方来源的 Duo Mobile App 解决了我的 Network Difficulties 问题

https://help.duo.com/s/article/2094?language=en_US 我利用百度搜索下载了一个 Duo Mobile App (由于 Google Play)在大陆不可用。 在扫描旧手机上的 Duo Mobile App 的二维码时, 显示出错...

圣洁之子
9分钟前
2
0
Zabbix监控Mysql容器(Docker容器)主从是否存活

1、在Zabbix Web端创建模板 2、为该模板创建监控项 3、创建触发器 4、在zabbix-agent端操作 在/etc/zabbix/zabbix_agentd.d新建customize.confw文件 内容如下 UserParameter=mysql.replicat...

abowu
11分钟前
1
0
基于 RocketMQ 的同城双活架构在美菜网的挑战与实践

本文整理自李样兵在北京站 RocketMQ meetup分享美菜网使用 RocketMQ 过程中的一些心得和经验,偏重于实践。 嘉宾李样兵,现就职于美菜网基础服务平台组,负责 MQ ,配置中心和任务调度等基础...

大涛学长
17分钟前
2
0
设计模式之:外观模式和桥接模式

作者:DevYK 链接:https://juejin.im/post/5d7e01f4f265da03b5747aac 外观模式 介绍 外观模式 (Facade) 在开发过程中的运用评率非常高,尤其是在现阶段,各种第三方 SDK “充斥” 在我们周边...

Java架构Monster
18分钟前
1
0
人证合一核验设备

人脸身份验证机,人证合一设备1:N如我们现在在车站或一些重要的场所如步行街、城中村等人流密集的场所应用的人脸识别布控系统,其特点是动态和非配合。所谓的动态也就是识别的不是照 片,不是...

非思丸智能
20分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部