多核调度的问题研究

      各位好,今天看到有朋友提了一下多核程序设计方面的东西,恰好前段时间看过相关的内容,所以就花了一个晚上,总结了一下。可能写得不是很好,不过但愿能够起到抛砖引玉的效果。希望各位都谈谈自己对于多核程序设计的一点想法,这样大家都能够有所提高。
谢谢!



We are dedicating all of our future product development to multicore designs. We believe this is a key inflection point for the industry.
                                                Intel President  
                                                        Paul Otellini
                                                Describing Intel’s future direction at the Developers Forum 2005



    多核下的多线程程序设计与传统的单核下的多线程程序设计有着一定的差别,在单CPU下,是多个线程在同一个CPU上并发地执行,而在多核下,则是由多个线程在多个核上并行地执行。
    但是,目前的程序设计中对于多核的利用并没有达到预期的效果。因此,为了能够在多核的环境下设计出更适合多核系统的程序,则是一个挑战。
    要做到这一点,就必须将应用程序看做是众多相互依赖的任务的集合,将应用程序划分成多个独立的任务,并确定这些任务之间的相互依赖关系,这就称为分解(decomposition)。如下如示:

分解方式                                  设计                                            说明
任务分解                    不同的程序行为采用不同的线程实现               常用于GUI应用程序
数据分解                   多个线程对不同的数据块执行相同的操作               常用于音频、图像处理和科学计算应用程序
数据流分解                   一个线程的输出作为另一个线程的输入               应注意尽量避免延迟


    任务分解:对应用程序根据其执行的功能进行分解的过程称为任务分解(task decomposition)。根据这种方法,就能够对众多的独立任务进行分类。如果其中两个任务能够同时运行,那么开发人员就应该对其进行调度,形成二者之间的并行执行。

    数据分解:数据分解也称为数据级并行(data-level parallelism)。是将应用程序根据各任务所处理的数据而非按任务来进行分解的方法,即以数据为中心。一般而言,能够按照数据分解方式进行分解的应用程序都包含多个线程,这些线程分别对不同的数据对象执行相同的操作。

    数据流分解:在很多情况下,当对一个问题进行分解时,关键问题不在于采用一些什么任务来完成这个工作,而在于数据在这些任务之间是如何流动的。这个时候就要采用数据流分解方式,如典型的生产者/消费者问题。

    对于任务分解,有两个需要注意的地方:
    1. 划分的对象是计算,将计算划分为不同的任务
    2. 划分后,研究不同任务所需的数据,如果这些数据不相交,则证明划分是成功的,如果数据有相当程序的相交,意味着要重新进行数据划分和功能划分。
    如在一个气候模型中,需要考虑到地表模型、水文模型与海洋模型等多种情况,那么就应该将这几种模型划分成不同的任务,再分别进行并行地运算。

    对于数据分解,划分的对象是数据,可以是算法的输入数据、中间处理数据和输出数据。在划分时应该考虑到数据上的相应操作。
    最简单的情况下,比如对1000万个数进行相加,可以对其进行数据上的分解,用多个线程来分别计算不同批次的数据。然后再将计算的中间数据加到一起成为最终的结果。

常见的并行程序设计问题的解决方法

1. 线程过多
        线程并不是越多越好,对于某个程序,如果线程过多反而会严重地降低程序的性能。这种影响主要在于:
        将给定的工作量划分给过多的线程会造成每个线程的工作量过少,因此可能导致线程启动和终止的开销比程序实际工作的时间还要多。
        同时,太多并发线程的存在将导致共享有限硬件资源的开销增大。如保存和恢复寄存器状态的开销、保存和恢复线程cache状态的开销、废除虚存的开销、线程聚集在一起等待获取某个锁。
        怎样解决这个问题:
        限制可运行线程的个数
        将计算线程与I/O线程分离开
        使用已有的技术,如OpenMP,线程池等

