cilk之User Guide学习笔记(3)Cilk执行模型

来源:互联网 发布:淘宝旺铺免费装修模板 编辑:程序博客网 时间:2024/06/05 23:55

说明:

下载User Guide: http://software.intel.com/zh-cn/forums/showthread.php?t=77996&o=a&s=lr(Cilk_User_Guide.pdf)

主要是对该用户指南(中文版)的一些学习笔记和简化并更加自己的理解添加一些代码示例,可以参考原文档获取更多细节。


cilk的三个关键字是很容易理解和使用的,但是要真正的理解cilk的执行和正确使用复杂的情况,就需要了解Cilk执行模型。


关键概念:

strand

用来描述程序中串行部分,更准确地说,strand的定义是“不包含任何并行控制结构的任意指令序列”。

一个不是某个更长strand一部分的strand被称为最大strand,也就是起点和终点为并行控制结构的strand.

衍生和同步

Cilk程序包含两种并行控制结构 – 衍生(spawn)和同步(sync)

说明:并行循环cilk_for是将某个问题分解为多个衍生和同步的简便写法。

注意:在cilk程序中,一次衍生有且只有一个输入strand和两个输出strand。一次同步有两个或更多输入strand,有且只有一个输出strand


strand图

传统串行程序的描述通常使用调用关系图或类层次图。对于Cilk并行程序,使用strand图来表达某个Cilk程序中串行/并行结构,其是一个有向无环图(DAG),其中,strands表示为直线和弧线(边),并行控制结构表示为圆形节点(顶点)。如下示例:


其中1234都是strands,AB为并行控制结构,其中A为衍生,B为同步。


工时和跨度

完成程序所需的处理器时间总数是所有标签数字之和。该值被定义为工时。

跨度,有时也被称作关键路径长度,是由程序起点到终点最长的一条路径。

通常,可以在上面的strand图中的边上标明每一个最长strand的执行时间(处理器时间),所以工时就是所有的边的时间的总和,而跨度是从起点到终点最长的一条路径的时间总和。显然,跨度小于等于工时。

工时的意义是:如果该程序在单个处理器上执行,那么它将运行工时所表示的时间。

跨度的意义是:在理想状态下(例如,没有调度开销时)以及无限多处理器可用时,该程序会运行的时间。


cilk程序的加速比和缩放性

一般而言,使用工时和跨度来预测一个Cilk程序在多处理器系统上的加速比和缩放性。假设,T(P)是程序在P个处理器上的执行时间,T(1)是工时,T(∞)是跨度。一般情况下,有如下工时定律:
T(P)>= T(1)/P
有如下跨度定律:
T(P)>= T(∞)

P个处理器上的加速比是:
T(1)/T(P)

最大的可能加速比会在无限多个处理器上获得.

并行度被定义为假定在无限多个处理器上运行时加速比。因此,并行度可以表示为:
T(1)/T(∞)


strand到工作线程的映射:

DAG并不依赖于处理器的数目。执行模型描述了运行调度程序是如何将strand映射到工作线程。引入并行后多个strand可以并行执行。但是在Cilk程序中,可以并行执行的strand并不一定会并行执行。调度程序会动态作出决定。

参考文章:http://software.intel.com/zh-cn/blogs/2010/06/25/cilk-strand/了解cilk中strand到workde(工作线程)的映射关系。

和其它并行编程方法一样,在程序运行过程中Cilk的运行时系统会将用户程序中的strand映射到操作系统线程上。但是,为了保证程序的串行语义Cilk的运行时系统会采取一些与众不同的策略。

关于cilk这个映射关系,需要重点理解以下几点:

1. 为了保证串行语义,衍生出来的函数总是和进入衍生节点的那个strand在同一个工作线程上执行。如果此时有其它工作线程可用,那么延续部分可以在另外的工作线程上执行。我们称这样为密取(steal),也就是说延续部分被新的工作线程密取了。

2. 在cilk_sync之后,程序执行可以由进入同步接点的任一工作线程继续。

总之,其关键思想包括:

在cilk_spawn之后,子任务总是和调用者在同一工作线程(即系统线程)上执行。
在cilk_spawn之后,延续部分可以在另一工作线程上执行。如果这样,我们称延续部分被另一工作线程密取。
在cilk_sync之后,程序执行可以由进入同步接点的任一工作线程继续。


cilk中的异常处理:

Cilk语言扩展试图尽可能地保持C++异常处理语义。通常这要求在有异常等待处理时限制并行度,以及程序在进行异常处理时不能依赖于并行。异常处理逻辑如下所述:

如果一个异常被抛出且未在繁衍的子任务中被捕获,那么该异常将会在下一个同步点被父任务重新抛出。

如果父任务或其它子任务也抛出一个异常,那么在串行执行顺序下第一个被抛出的异常具有优先权。那些逻辑上靠后的异常将被丢弃。目前没有机制能够收集并行抛出的多个异常。


原创粉丝点击