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

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核心2
	unsigned 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() 由于其较低的精度和对多线程支持的限制,在现代编程中使用较少。


http://www.kler.cn/a/288945.html

相关文章:

  • 生成自签名证书并配置 HTTPS 使用自签名证书
  • 力扣513:找树左下角的值
  • 提高数据处理效率:JavaScript 操作 XLSX 文件的最佳实践
  • Keil基于ARM Compiler 5的工程迁移为ARM Compiler 6的工程
  • 会话信息处理: HttpSession、token序列化、收集登录设备信息、基于`spring-session-data-redis`实现session共享。
  • 华为云前台用户可挂载数据盘和系统盘是怎么做到的?
  • 物联网(IoT)支持的小型水处理厂实时硬件在环(HIL)仿真
  • 角谷猜想——考拉兹猜想
  • 《OpenCV计算机视觉》—— 图像边缘检测
  • day4 C++
  • 【STM32】IIC
  • mongodb 在 Windows 环境下迁移数据库的问题
  • Linux:手搓shell
  • 解析淘宝商品详情API返回值中的特殊属性
  • python系列教程231——__init__.py
  • Docker php文件本地包含--pearcmd.php利用
  • Prometheus+Grafana监控数据可视化
  • 反序列化漏洞(一)
  • flume系列之:批量并行启动、停止、重启flume agent组
  • 设计模式之中介者模式
  • Pixelmator Pro for Mac 专业图像处理软件【媲美PS的修图软件】
  • 微信小程序 - 自定义头部导航栏开发
  • 【区块链 + 物联网】车载终端可信分账应用 | FISCO BCOS应用案例
  • 使用docker部署tensorrtllm推理大模型baichuan2-7b
  • 安装包丨WebGIS开发环境搭建及所需工具
  • 2024-MongoDB中国用户大会