2. 数据竞争、死锁
        死锁,想必大家都很熟悉。这里谈谈一些简单的避免死锁的规则:
        加锁的顺序是关键,使用嵌套的锁时必须保证以相同的顺序获取锁
        防止发生饥饿:即这个代码的执行是否一定会结束。
        不要重复请求同一个锁
        越复杂的加锁方案越有可能造成死锁—设计应力求简单

3. 竞争激烈的锁
        即使是正确使用锁来避免数据竞争,但如果各线程对锁的竞争很激烈,那么也会引发性能问题。即很多个线程来竞争同一个锁。在这个情况下,可以考虑将资源划分成若干个部分,然后用彼此独立的锁分别保护各个部分。即合理地安排加锁粒度的问题。在早期的Linux内核中就使用了大内核锁,现在已经把锁给细划到不同的子系统中去了。
        如果一个数据结构被频繁读取但不被频繁写入,就可以使用读写锁来解决竞争。

4. 线程安全函数
        已有的一些函数并不是线程安全的,具体的线程安全函数可以参考APUE2上面的线程一章。

5. 存储效率问题        
        目前,处理器的速度已经比存储器快很多,一个处理器从内存中读或写一个值的时间内可以完成上百次的操作。因此,现在的程序往往受限于存储器的瓶颈。
        首先,可以通过节省带宽,可以减少与存储器的数据交换数量,要节省带宽就要将数据压缩得更加紧凑。
        其次是cache的利用。可以减少数据在不同CPU的cache间的移动。CPU亲合力(CPU Affinity)就是指在Linux系统中能够将一个或多个进程绑定到一个或多个处理器上运行。一个进程的CPU亲合力掩码决定了该进程将在哪个或哪几个CPU上运行,在一个多处理器系统中,设置CPU亲合力的掩码可能会获得更好的性能。
        在下面的例子中讲解了如何利用将某个进程绑定以某个CPU上运行的实例。
http://linux.chinaunix.net/bbs/v ... p%3Bfilter%3Ddigest


Cache缓存与一些程序性能优化的小方法:

由于CPU运算速度的增长远远大于内存速度的增长,同时由于程序运行的局部性原理,所以现代计算机体系结构中引入了cache。
        其实系统的存储器本身就是一个层次结构,从寄存器->高速缓存->主存->本地磁盘->颁布式文件系统。
        在下面的贴子中的一个文档对cache方面讲解得非常不错,可以看看:
http://bbs.chinaunix.net/viewthr ... mp;highlight=scutan

        高速缓存的性能主要有以下几个方面:

1. 高速缓存的大小:
        当CPU接收到指令后,它会最先向CPU中的一级缓存去寻找相关的数据,如果未命中,则继续向下一级的二级缓存中寻找。所以高速缓存越大,命中的机率也就越高。

2. 块大小的影响
        大的块有利有弊,一方面,较大的块能利用程序中可能存在的空间局部性,帮助提高命中率。不过,对于给定的高速缓存的大小,块越大就意味着缓存行数越小,这会损害时间局部性比空间局部性更好的程序中的命中率。同时,因为块越大,传达时间也就越长。

3. 相联度的影响
        较高的相联度的优点的降低了高速缓存由于冲突不命中出现抖动的可能性。不过,较高的相联度会造成较高的成本。

4. 前端总线的影响
        现在的CPU技术发展很快,运算速度提高很大,而足够大的前端总线可以保障有足够的数据供给CPU,较低的前端总线将无法供给足够的数据给CPU,限制了CPU性能的发挥。

        最后谈谈程序性能优化的相关内容。
        对于程序性能的优化,首先应该考虑的架构以及算法这两方面的优化,最后再来考虑下面所讲述的这些优化。
        消除连续的函数调用
        消除不必要的存储器引用
        通过展开循环降低循环开销
        提高并行性
        重新排列循环以提高空间局部性
        让最常运行部分运行得更快


