C 语言多进程 vs 多线程性能问题

2020-11-02 15:07:03 +08:00
 tom82232
测试源码如下:
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>

typedef struct __test{
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
uint64_t e;
}test_t;


#define CPU_MAX 128
int cpuid[CPU_MAX];
test_t tdata[CPU_MAX];
int seq[CPU_MAX];
int thd_num = 1;
uint64_t prev[CPU_MAX];
uint64_t tmp[CPU_MAX];
int flag_stat = 0;

static void
init(void)
{
for(int i = 0; i < CPU_MAX; i++) {
cpuid[i] = -1;
seq[i] = i;
tdata[i].e = 100;
tdata[i].a = 0;
tdata[i].b = 0;
tdata[i].c = 0;
tdata[i].d = 0;
prev[i] = 0;
}
}

static int
parse_cpuid(const char *str)
{
char buf[256];
int flag_start = 0;
int thdnum = 0;
int len = strlen(str);
if(len > 255) {
memcpy(buf, str, 255);
buf[255] = 0;
}
else if(0 < len) {
strcpy(buf, str);
}
else return 0;

for(int i = 0; i < 256; i++) {
if(buf[i] == ' ' || buf[i] == '\t' || buf[i] == ',') buf[i] = 0;
}

for(int i = 0; i < 256; i++) {
if(flag_start && 0 == buf[i]) flag_start = 0;
if(0 == flag_start && 0 != buf[i]) {
flag_start = 1;
cpuid[thdnum] = atoi(buf+i);
if(0 > cpuid[thdnum] || CPU_MAX <= cpuid[thdnum]) return -1;
thdnum++;
}
}

return 0;
}
static int
parse_cmd(int argc, char **argv)
{
if(0 < argc) {
thd_num = atoi(argv[0]);
if(0 > thd_num) return -1;
argc--, argv++;
}

if(0 < argc) {
return parse_cpuid(argv[0]);
}

return 0;
}

static void*
task_root(void *arg)
{
register int seq = *(int*)arg;
int cid = cpuid[seq];
cpu_set_t cpumask;
pid_t pid = syscall(__NR_gettid);

if(0 <= cid && CPU_MAX > cid) {
//绑定 CPUID
CPU_ZERO(&cpumask);
CPU_SET(cid, &cpumask);
sched_setaffinity(pid, sizeof(cpumask), &cpumask);
usleep(1000);
printf("task[%d] run on cpuid=%d\n", seq, cid);
}
else {
printf("task[%d] run on cpuid=auto\n", seq);
}

while(1) {
tdata[seq].a += 1;
tdata[seq].b += tdata[seq].e*8;
tdata[seq].c += 1;
tdata[seq].d += tdata[seq].e*8;
}

return NULL;
}

static void*
stat_root(void *arg)

{
arg = arg;
uint64_t ttl;
uint64_t d10[CPU_MAX];

while(1) {

if(0 == flag_stat) {
usleep(1000);
}
else {
flag_stat = 0;
ttl = 0;
for(int i = 0; i < thd_num; i++) {
tmp[i] = tdata[i].a;
}

for(int i = 0; i < thd_num; i++) {
tmp[i] = tdata[i].a;
d10[i] = tmp[i] - prev[i];
ttl += d10[i];
}

printf("\nTotal do times: %lu(sec)\n", ttl/10);
for(int i = 0; i < thd_num; i++) {
if(-1 == cpuid[i]) {
printf("\ttask[%d] cpu=auto do times: %lu(/sec)\n", i, d10[i]/10);
}
else {
printf("\ttask[%d] cpu=%d do times: %lu(/sec)\n", i, cpuid[i], d10[i]/10);
}

prev[i] = tmp[i];
}
}
}

return NULL;
}

static void*
timer_root(void *arg)
{
arg = arg;
uint64_t ttl;
uint64_t d10[CPU_MAX];

while(1) {
sleep(10);
flag_stat = 1;
}

return NULL;
}

static int
task_set(void)
{
pthread_t thdid;
for(int i = 0; i < thd_num; i++) {
pthread_create(&thdid, NULL, task_root, &seq[i]);
}

pthread_create(&thdid, NULL, timer_root, NULL);
pthread_create(&thdid, NULL, stat_root, NULL);

return 0;
}

int main(int argc, char **argv)
{
//program thread-num thread-cpu-seq
init();
argc--, argv++;
if(-1 == parse_cmd(argc, argv)) {
printf("Input param error\n");
exit(-1);
}

task_set();

while(1) {
sleep(1000);
}

return 0;
}

双 CPU-4 核-超线程 Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
逻辑 CPU 0 8 2 10 4 12 6 14 1 9 3 11 5 13 7 15
pysical id 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
core id 0 0 1 1 9 9 10 10 0 0 1 1 9 9 10 10
系统:centos8

