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 ...
随机推荐
- android 设置默认启动network mode
network mode常见类型 WCDMA preferred : 0 GSM only : 1 WCDMA only : 2 GSM UMTS : 3 CDMA : 4 ... (参考RILCon ...
- SplitContainer如何实现左侧导航,正确显示和导航内容
关于这种类型的设计有很多的实现,这样,我首先解释一下我使用: 我的原则是实现方式,将form嵌panel在,作为一个子窗口. 如下面的代码细节: Form form = new DataSelect( ...
- Cluster Table
对簇表来说,总是要先创建簇段(cluster segment).然后将表关联到cluster segment里.由此可知,簇表也是虚拟表,没有对应的segment,簇表对应的是cluster segm ...
- hdu 4557 非诚勿扰 vector的应用 原来vector 可以删除指定位置元素 不过消耗大
非诚勿扰 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Submi ...
- 使用require.js和backbone实现简单单页应用实践
前言 最近的任务是重做公司的触屏版,于是再园子里各种逛,想找个合适的框架做成Web App.看到了叶大(http://www.cnblogs.com/yexiaochai/)对backbone的描述和 ...
- java反编译
反编译工具下载地址 http://download.csdn.net/detail/u011110110/8621653 反编译方法: 第一步:你先把下载的包的后缀名改成.zip第二步:到网上搜索de ...
- 解决iOS app集成共享QQ场地,微信的朋友,朋友等功能圈,不能采用苹果公司的审计问题
最近提交的应用程序App Store时刻,由于App综合QQ登录.份额QQ场地.微信等功能.被拒绝.很郁闷:在最佳.想想办法,这个问题是可以解决. 当共享平台列表显示.根据推断当前设备被安装在一节Ap ...
- socket计划编制的原则
socket编程原理 1.问题的引入 1) 普通的I/O操作过程: UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-rea ...
- 得知Android小遴选程序第七头(他们定义对话框、Gallery、ImageSwitcher)
效果如下面的: 一共一个activity和两个xml. ******当我们须要使用的组件不在setContentView()设置的布局文件里,那我们就须要使用inflate()方 ...
- 【SQL】Oracle的PL/SQL语法及其拓展数据类型总结
PL/SQL语法 PL/SQL程序由三部分组成,声明部分.执行部分.异常处理部分. 模板: DECLARE /*变量声明*/ BEGIN /*程序主体*/ EXCEPTION /*异常处理部分*/ E ...