当前位置: 首页 > news >正文

linux下cpu多核运行程序以及运行时间统计

一、多核心运行程序

在linux下我们可以指定线程或者进程运行在指定的cpu核心上,操作方法如下:

1)运行进程指定cpu核心

taskset -c 2 ./app //-c指定运行的cpu核心号,从0计数,查看效果如下:

2)运行线程指定cpu核心

主要是设置线程的属性,具体代码如下,详看main函数。

#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
#include <time.h>void* thread_func0(void* arg) {int iterations = 1000000000; // 迭代次数double a = 3.14159; // 乘法操作的乘数double b = 2.71828; // 乘法操作的被乘数double sum = 0.0; // 加法操作的累加器struct timespec start, end;clock_gettime(CLOCK_MONOTONIC, &start);// 执行乘法运算for (int i = 0; i < iterations; ++i) {double c = a * b;sum += c; // 将乘法结果加到累加器上}clock_gettime(CLOCK_MONOTONIC, &end);double time_spent = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;printf("cpu0 Performed %d in %f seconds\n", iterations, time_spent);printf("cpu0 Resulting sum: %f\n", sum);return NULL;
}void* thread_func1(void* arg) {int iterations = 1000000000; // 迭代次数double a = 3.14159; // 乘法操作的乘数double b = 2.71828; // 乘法操作的被乘数double sum = 0.0; // 加法操作的累加器struct timespec start, end;clock_gettime(CLOCK_MONOTONIC, &start);// 执行乘法运算for (int i = 0; i < iterations; ++i) {double c = a * b;sum += c; // 将乘法结果加到累加器上}clock_gettime(CLOCK_MONOTONIC, &end);double time_spent = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;printf("cpu1 Performed %d in %f seconds\n", iterations, time_spent);printf("cpu1 Resulting sum: %f\n", sum);return NULL;
}int main() {pthread_t thread0, thread1; // 为每个线程使用不同的变量pthread_attr_t attr0, attr1; // 为每个线程属性使用不同的变量unsigned long mask0 = 1UL << 2; // 将线程绑定到CPU核心2unsigned long mask1 = 1UL << 3; // 将线程绑定到CPU核心3// 初始化线程属性pthread_attr_init(&attr0);pthread_attr_init(&attr1);pthread_attr_setaffinity_np(&attr0, sizeof(mask0), &mask0);pthread_create(&thread0, &attr0, thread_func0, NULL);pthread_attr_setaffinity_np(&attr1, sizeof(mask1), &mask1);pthread_create(&thread1, &attr1, thread_func1, NULL);// 等待线程0和线程1完成pthread_join(thread0, NULL);pthread_join(thread1, NULL);return 0;
}

编译后运行效果如下(代码指定了2和3,从0计数):

3)两者的优先级

代码中的线程属性设置cpu核心为2和3,进程以cpu核心0来运行,实际运行在核心2和3上。

测试代码用上述不变,运行命令为:taskset -c 0 ./app

因此,可得结论:在进程和线程都指定运行的cpu核心时,以线程为准。

二、多核心运行的时间测量需要注意的事项

1)多核计时异常

在测试运行时间时,遇到一个问题,最开始我使用的时间测试代码如下:

clock_t start = clock();//测量开始时间
//功能代码
//...
clock_t end = clock();// 测量结束时间
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;

这个代码在测试单核运行的代码时,时间是对的,但是使用多核运行时,发现这个代码统计的时间是我实际手机计时的2倍,怀疑是该函数统计了本程序对所有cpu的占用时间,即双核的时间。

后修改时间测量代码如下:

struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
//功能代码
//...
clock_gettime(CLOCK_MONOTONIC, &end);
double time_spent = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;

测试时间和手机测试的一致。

2)clock()clock_gettime() 比较