参考资料:
[1]. John L. Hennessy, David A. Patterson. 计算机体系结构:量化研究方法. 第4版
[2]. Shameem Akhter, Jason Roberts. 多核程序设计技术—通过软件多线程提升性能
[3]. Randal E. Bryant, David O’Hallaron. 深入理解计算机系统
[4]. Daniel P.Bovet, Marco Cesati. 深入理解Linux内核 第3版

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
光电经纬仪是最早、最广泛应用于飞行器测控领域的光电跟踪测量设备,它 的组成部分包括大地测量光学经纬仪、激光跟踪测量系统、微机控制系统与图像 处理系统组成。光电经纬仪通过记录飞行过程中的目标图像,并测量传动机架的 角度,从而获得目标飞行参数,它在飞行实况记录中发挥重要的作用 [1] 。此外, 它还可以实现迅速定位目标位置和自动跟踪高速目标,已被广泛地应用于诸如航 天发射、飞行器测控等光电测量领域 [1] 。 随着数字图像处理等技术的发展,光电经纬仪由胶片式成像向数字式成像转 变。此外,高帧速率、高分辨率成像传感器技术已被广泛应用于光电经纬仪。这 些给光电经纬仪实时图像处理平台的发展带来新的挑战:复杂图像处理算法的实 现和数据吞吐量的巨大需求 [1-2] 。 DSP 作为一种密集型数据运算与实时信号处理的微处理器,能够很好的满足 复杂图像处理算法、实时性处理的需求。DSP 技术经过多年的发展,被广泛应用 在信号、图像、通信等技术领域,尤其是高性能计算、高速实时图像处理、超大 数据量处理的军用电子领域 [2] 。现今的图像处理平台由于芯片单片运算能力受到 限制,绝大部分使用了多个 DSP + FPGA 的架构,才能勉强实现实时图像处理任 务 [3] 。但是这样的平台带来的困难是显而易见的: 1. 系统结构复杂。采用多片 DSP+FPGA 的架构,系统的整体处理性能受片 间(DSP 与 FPGA 之间、DSP 与 DSP 之间)通信带宽瓶颈而下降。 2. 系统功耗大。多片 DSP 在单块电路板上的集成度越高,带来了单板整体 功耗的增加和散热的问题,导致单板多片 DSP 整体处理性能的可靠性和稳定性。 3. 系统调试困难。由于系统结构的复杂,导致系统的调试异常的困难。芯 片之间的任务分配、数据传输、并行处理非常复杂,使得产品在设计、调试、生 产阶段的难度加大。 本文研究的课题来源于光电经纬仪图像处理平台由多片 DSP 架构升级到多 核 DSP 架构而提出的系统应用需求。结合实验室的项目情况,本文将重点放在 多核 DSP 并行的以下相关技术: 1. DSP+FPGA 架构下图像数据流的设计。光电经纬仪的图像处理系统需要 兼容前端的多种图像输入格式,包括 CameraLink、SDI 以及光纤接口,DSP+FPGA载板搭配不同的子板就可以实现输入的灵活性;此外,DSP+FPGA 图像处理系 统中的高速 SRIO 接口用于图像数据通信。本文在 CameraLink 和 SRIO 这两个关 键接口做了一定的研究工作。 2. 多核环境下并行访问共享/外部存储器的性能研究和设计原则分析。多核 DSP 中存在多个主设备,包括多个 DSP 内核、多个 EDMA 设备等,它们并行访 问存储器的数据带宽,对于应用程序存储资源的安排、软件结构的设计是至关重 要的。 3. 多核 DSP 并行调度方案的研究多核 DSP 图像处理平台,一方面要实 现复杂的图像处理算法,另一方面要满足超大运算量对实时性处理的需求。基于 多核的系统应用开发关键的一步,就是选择合适的处理模型实现任务并行调度。 本文将介绍多核 DSP 并行调度的几种方案,并以算法实例对主从模型进行分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值