![]() |
|
|
void* add(void* x)
{
if(-1 == set_cpu(1))
{
return NULL;
}
for(sum=0;suma += sum;
((struct apple *)x)->b += sum;
}
return NULL;
}
int main (int argc, const char * argv[]) {
// insert code here...
struct apple test;
struct orange test1;
cpu_nums = sysconf(_SC_NPROCESSORS_CONF);
if(-1 == set_cpu(0))
{
return -1;
}
pthread_create(&ThreadA,NULL,add,&test);
for(index=0;index<ORANGE_MAX_VALUE;index++)
{
sum+=test1.a[index]+test1.b[index];
}
pthread_join(ThreadA,NULL);
return 0;
}
测量结果为:
图 5. 采用硬亲和力时间对比图(两线程)
其测量结果正是我们所希望的,但花费的时间还是比单线程的多,其原因与上面分析的类似。
进一步分析不难发现,样例程序大部分时间都消耗在计算 apple 上,如果将计算 a 和 b 的值,分布到不同的 CPU 上进行计算,同时考虑 Cache 的影响,效率是否也会有所提升呢?
图 6. 采用硬亲和力时间对比图(三线程)
从时间上观察,设置亲和力的程序所花费的时间略高于采用 Cache 的三线程方案。由于考虑了 Cache 的影响,排除了一级缓存造成的瓶颈,多出的时间主要消耗在系统调用及内核上,可以通过 time 命令来验证:
#time ./unlockcachemultiprocess
real 0m0.834s user 0m1.644s sys 0m0.004s
#time ./affinityunlockcacheprocess
real 0m0.875s user 0m1.716s sys 0m0.008s
通过设置 CPU 亲和力来利用多核特性,为提高应用程序性能提供了捷径。同时也是一把双刃剑,如果忽略负载均衡、数据竞争等因素,效率将大打折扣,甚至带来事倍功半的结果。
在进行具体的设计过程中,需要设计良好的数据结构和算法,使其适合于应用的数据移动和处理器的性能特性。
总结
根据以上分析及实验,对所有改进方案的测试时间做一个综合对比,如下图所示:
图 7. 各方案时间对比图
单线程原始程序平均耗时:1.049046s,最慢的不加锁三线程方案平均耗时:2.217413s,最快的三线程( Cache 为128)平均耗时:0.826674s,效率提升约26%。当然,还可以进一步优化,让效率得到更高的提升。
从上图不难得出结论:采用多核多线程并行设计方案,能有效提高性能,但如果考虑不全面,如忽略带宽、数据竞争及数据同步不当等因素,效率反而降低,程序执行越来越慢。
如果抛开本文开篇时的限制,采用上文曾提到的另外一种数据分解模型,同时结合硬亲和力对样例程序进行优化,测试时间为0.54s,效率提升了92%。
软件优化是一个贯穿整个软件开发周期,从开始设计到最终完成一直进行的连续过程。在优化前,需要找出瓶颈和热点所在。正如最伟大的 C 语言大师 Rob Pike 所说:
如果你无法断定程序会在什么地方耗费运行时间,瓶颈经常出现在意想不到的地方,所以别急于胡乱找个地方改代码,除非你已经证实那儿就是瓶颈所在。
将这句话送给所有的优化人员,和大家共勉。
|
Copyright @ 2006 天地合华科技 All Rights Reserved 北京天地合华科技有限责任公司 京ICP备09031756号 |
|
电话:010-51664188 51664189 51667681 邮箱:412414798@qq.com 地址:北京市海淀区阜成路42号中裕商务花园1号楼101室 |