clock()clock_gettime() 都是 C 语言标准库中用于获取时间的函数,但它们在用途和行为上有一些重要的区别:

  1. 定义和来源

    • clock() 函数定义在 <time.h> 头文件中,它测量的是程序占用 CPU 的时间(也称为 CPU 时间或处理器时间)。它返回程序启动以来的时钟周期数,这个值是通过处理器的时钟周期来计算的。
    • clock_gettime() 函数是 POSIX.1-2001 标准的一部分,也定义在 <time.h> 中,它提供了更精确的时间测量。它可以测量多种类型的时间,包括实时时间(系统时间)、进程时间、线程时间等。
  2. 时间类型

    • clock() 只能测量程序占用 CPU 的时间。
    • clock_gettime() 可以测量多种时间,通过指定不同的时钟 ID 来获取不同类型的时间。例如:
      • CLOCK_REALTIME:返回以系统实时时间为基础的时间,受系统时间的更改影响。
      • CLOCK_MONOTONIC:返回一个单调时钟,它以系统启动为基础,不受系统时间更改的影响,适合测量时间间隔。
      • CLOCK_PROCESS_CPUTIME_ID:返回调用进程占用的 CPU 时间总和。
      • CLOCK_THREAD_CPUTIME_ID:返回调用线程占用的 CPU 时间。
  3. 精度

    • clock() 的精度受限于系统和硬件,通常以秒为单位,精度较低。
    • clock_gettime() 通常提供更高的精度,可以测量到纳秒级别。
  4. 返回值

    • clock() 返回一个 clock_t 类型的值,表示程序占用 CPU 的时钟周期数。如果失败,返回 ((clock_t) -1)
    • clock_gettime() 成功时返回 0,失败时返回 -1,并设置 errno 以指示错误。
  5. 使用场景

    • clock() 适用于需要测量程序执行时间的场景,但它不适用于测量墙上时钟时间(实际时间)。
    • clock_gettime() 适用于需要高精度时间测量的场景,包括但不限于测量墙上时钟时间、系统时间、进程或线程的 CPU 时间。
  6. 多线程环境

    • 在多线程环境中,clock() 可能无法准确反映单个线程的 CPU 时间,因为它测量的是整个进程的 CPU 时间。
    • clock_gettime() 通过 CLOCK_THREAD_CPUTIME_ID 可以准确测量单个线程的 CPU 时间。
  7. 系统依赖性

    • clock() 是 C 语言标准的一部分,几乎所有的 C 语言环境都支持。
    • clock_gettime() 是 POSIX 标准的一部分,可能在非 POSIX 兼容的系统上不可用或需要特定的编译器标志。

总结来说,clock_gettime() 提供了更多的功能和更高的精度,是现代 C 语言编程中推荐的时间测量函数。而 clock() 由于其较低的精度和对多线程支持的限制,在现代编程中使用较少。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 复杂工件的高效测量方案:自动化三坐标测量与影像测量技术集成
  • 分类预测|基于黑翅鸢优化BKA-Transformer-LSTM组合模型的数据预测Matlab程序多特征输入多类别输出
  • 大语言模型算力优化策略:基于并行化技术的算力共享平台研究
  • 是否应该使用WordPress自动更新的功能
  • 虚幻5|技能栏优化(1)---优化技能UI,并添加多个技能
  • JavaScript 知识:this、apply/call/bind、Promise、HTTP 库 Axios
  • QUIC(Quick UDP Internet Connections)协议
  • 【Zookeeper】小白基础入门
  • Idea发布springboot项目无法识别到webapp下面的静态资源
  • TikTok流量推送逻辑与IP的关系
  • Java 集合Collection(List、Set)Map
  • 碎碎念之Android中CPU架构arm-v8a、arm-v7a、x86
  • 信息安全--(五)物理与环境安全技术(一)物理安全概念
  • 代码随想录算法训练营第19天 | 第七章 回溯算法part01
  • ARM32开发——(二十三)存储器介绍
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • @angular/forms 源码解析之双向绑定
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • CentOS 7 防火墙操作
  • ECS应用管理最佳实践
  • Intervention/image 图片处理扩展包的安装和使用
  • js数组之filter
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • tensorflow学习笔记3——MNIST应用篇
  • use Google search engine
  • Vim 折腾记
  • Vue官网教程学习过程中值得记录的一些事情
  • Vue学习第二天
  • 深度解析利用ES6进行Promise封装总结
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • Linux权限管理(week1_day5)--技术流ken
  • ​io --- 处理流的核心工具​
  • ​油烟净化器电源安全,保障健康餐饮生活
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (31)对象的克隆
  • (Ruby)Ubuntu12.04安装Rails环境
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (算法设计与分析)第一章算法概述-习题
  • (五)activiti-modeler 编辑器初步优化
  • (转)Sublime Text3配置Lua运行环境
  • (转)平衡树
  • (转载)深入super,看Python如何解决钻石继承难题
  • .NET 4.0中的泛型协变和反变
  • .Net Core中Quartz的使用方法
  • .NET Framework杂记
  • .Net Remoting常用部署结构
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .NET/C# 的字符串暂存池
  • :中兴通讯为何成功