<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在本篇文章當中主要給大家介紹 OpenMp for construct 的實現原理,以及與他相關的動態庫函數分析,與 for construct 非常相關的是迴圈的排程方式,在 OpenMP 當中一共有四種調調方式,auto, dynamic, guided, runtime, 在本篇文章當中主要是對 dynamic 的排程方式進行分析。
在介紹 for construct 的實現原理之前,我們首先需要了解一下編譯器是如何處理常式引數傳遞的(本文基於 x86_64 ISA),我們來看一下下面的程式碼在編譯之後函數引數的傳遞情況。
在前面的文章當中我們已經談到過了,在 x86 當中引數傳遞的規約,具體的內容如下所示:
暫存器 | 含義 |
---|---|
rdi | 第一個引數 |
rsi | 第二個引數 |
rdx | 第三個引數 |
rcx | 第四個引數 |
r8 | 第五個引數 |
r9 | 第六個引數 |
我們現在使用下面的程式碼來分析一下具體的情況(因為前面使用暫存器只能夠傳遞 6 個引數,而在後面我們要分析的動態庫函數當中會傳遞 7 個引數,因此這裡我們使用 8 個引數來測試一下具體的引數傳遞情況):
#include "stdio.h" void echo(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { printf("%d %d %d %d %d %d %d %dn", a8, a7, a1, a2, a3, a4, a5, a6); } int main() { echo(1, 2, 3, 4 ,5 ,6, 7, 8); return 0; }
上面的程式的反組合結果如下所示:
000000000040053d <echo>:
40053d: 55 push %rbp
40053e: 48 89 e5 mov %rsp,%rbp
400541: 48 83 ec 30 sub $0x30,%rsp
400545: 89 7d fc mov %edi,-0x4(%rbp)
400548: 89 75 f8 mov %esi,-0x8(%rbp)
40054b: 89 55 f4 mov %edx,-0xc(%rbp)
40054e: 89 4d f0 mov %ecx,-0x10(%rbp)
400551: 44 89 45 ec mov %r8d,-0x14(%rbp)
400555: 44 89 4d e8 mov %r9d,-0x18(%rbp)
400559: 8b 7d f4 mov -0xc(%rbp),%edi
40055c: 8b 75 f8 mov -0x8(%rbp),%esi
40055f: 8b 55 fc mov -0x4(%rbp),%edx
400562: 8b 45 18 mov 0x18(%rbp),%eax # a8
400565: 8b 4d e8 mov -0x18(%rbp),%ecx
400568: 89 4c 24 10 mov %ecx,0x10(%rsp)
40056c: 8b 4d ec mov -0x14(%rbp),%ecx
40056f: 89 4c 24 08 mov %ecx,0x8(%rsp)
400573: 8b 4d f0 mov -0x10(%rbp),%ecx
400576: 89 0c 24 mov %ecx,(%rsp)
400579: 41 89 f9 mov %edi,%r9d
40057c: 41 89 f0 mov %esi,%r8d
40057f: 89 d1 mov %edx,%ecx
400581: 8b 55 10 mov 0x10(%rbp),%edx # a7
400584: 89 c6 mov %eax,%esi # a8
400586: bf 64 06 40 00 mov $0x400664,%edi
40058b: b8 00 00 00 00 mov $0x0,%eax
400590: e8 8b fe ff ff callq 400420 <printf@plt>
400595: c9 leaveq
0000000000400597 <main>:
400597: 55 push %rbp
400598: 48 89 e5 mov %rsp,%rbp
40059b: 48 83 ec 10 sub $0x10,%rsp
40059f: c7 44 24 08 08 00 00 movl $0x8,0x8(%rsp) # 儲存引數 8
4005a6: 00
4005a7: c7 04 24 07 00 00 00 movl $0x7,(%rsp) # 儲存引數 7
4005ae: 41 b9 06 00 00 00 mov $0x6,%r9d # 儲存引數 6
4005b4: 41 b8 05 00 00 00 mov $0x5,%r8d # 儲存引數 5
4005ba: b9 04 00 00 00 mov $0x4,%ecx # 儲存引數 4
4005bf: ba 03 00 00 00 mov $0x3,%edx # 儲存引數 3
4005c4: be 02 00 00 00 mov $0x2,%esi # 儲存引數 2
4005c9: bf 01 00 00 00 mov $0x1,%edi # 儲存引數 1
4005ce: e8 6a ff ff ff callq 40053d <echo>
4005d3: b8 00 00 00 00 mov $0x0,%eax
4005d8: c9 leaveq
4005d9: c3 retq
4005da: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
從上面的組合程式我們可以知道 1 - 6,這幾個引數確實是通過暫存器傳遞的,對應的暫存器就是上文當中我們提到不同的引數對應的暫存器。但是引數 7 和引數 8 是儲存在棧上的。根據上面的 main 函數的組合程式分析,他對應的棧幀的記憶體佈局如下所示:
我們在來分析一下 echo 函數當中 printf 函數引數的傳遞情況,第二個引數和第三個引數分別是 a8, a7,應該分別儲存到暫存器 rsi/esi, rdx/edx 當中,在上面的組合程式碼當中已經使用註釋的方式進行標註出來了,從下往上進行分析可以看到 a8 儲存在位置 0x18(%rbp),a7 儲存在 0x10(%rbp),這個地址正是 main 函數儲存 a7(當進入函數 echo 之後,a7,和 a8 的位置分別是 rsp + 0x10), a8(當進入函數 echo 之後,a7,和 a8 的位置分別是 rsp + 0x10 + 0x8) 的位置,具體可以結合上面的記憶體佈局圖進行分析。
我們使用下面的程式碼來分析一下動態排程的情況下整個程式的執行流程是怎麼樣的:
#pragma omp parallel for num_threads(t) schedule(dynamic, size) for (i = lb; i <= ub; i++) body;
編譯器會將上面的程式編譯成下面的形式:
void subfunction (void *data) { long _s0, _e0; while (GOMP_loop_dynamic_next (&_s0, &_e0)) { long _e1 = _e0, i; for (i = _s0; i < _e1; i++) body; } // GOMP_loop_end_nowait 這個函數的主要作用就是釋放資料的記憶體空間 在後文當中不進行分析 GOMP_loop_end_nowait (); } GOMP_parallel_loop_dynamic_start (subfunction, NULL, t, lb, ub+1, 1, size); subfunction (NULL); // 這個函數在前面的很多文章已經分析過 本文也不在進行分析 GOMP_parallel_end ();
void GOMP_parallel_loop_dynamic_start (void (*fn) (void *), void *data, unsigned num_threads, long start, long end, long incr, long chunk_size) { gomp_parallel_loop_start (fn, data, num_threads, start, end, incr, GFS_DYNAMIC, chunk_size); } static void gomp_parallel_loop_start (void (*fn) (void *), void *data, unsigned num_threads, long start, long end, long incr, enum gomp_schedule_type sched, long chunk_size) { struct gomp_team *team; // 解析具體建立多少個執行緒 num_threads = gomp_resolve_num_threads (num_threads, 0); // 建立一個含有 num_threads 個執行緒的執行緒組 team = gomp_new_team (num_threads); // 對執行緒組的資料進行初始化操作 gomp_loop_init (&team->work_shares[0], start, end, incr, sched, chunk_size); // 啟動 num_threads 個執行緒執行函數 fn gomp_team_start (fn, data, num_threads, team); } enum gomp_schedule_type { GFS_RUNTIME, // runtime 排程方式 GFS_STATIC, // static 排程方式 GFS_DYNAMIC, // dynamic 排程方式 GFS_GUIDED, // guided 排程方式 GFS_AUTO // auto 排程方式 };
在上面的程式當中 GOMP_parallel_loop_dynamic_start,有 7 個引數,我們接下來仔細解釋一下這七個引數的含義:
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45