测试线程:
单线程绑定 0 逻辑 CPU 测试结果(执行累加次数) 108363138 (次 /秒)
双线程绑定 0,1 逻辑 CPU 测试结果(执行累加次数) 79961987 (次 /秒)
3 线程绑定 0,1,2 逻辑 CPU 测试结果(执行累加次数) 108639280 (次 /秒)
4 线程绑定 0,1,2,3 逻辑 CPU 测试结果(执行累加次数) 97511278 (次 /秒)
5 线程绑定 0,1,2,3,4 逻辑 CPU 测试结果(执行累加次数) 115751101 (次 /秒)
6 线程绑定 0,1,2,3,4,5 逻辑 CPU 测试结果(执行累加次数) 138198505 (次 /秒)
7 线程绑定 0,1,2,3,4,5,6 逻辑 CPU 测试结果(执行累加次数) 129034696 (次 /秒)
8 线程绑定 0,1,2,3,4,5,6,7 逻辑 CPU 测试结果(执行累加次数) 126871151 (次 /秒)
9 线程绑定 0,1,2,3,4,5,6,7,8 逻辑 CPU 测试结果(执行累加次数) 157512706 (次 /秒)
10 线程绑定 0,1,2,3,4,5,6,7,8,9 逻辑 CPU 测试结果(执行累加次数) 141989197 (次 /秒)
[结论]
增加线程数量并没有想象中的增加性能。
预期的目标应该是增加线程数(在同一个 CPU 中分配给不同的 CORE 的时候性能应该倍数增加,实际上没有),和预期的相差很大。

测试进程:
每个进程开始一个累加统计线程
测试结果
进程 1 绑定 CPU0 测试结果(执行累加次数) 102847956 (次 /秒)
进程 2 绑定 CPU2 测试结果(执行累加次数) 102903297 (次 /秒)
进程 3 绑定 CPU4 测试结果(执行累加次数) 102909125 (次 /秒)
进程 4 绑定 CPU6 测试结果(执行累加次数) 102934502 (次 /秒)
进程 5 绑定 CPU3 测试结果(执行累加次数) 107560180 (次 /秒)
假如开一个进程,绑定 CPU 和别的进程绑定的 CPU 在同一个 CPU 的同一个 CORE 下的话,性能会变成一半,两个进程加起来和单独只开一个进程的时候差不多,
[结论]
开进程处理数据没有相互影响,和预期的一样,增加进程性能倍数增加。
两个进程开在同一个 CPU 的同一个 CORE 中的时候性能减半,因为使用同一套 CORE 的计算单元,所以可以理解。

[疑问]
多线程的性能变化应该和多进程的一样预期,实际测试结果多线程的性能提升很少。(到底是什么因素导致的这个测试结果,没有思路,有知道的大佬能告诉一下吗???
1075 次点击
所在节点    问与答
6 条回复
msg7086
2020-11-02 15:16:02 +08:00
你用多线程跑的时候,CPU 吃满了吗?
tom82232
2020-11-02 15:18:46 +08:00
@msg7086 CPU 是 100%us
msg7086
2020-11-02 15:46:33 +08:00
@tom82232 我的意思是,每个 Core 都吃满了么。然后就是看看多线程下的算力和时间计算有没有错。
上面代码贴得太乱实在读不下去了。
besto
2020-11-02 16:10:33 +08:00
先说点 别的,timer 做的毫无意义,你这里面全部没 mutex,不如 stat 的时候就一个简单逻辑 sleep(x), 然后直接算这个期间到底算了多少。多线程没有显著提升我觉得有很大原因是和 cache 命中有关系。 试试加大计算量:
diff --git a/b.c b/b.c
index 5168b0d..a92dc5e 100644
--- a/b.c
+++ b/b.c
@@ -28,6 +28,8 @@ uint64_t prev[CPU_MAX];
uint64_t tmp[CPU_MAX];
int flag_stat = 0;

+uint8_t *cache;
+
static void
init(void)
{
@@ -116,6 +118,7 @@ tdata[seq].a += 1;
tdata[seq].b += tdata[seq].e*8;
tdata[seq].c += 1;
tdata[seq].d += tdata[seq].e*8;
+memset(cache, 0, 64*1024*1024);
}

return NULL;
@@ -195,6 +198,7 @@ return 0;

int main(int argc, char **argv)
{
+ cache = malloc(64*1024*1024);
//program thread-num thread-cpu-seq
init();
argc--, argv++;
tom82232
2020-11-02 16:32:29 +08:00
@besto timer 可以不去考虑,都没关系。累加的时候处理的数据都没有变化,这样也会发生 cache 不命中?
besto
2020-11-02 17:36:42 +08:00
@tom82232 说实话,我不能确定是不是 cache 命中导致,但现象让我很怀疑。另一个可怀疑的点就是你的这个计算运算量的方法。。。所以让每个循环多做点事情也可能是减少误差的真正原因

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/721015

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX