绑定CPU逻辑核心的利器——taskset
时间:2022-06-17
本文章向大家介绍绑定CPU逻辑核心的利器——taskset,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在工作中,我们可能遇到这样的需求:如何评估程序在一核和多核下的工作效率差距?最简单的想法是找一台只有一个CPU逻辑核的机器和一台有多个逻辑核的机器。(转载请指明出于breaksoftware的csdn博客)但是这种方式有明显的问题:
- 不容易找到这样的机器。
- 找到的机器不能保证其他配置一致,比如CPU主频。
- 找的的机器不能保证环境一致,比如操作系统或者运行中的其他程序。
于是比较好的方式是:在一台多逻辑核的机器上指定程序可以运行在哪些核上。为了可以证明我们程序在多个核心上切换,我编写了如下代码
// build script:gcc -lpthread bind_core.c -o bind_core
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
void* thread_routine(void* arg) {
int cpu = -1;
while(1) {
int cur_cpu = sched_getcpu();
if (cur_cpu != cpu) {
printf("pre:%d, cur:%dn", cpu, cur_cpu);
cpu = cur_cpu;
}
}
};
void test_cpu_switch() {
pthread_t thread;
pthread_create(&thread, NULL, thread_routine, NULL);
pthread_detach(thread);
sleep(100);
}
这段代码中启动了一个线程,通过sched_getcpu函数不停检测当前占用的逻辑核心编号。如果发生核心切换,就打印出来。在一台相对繁忙的40个逻辑核心机器上,其输出结果如下:
上图可以看出,程序分别在:0,1,2,3,7,8,10,12,13,14,15,17,19,21号逻辑核上运行过。为了让CPU在固定的核心上执行,我们可以使用taskset指令,让程序绑定逻辑核心。
taskset -c 0,10 ./bind_core
上面指令让bind_core执行于0和10号逻辑核心上,这样我就可以看到它在这两个核心上的切换
基于上面的基础,我们可以编写测试代码,看看多线程程序在单核心和多核心下的处理能力
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
unsigned long g_a = 0;
unsigned long g_b = 0;
void* thread_routine(void* arg) {
while(1) {
(*((unsigned long*)arg))++;
}
};
void test_cpu_ability() {
pthread_t thread_a;
pthread_create(&thread_a, NULL, thread_routine, &g_a);
pthread_detach(thread_a);
pthread_t thread_b;
pthread_create(&thread_b, NULL, thread_routine, &g_b);
pthread_detach(thread_b);
sleep(3);
printf("a:%lutb:%lun", g_a, g_b);
};
这段代码启动了两个线程,每个线程分别不停自增。过了3秒后,通过两个全局变量的值表达出不同场景的处理能力:
- 不设置CPU绑定 ./bind_core a:999409723 b:994174648
- 设置绑定到0号CPU逻辑核心 taskset -c 0 ./bind_core a:563819215 b:564766868
- 设置绑定到0,1号CPU逻辑核心 taskset -c 0,1 ./bind_core a:1113333145 b:1072107088
- 设置绑定到0,1,2号CPU逻辑核心 taskset -c 0,1,2 ./bind_core a:1114825104 b:1113289961
可以看到,当启动两个线程时,绑定一个核心的处理能力是绑定两个核心的处理能力的一半左右。而绑定的核心数超过线程数时(如绑定到0,1,2号逻辑核心),其效率并没有明显提高。当然上述结论有个前提:这是CPU资源密集型的场景。
- 【项目管理和构建】——Maven下载、安装和配置(二)
- 打印机安全研究(一):不容乐观的网络打印机安全状况
- Apache Maven 入门篇
- hyperledger v1.0.5 区块链运维入门(一)
- 分析无线遥控器信号并制作Hack硬件进行攻击
- 第二章:Shiro入门——深入浅出学Shiro细粒度权限开发框架
- 在Apache Spark上跑Logistic Regression算法
- 第四章:Shiro的身份认证(Authentication)——深入浅出学Shiro细粒度权限开发框架
- 第五章:Shiro的授权(Authorization)——深入浅出学Shiro细粒度权限开发框架
- 第六章:Shiro的Realms——深入浅出学Shiro细粒度权限开发框架
- 第八章:Shiro和Spring的集成——深入浅出学Shiro细粒度权限开发框架
- 第九章:Shiro的Web——深入浅出学Shiro细粒度权限开发框架
- 第十章:Shiro的Cache——深入浅出学Shiro细粒度权限开发框架
- Appboy基于MongoDB的数据密集型实践
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Django-rest-framework中过滤器的定制实例
- Python greenlet和gevent使用代码示例解析
- 完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
- Android开发中Intent.Action各种常见的作用汇总
- Android解决ScrollView下嵌套ListView和GridView中内容显示不全的问题
- Android添加ButterKnife时报错Error:(2, 0) Cannot add extension with name 'android'的解决办法
- Python视频编辑库MoviePy的使用
- python json.dumps中文乱码问题解决
- Android定时器实现定时执行、重复执行、定时重复执行、定次数执行的多种方式
- Android开发导入项目报错Ignoring InnerClasses attribute for an anonymous inner class的解决办法
- Android中buildToolVersion与CompileSdkVersion的区别
- Glide用法与技巧以及优秀库的推荐
- Android整理好的图片压缩工具类
- Android Studio获取网络JSON数据并处理的方法
- Android使用ViewPager快速切换Fragment时卡顿的优化方案