Preemption Context Switches 和 Synchronization Context Switches
- Preemption Context Switches测量操作系统任务调度线程处理器上执行的次数,以及切换到较高-priority螺纹,数。
- Synchronization context switches度量的是因为显式调用线程同步API而发生线程切换的次数。如给多线程共享的变量加锁,多线程共同去改动。有些线程要堵塞在lock。直至占用锁的线程释放lock。这个度量反映的是线程间竞争的程度。
以下的实验来自VTune。旨在探究Preemption Context Switches的来源。
实验一:多线程无锁保护
speedup-example-no-mutex.cpp
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h> #define N 4
#define M 30000 int nwait = 0; volatile long long sum;
long loops = 6e3; void set_affinity(int core_id) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
assert(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == 0);
} void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
} int main(int argc, char *argv[]) {
set_affinity(23);
pthread_t th[N];
int ret; for(unsigned i=0; i<N; ++i) {
ret = pthread_create(&th[i], NULL, thread_func, (void*)i);
assert(!ret && "pthread_create() failed!");
} for(unsigned i=0; i<N; ++i)
pthread_join(th[i], NULL); exit(0);
}
VTune现象:
Preemption Context Switches由两部分组成:clone和Unknown stack frame(s)。
- 后者的Preemption稳定在5:在这个程序中,共同拥有5个线程在执行,VTune显示每一个线程各占1,所以后者的Preemption才稳定在5上。为了验证,我们让N等于8,结果是每一个线程各占1。Unknown stack frame(s)处的Preemption稳定在9。
- clone处的Preemption不是一个确定的数。有可能是6、7、8等。
为了验证,我们让N等于8,结果例如以下:
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++)
sum += i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
nwait++;
}
}无clone处的Preemption Context Switches
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
}
}
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
}
}
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++) {
sum += i; sum += i; sum += i; sum += i;
}
}
}
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++) {
sum += i;
sum += i;
sum += i;
sum += i;
sum += i;
sum += i;
sum += i;
}
}
}
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
for (long i = 0; i < loops; i++) {
sum += i;
sum += i;
sum += i;
sum += i;
}
}
}
从运行时间而来。
当然这仅仅是针对多线程间无锁情况,以下给它加上锁。看看是否有哪个因素也会影响到Preemption Context Switches。
实验二:多线程加锁
speedup-example-mutex-only.cpp
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h> #define N 4
#define M 30000 int nwait = 0; volatile long long sum;
long loops = 6e3; pthread_mutex_t mutex; void set_affinity(int core_id) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
assert(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == 0);
} void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
} int main(int argc, char *argv[]) {
set_affinity(23);
pthread_t th[N];
int ret; for(unsigned i=0; i<N; ++i) {
ret = pthread_create(&th[i], NULL, thread_func, (void*)i);
assert(!ret && "pthread_create() failed!");
} for(unsigned i=0; i<N; ++i)
pthread_join(th[i], NULL); exit(0);
}
接下来我们改变线程数。即N等于8:(我们期望Unknown处的Preemption添加类似线性,而clone处的添加幅度大。即与多线程无锁的情况类似)
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
phtread_mutex_unlock(&mutex);
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++) {
sum += i;
sum += i;
sum += i;
sum += i;
}
phtread_mutex_unlock(&mutex);
}
}
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++) {
sum += i*i*i*i*i*i;
sum += i*i*i*i*i*i;
sum += i*i*i*i*i*i;
sum += i*i*i*i*i*i;
}
}
}
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}
和
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
}
}
clone处Preemption的数目基本一致,但在加锁的情况下:
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}
和
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
}
}
clone处Preemption的数目不一样。前者要明显多于后者。可是假设我们将后者改为:
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
for (long i = 0; i < loops; i++)
sum += i;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i;
}
}
则VTune分析有:
而解释C、D、E三者之间的差异,也许也能够用我们的“时间理论”。运行三者:
在说明原因之前。先看还有一个程序:
void* thread_func(void *arg) {
set_affinity((int)(long)arg);
for (int j = 0; j < M; j++) {
phtread_mutex_lock(&mutex);
nwait++;
phtread_mutex_unlock(&mutex);
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
for (long i = 0; i < loops; i++)
sum += i*i*i*i*i*i;
}
}
和D在clone处拥有基本一样的Preemption数。但二者的执行时间却大不一样。
看来无锁和加锁还是有个重要区别的。我们都知道在无锁情况下,全部子线程并行执行。VTune中有例如以下调度:
事实上“时间理论”也适用于加锁情况,那为什么会出现上面C、D、E的情况,以及D和F的情况?我们也从调度图入手:
版权声明:本文博客原创文章,博客,未经同意,不得转载。
Preemption Context Switches 和 Synchronization Context Switches的更多相关文章
- context:component-scan" 的前缀 "context" 未绑定。
SpElUtilTest.testSpELLiteralExpressiontestSpELLiteralExpression(cn.zr.spring.spel.SpElUtilTest)org.s ...
- Android中,Context,什么是Context?
注:本文翻译自Context, What Context?,原文链接在这里,作者是Dave Smith.ps:译者链接http://blog.csdn.net/race604/article/deta ...
- Android开发之Android Context,上下文(Activity Context, Application Context)
转载:http://blog.csdn.net/lmj623565791/article/details/40481055 1.Context概念Context,相信不管是第一天开发Android,还 ...
- System.Drawing.Design.UITypeEditor自定义控件属性GetEditStyle(ITypeDescriptorContext context),EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.C ...
- Spring context:component-scan中使用context:include-filter和context:exclude-filter
Spring context:component-scan中使用context:include-filter和context:exclude-filter XML: <?xml version= ...
- Android深入理解Context(一)Context关联类和Application Context创建过程
前言 Context也就是上下文对象,是Android较为常用的类,但是对于Context,很多人都停留在会用的阶段,这个系列会带大家从源码角度来分析Context,从而更加深入的理解它. 1.Con ...
- Tomcat 的context.xml说明、Context标签讲解
Tomcat的context.xml说明.Context标签讲解 1. 在tomcat 5.5之前 --------------------------- Context体现在/conf/server ...
- 元素 "context:component-scan" 的前缀 "context" 未绑定的解决方案
在动态web项目(Dynamic Web Project)中,使用SpringMVC框架,新建Spring的配置文件springmvc.xml,添加扫描控制器 <context:componen ...
- Tomcat的context.xml说明、Context标签讲解
Tomcat的context.xml说明.Context标签讲解 1. 在tomcat 5.5之前 --------------------------- Context体现在/conf/server ...
随机推荐
- The JSR-133 Cookbook for Compiler Writers(an unofficial guide to implementing the new JMM)
The JSR-133 Cookbook for Compiler Writers by Doug Lea, with help from members of the JMM mailing lis ...
- Java的Log系统介绍和切换(转)
Java的log系统比较繁杂.在这里梳理一下.本文只涉及log系统介绍和处理log系统之间的切换.不涉及如何配置和使用. 具体的log系统 Log4j:准确的说是log4j 1.x版.是之前使用最广泛 ...
- 更改CPU厂商信息
更改所检测到第三方手机CPU制造商型号,于kernel\arch\arm\mach-msm以下适当Board-*.c更改文件.例如我们8226的CPU.必要的Board-8226.c在里面DT_MAC ...
- 变化App.config其中值,并保存
using System; using System.Collections.Generic; using System.Configuration; using System.IO; using S ...
- 领域驱动设计(DDD)部分核心概念的个人理解(转)
领域驱动设计(DDD)是一种基于模型驱动的软件设计方式.它以领域为核心,分析领域中的问题,通过建立一个领域模型来有效的解决领域中的核心的复杂问题.Eric Ivans为领域驱动设计提出了大量的最佳实践 ...
- 键盘控制div上下左右移动 (转)
<html> <head> <title></title> <link rel="stylesheet" type=" ...
- 在CentOS下安装配置MySQL(转)
今天刚把项目做完,需要马上部署到新到的测试服务器上,于是乎,要在服务器上安装环境,由于好久在linux上部署了,手有些生,比较费劲装完,现在把重要步骤贴出,供自己以后参照.1.首先要看看有没有已经安装 ...
- or1200中IMMU分析(续)
下面内容摘自<步步惊芯--软核处理器内部设计分析>一书 2 IMMU中的特殊寄存器 OR1200处理器中的IMMU包括第2组特殊寄存器,如表10.1所看到的. ITLBW0MRx是指令TL ...
- cocos2dx 遮罩层 android 手机上 失败
1.CCClippingNode使用(在模拟器上ok,在手机上不行),实现多个剪切区域 local layer=CCLayerColor:create(ccc4(0,0,0,110)) --/ ...
- Ubuntu14.04下安装ZendStudio10.6.1+SVN出现Failed to load JavaHL Library
Subclipse不能正常工作,打开后报错: Failed to load JavaHL Library. These are the errors that were encountered: no ...