青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++ Coder

HCP高性能計算架構(gòu),實現(xiàn),編譯器指令優(yōu)化,算法優(yōu)化, LLVM CLANG OpenCL CUDA OpenACC C++AMP OpenMP MPI

C++博客 首頁 新隨筆 聯(lián)系 聚合 管理
  98 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks

#

最近在實現(xiàn)一個向量相稱的CUDA程序的時候,碰見一個讓我很頭疼的問題。基本癥狀是:計算結(jié)果在小數(shù)據(jù)量的時候是完全正確的,如果向量的維數(shù)增大到一定數(shù)值后,計算結(jié)果就不對了。我查了好久,終于找到了問題的源頭。竟然是數(shù)據(jù)類型的問題,寫下來提醒后來人!

我在內(nèi)核函數(shù)中使用以下語句:

01.unsigned char tx = threadIdx.x;  
02.unsigned char bx = blockIdx.x;  
03.unsigned int id = tx + bx*blockDim.x;  

 

id竟然不對了。我需要ls個線程,如果ls的數(shù)目足夠大,使得bx的值溢出了。


解決方法是: 

 

unsigned short bx = blockIdx.x;

頭疼的解決總會是好的。歡迎大家的駐足,我繼續(xù)。。


http://blog.csdn.net/bendanban/article/details/7971447
posted @ 2012-10-21 12:56 jackdong 閱讀(499) | 評論 (0)編輯 收藏

問題描述:有很多朋友希望自己的MFC程序中能使用CUDA。就一直搜索MFC項目配置CUDA的資料。在這里以個人的經(jīng)驗和理解向還在迷茫的朋友們說幾點,看完這幾點說明,相信大家不會再迷茫。

1、首先微軟提供過的各種項目模版只是簡化了我們的開發(fā)時間,它的實質(zhì)還是C或者C++語言。所以我們只要把神馬MFC項目理解為普通的C\C++項目就可以了。

2、基于第一點,我們應(yīng)該做些什么那?只要在我們的MFC項目下按照一般C\C++程序添加CUDA代碼就可以了。這一點我們應(yīng)該思考,添加了代碼就可以了嗎?當(dāng)然不可以!應(yīng)該思考一下文件的編譯過程,在沒有指定編譯器的情況下你的CUDA程序怎么可能被正確編譯那?你必須選擇.cu文件的編譯規(guī)則!如果你使用runtime,你要添加自定義編譯規(guī)則,然后修改你的cu文件的屬性,告訴VS你的cu問價是誰來編譯的。

3、根據(jù)nvcc的編譯規(guī)則,cu文件首先會被編譯,然后生成一大堆的obj文件,然后是微軟的編譯器開始工作,他編譯了剩下的程序。然后是連接器,它連接了所有obj,lib。然后你如果想執(zhí)行,執(zhí)行就是了。

4、如果大家覺得這種方法不可靠,完全可以把cuda的程序?qū)懗蒁LL的,然后在大家想使用CUDA的程序中添加lib、dll。

 

以上是我個人理解,如有可以探討的問題,可以評論,我會及時做出回答。微笑


http://blog.csdn.net/bendanban/article/details/7606116
posted @ 2012-10-21 12:54 jackdong 閱讀(442) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/7918391

本文以CUDA4.2為例講解如何在Ubuntu12.04上安裝CUDA

注意一點,在安裝之前,必須確保自己的GPU是NVIDIA的GPU,并且支持CUDA。如果不確定自己的顯卡是否支持CUDA,可以在http://developer.nvidia.com/cuda-gpus中找到支持CUDA的GPU列表。如果你的顯卡是ATI的,可以使用OpenCL來獲得GPU的計算資源(http://www.khronos.org/opencl).

 

如果你的GPU滿足上面的要求,下面我們就開始安裝了。

第一步:下載安裝文件,安裝文件driver,toolkit,SDK。可以在http://developer.nvidia.com/cuda/cuda-toolkit-archive下載到自己想安裝的版本。特別注意一下自己的系統(tǒng)是多少位的,在終端執(zhí)行下面的命令可以知道你的系統(tǒng)的位數(shù)。

[]$uname -m

 

i686是32位系統(tǒng),x86_64是64位系統(tǒng)。至于選擇那個toolkit選擇Ubuntu11.04是可行的,至少我使用了幾個月了沒遇到問題。

 

 

第二步:安裝驅(qū)動。

確保所有需要的東西都已經(jīng)安裝好了。

 

$sudo apt-get install freeglut3-dev build-essential libx11-dev libxmu-dev libxi-dev libgl1-mesa-glx libglu1-mesa libglu1-mesa-dev binutils-gold

為了不讓系統(tǒng)打擾我們安裝驅(qū)動,把一些需要的模塊列入黑名單:

[]$gksu gedit /etc/modprobe.d/blacklist.conf

在打開的文件里添加一下幾行

blacklist amd76x_edac
blacklist vga16fb
blacklist nouveau
blacklist rivafb
blacklist nvidiafb
blacklist rivatv

將文件保存后退出。

 

 

為了能去除所有NVIDIA的殘余物,在終端中執(zhí)行下面的命令:

sudo apt-get remove --purge nvidia*

這個命令可能需要執(zhí)行一段時間,所以要耐心的等等。等它完成了,重新啟動你的機(jī)器。在登錄界面出現(xiàn)后,先不要登錄,在鍵盤上按下Ctrl+Alt+F1組合鍵,以文本的方式登錄,找到你的驅(qū)動安裝文件,執(zhí)行下面的命令:

sudo service lightdm stop
chmod a
+x devdriver*.run

這里devdriver*.run指的是你的驅(qū)動的名字。下面是安裝。

sudo ./devdriver*.run

安裝結(jié)束后,重新啟動系統(tǒng)。

 

 

第三步:登錄后,打開終端,安裝toolkit

在終端下進(jìn)入toolkit的目錄,執(zhí)行下面的命令:

chmod a+x cudatoolkit*.run
sudo .
/cudatoolkit*.run

 

cudatoolkit*.run代表你的toolkit的安裝文件。

這樣安裝之后還要確保你安裝的動態(tài)鏈接庫可以被自己的程序找到。最好在使用CUDA之前執(zhí)行下面的命令。

對于32位系統(tǒng):

 

export LD_LIBRARY_PATH=/usr/local/cuda/lib:$LD_LIBRARY_PATH

對于64位系統(tǒng):

export LD_LIVRARY_PATH=/usr/local/cuda/lib:$LD_LIBRARY_PATH
export LD_LIVRARY_PATH
=/usr/local/cuda/lib64:$LD_LIBRARY_PATH

第四步:安裝sdk。實際上,這一步并不是使用GPU計算的必要部分,這里面只是包含了一些有用的例子。不過還是推薦大家安裝這個SDK。

在終端下進(jìn)入包含SDK的目錄,執(zhí)行下面的命令

chmod a+x cudasdk.run
.
/cudasdk.run

 

cudasdk.run代表了你的SDK的安裝文件。

 

OK了,如果有問題,一定要留言奧。。。

 

PS:本文參考了一篇英文的文章,不過我沒有找到那篇文章,要是有網(wǎng)友找到了,可以給我留言。我加上對它的引用。







 



posted @ 2012-10-21 12:51 jackdong 閱讀(530) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/7673607
給程序計時對于程序員來說實在是太重要了,在windows上的那個clock()實在是不夠精確,精度只有10ms,真讓人難過。研究了下windows下使用C、C++計時的函數(shù),給大家分享下。

主要就是兩個函數(shù)的使用。我先把一段可以運行的代碼貼出來,然后講講這兩個函數(shù)。

#include <windows.h>
#include 
<stdio.h>
int main(int argc, char **argv)
{
    LARGE_INTEGER freq;
    LARGE_INTEGER start_t, stop_t;
    
double exe_time;
    QueryPerformanceFrequency(
&freq);
    fprintf(stdout, 
"The frequency of your pc is %d.\n", freq.QuadPart);
    QueryPerformanceCounter(
&start_t);
    Sleep(
1000);
    QueryPerformanceCounter(
&stop_t);
    exe_time 
= 1e3*(stop_t.QuadPart-start_t.QuadPart)/freq.QuadPart;
    fprintf(stdout, 
"Your program executed time is %fms.\n", exe_time); 
    getchar();
    
return 0;
}

 

1、LARGE_INTEGER在微軟的編譯器中實際上是一個union,它的定義如下:
typedef union _LARGE_INTEGER
{  
    
struct
 
    
{    
        DWORD LowPart;   
        LONG HighPart;  
    }

    
struct
 
    
{   
        DWORD LowPart;    
        LONG HighPart;  
    }
 u;  
    LONGLONG QuadPart;
}
 LARGE_INTEGER,  *PLARGE_INTEGER;


如果你使用的編譯器支持64位整數(shù),那么可以使用QuadPart來引用變量的值。如果你的編譯器不支持64位整數(shù),那么可以使用LowPart和HighPart來引用64位整數(shù)的低32位和高32位。

2、QueryPerformanceFrequncy(LARGE_INTEGER *freq)

它用于獲得你的機(jī)器一秒鐘執(zhí)行多少次,就是你的時鐘周期。

3、QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)

它獲得的是CPU從開機(jī)以來執(zhí)行的時鐘周期數(shù)。

 

O啦。。。。好好用用它吧。






posted @ 2012-10-21 12:45 jackdong 閱讀(541) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/7669624

總有些童鞋想知道怎么在CUDA中使用二維數(shù)組([M][N]這種類型),其實這個很簡單,不過你要完全弄明白,必須對指針,地址等概念非常清楚才行。寫這篇博客解決下大家這個問題:

1、首先講述一下在一般C語言中如何使用二維數(shù)組。

int r, c;
int **arr = (int**)malloc(ROWS*sizeof(int*));
int *data = (int*)malloc(COLS*ROWS*sizeof(int));
for (r = 0; r < ROWS; r++)
{
    arr[r] 
= data + r*COLS;
}


free(arr);
free(data);

 


 代碼中的arr實個二維數(shù)組變量了,你可以在for循環(huán)之后arr[i][j]的方式使用它。

 

2、告訴你如何在CUDA中使用二維數(shù)組可以類比1中的方法,不過你要清楚幾點,這幾點在代碼之后說明。

#include <stdio.h>
#include 
<stdlib.h>
#include 
<cuda_runtime.h>

#define ROWS 32
#define COLS 16
#define CHECK(res) if(res!=cudaSuccess){exit(-1);}
__global__ 
void Kerneltest(int **da, unsigned int rows, unsigned int cols)
{
    unsigned 
int row = blockDim.y*blockIdx.y + threadIdx.y;
    unsigned 
int col = blockDim.x*blockIdx.x + threadIdx.x;
    
if (row < rows && col < cols)
    
{
        da[row][col] 
= row*cols + col;
    }

}


int main(int argc, char **argv)
{
    
int **da = NULL;
    
int **ha = NULL;
    
int *dc = NULL;
    
int *hc = NULL;
    cudaError_t res;
    
int r, c;
    
bool is_right=true;

    res 
= cudaMalloc((void**)(&da), ROWS*sizeof(int*));CHECK(res)
    res 
= cudaMalloc((void**)(&dc), ROWS*COLS*sizeof(int));CHECK(res)
    ha 
= (int**)malloc(ROWS*sizeof(int*));
    hc 
= (int*)malloc(ROWS*COLS*sizeof(int));

    
for (r = 0; r < ROWS; r++)
    
{
        ha[r] 
= dc + r*COLS;
    }

    res 
= cudaMemcpy((void*)(da), (void*)(ha), ROWS*sizeof(int*), cudaMemcpyHostToDevice);CHECK(res)
    dim3 dimBlock(
16,16);
    dim3 dimGrid((COLS
+dimBlock.x-1)/(dimBlock.x), (ROWS+dimBlock.y-1)/(dimBlock.y));
    Kerneltest
<<<dimGrid, dimBlock>>>(da, ROWS, COLS);
    res 
= cudaMemcpy((void*)(hc), (void*)(dc), ROWS*COLS*sizeof(int), cudaMemcpyDeviceToHost);CHECK(res)

    
for (r = 0; r < ROWS; r++)
    
{
        
for (c = 0; c < COLS; c++)
        
{
            printf(
"%4d ", hc[r*COLS+c]);
            
if (hc[r*COLS+c] != (r*COLS+c))
            
{
                is_right 
= false;
            }

        }

        printf(
"\n");
    }

    printf(
"the result is %s!\n", is_right? "right":"false");
    cudaFree((
void*)da);
    cudaFree((
void*)dc);
    free(ha);
    free(hc);
    getchar();
    
return 0;
}

 


在CUDA中使用二維數(shù)組的幾點說明:

1)da是一個二維變量,一定更不可以在33行的時候把ha改成da!一定要記住顯存和內(nèi)存是相互獨立的,主機(jī)端的程序不可以直接操作顯存!必須通過CUDA 提供的API函數(shù)來操作!

2)注意在內(nèi)存申請時強(qiáng)制類型轉(zhuǎn)換(void**)(&),怎么把***的變量轉(zhuǎn)成**了!!這主要是API借口決定的,最好自己顯式轉(zhuǎn)換格式,避免不必要的麻煩。

3)看見數(shù)據(jù)拷貝的函數(shù)了嗎,類型、類型、還是類型。

4)別忘了釋放內(nèi)存和顯存!看見沒,還是類型。

5)很希望這篇博客能幫到大家,可是我真的不推薦大家在GPU上使用二維數(shù)組!真的!!為什么呢?終歸是效率惹的禍!顯存的訪問總是慢的。二維訪存,可是連續(xù)訪問了兩次啊。要是老這樣做,不但執(zhí)行效率低,而且寫代碼也慢。如果對內(nèi)存的概念不熟悉,千萬別趟這趟渾水。看懂這段代碼,就當(dāng)是學(xué)習(xí)一下或者理解下內(nèi)存、顯存與內(nèi)存獨立的概念和規(guī)則吧。

附上執(zhí)行結(jié)果:


 


posted @ 2012-10-21 12:43 jackdong 閱讀(774) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/7753995
剛學(xué)了一招,可以使用編譯器的-D選項來定義程序中使用的宏。
#include <stdio.h>
int main(int argc, char **argv)
{
    #ifdef MY_MAC
    printf(
"Hello -D.\n");
    
#else 
    printf(
"MY_MAC was not defined.\n");
    
#endif
    
return 0;
}
上面的代碼中使用了MY_MAC宏,

 

【】$g++ -DMY_MAC -o dtest dtest.c

執(zhí)行結(jié)果:

【】$ ./dtest 
Hello 
-D.
【】$

無掉-D選項,重新編譯,執(zhí)行結(jié)果:

【】$ g++ ./dtest.c -o dtest
【】$ .
/dtest 
MY_MAC was not defined.

我們可以利用編譯器這個選項來調(diào)試我們的程序奧。

 

如果我的宏代表一個常量怎么辦呢??

看看修改后的代碼:

 

#include <stdio.h>
int main(int argc, char **argv)
{
    #ifdef MY_MAC
    printf(
"Hello -D. %d\n", MY_MAC);
    
#else 
    printf(
"MY_MAC was not defined.\n");
    
#endif
    
return 0;
}



我輸出了宏代表的值。

 

在終端執(zhí)行一下命令:

 

【】$ g++ -DMY_MAC=5 ./dtest.c -o dtest
【】$ .
/dtest 
Hello 
-D. 5
【】$

如果程序中有多個宏可以這樣編譯

【】$g++ -DMAC1=5 -DMAC2=6 soucefile.c

^_^,,很興奮是吧??這樣我們就不用在代碼里修改宏變量了。。




posted @ 2012-10-21 12:41 jackdong 閱讀(323) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/7742593

在網(wǎng)上找了找關(guān)于Progfile的工具,找到了這篇文章覺得不錯,轉(zhuǎn)來分享下。對原文修改了下。

本文介紹了如何使用Gnu gprof 對Linux平臺下的現(xiàn)有程序進(jìn)行優(yōu)化分析和生成程序調(diào)用圖。主要偏重于對生成和使用流程圖作介紹.

Gprof 簡介:
Gprof功能:打印出程序運行中各個函數(shù)消耗的時間,可以幫助程序員找出眾多函數(shù)中耗時最多的函數(shù)。產(chǎn)生程序運行時候的函數(shù)調(diào)用關(guān)系,包括調(diào)用次數(shù),可以幫助程序員分析程序的運行流程。
有了函數(shù)的調(diào)用關(guān)系,這會讓開發(fā)人員大大提高工作效率,不用費心地去一點點找出程序的運行流程,這對小程序來說可能效果不是很明顯,但對于有幾萬,幾十萬代碼量的工程來說,效率是毋庸置疑的!而且這個功能對于維護(hù)舊代碼或者是分析Open Source來說那是相當(dāng)誘人的,有了調(diào)用圖,對程序的運行框架也就有了一個大體了解,知道了程序的“骨架“,分析它也就不會再那么茫然,尤其是對自己不熟悉的代碼和Open Source。費話不多說了,讓我們開始我們的分析之旅吧!

Gprof 實現(xiàn)原理:
通過在編譯和鏈接你的程序的時候(使用 -pg 編譯和鏈接選項),gcc 在你應(yīng)用程序的每個函數(shù)中都加入了一個名為mcount ( or  “_mcount”  , or  “__mcount” , 依賴于編譯器或操作系統(tǒng))的函數(shù),也就是說你的應(yīng)用程序里的每一個函數(shù)都會調(diào)用mcount, 而mcount 會在內(nèi)存中保存一張函數(shù)調(diào)用圖,并通過函數(shù)調(diào)用堆棧的形式查找子函數(shù)和父函數(shù)的地址。這張調(diào)用圖也保存了所有與函數(shù)相關(guān)的調(diào)用時間,調(diào)用次數(shù)等等的所有信息。

Gprof基本用法:
1. 使用 -pg 編譯和鏈接你的應(yīng)用程序。

2. 執(zhí)行你的應(yīng)用程序使之生成供gprof 分析的數(shù)據(jù)。

3. 使用gprof 程序分析你的應(yīng)用程序生成的數(shù)據(jù)。

Gprof 簡單使用:
讓我們簡單的舉個例子來看看Gprof是如何使用的。

1.打開linux終端。新建一個test.c文件,并生用-pg 編譯和鏈接該文件。 test.c 文件內(nèi)容如下:
#include "stdio.h"
#include 
"stdlib.h"
void a()
{
  printf(
"\t\t+---call a() function\n");
}

void c()
{
  printf(
"\t\t+---call c() function\n");
}

int b()
{
  printf(
"\t+--- call b() function\n");
  a();
  c();
  
return 0;
}


int main()
{
  printf(
" main() function()\n");
  b();
}

命令行里面輸入下面命令,沒加-c選項,gcc 會默認(rèn)進(jìn)行編譯并鏈接生成a.out:
$gcc -pg test.c

如果沒有編譯錯誤,gcc會在當(dāng)前目錄下生成一個a.out文件,當(dāng)然你也可以使用 –o 選項給生成的文件起一個別的名字,像 gcc –pg test.c –o test , 則gcc會生成一個名為test的可執(zhí)行文件,在命令行下輸入[linux /home/test]$./test , 就可以執(zhí)行該程序了,記住一定要加上 ./ 否則程序看上去可能是執(zhí)行,可是什么輸出都沒有。

 

2.執(zhí)行你的應(yīng)用程序使之生成供gprof 分析的數(shù)據(jù)。  命令行里面輸入:

[linux /home/test]$a.out
main() function()
+--- call b() function
+---call a() function
+---call c() function

你會在當(dāng)前目錄下看到一個gmon.out 文件, 這個文件就是供gprof 分析使用的。

 

3.使用gprof 程序分析你的應(yīng)用程序生成的數(shù)據(jù)。
命令行里面輸入:

 

$ gprof -b a.out gmon.out | less

由于gprof輸出的信息比較多,這里使用了 less 命令,該命令可以讓我們通過上下方向鍵查看gprof產(chǎn)生的輸出,| 表示gprof -b a.out gmon.out 的輸出作為 less的輸入。下面是我從gprof輸出中摘抄出的與我們有關(guān)的一些詳細(xì)信息。

%     cumulative    self              self     total
time   seconds     seconds    calls  Ts
/call  Ts/call  name
0.00      0.00     0.00        1     0.00     0.00  a
0.00      0.00     0.00        1     0.00     0.00  b
0.00      0.00     0.00        1     0.00     0.00  c

Call graph

granularity: each sample hit covers 
4 byte(s) no time propagated

index 
% time    self  children    called     name
0.00    0.00       1/1           b [2]
[
1]      0.0    0.00    0.00       1         a [1]
-----------------------------------------------
0.00    0.00       1/1           main [10]
[
2]      0.0    0.00    0.00       1         b [2]
0.00    0.00       1/1           a [1]
0.00    0.00       1/1           c [3]
-----------------------------------------------
0.00    0.00       1/1           b [2]
[
3]      0.0    0.00    0.00       1         c [3]

從上面的輸出我們能明顯的看出來,main 調(diào)用了 b 函數(shù), 而b 函數(shù)分別調(diào)用了a 和 c 函數(shù)。由于我們的函數(shù)只是簡單的輸出了一個字串,故每個函數(shù)的消耗時間都是0 秒。

 


常用的Gprof 命令選項解釋:

-b不再輸出統(tǒng)計圖表中每個字段的詳細(xì)描述。

-p 只輸出函數(shù)的調(diào)用圖(Call graph 的那部分信息)。

-q 只輸出函數(shù)的時間消耗列表。

-E Name不再輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖,此標(biāo)志類似于 -e 標(biāo)志,但它在總時間和百分比時間的計算中排除了由函數(shù)Name 及其子函數(shù)所用的時間。

-e Name 不再輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖(除非它們有未被限制的其它父函數(shù))。可以給定多個 -e 標(biāo)志。一個 -e 標(biāo)志只能指定一個函數(shù)。

-F Name 輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖,它類似于 -f 標(biāo)志,但它在總時間和百分比時間計算中僅使用所打印的例程的時間。可以指定多個 -F 標(biāo)志。一個 -F 標(biāo)志只能指定一個函數(shù)。-F 標(biāo)志覆蓋 -E 標(biāo)志。

-f Name輸出函數(shù)Name 及其子函數(shù)的調(diào)用圖。可以指定多個 -f 標(biāo)志。一個 -f 標(biāo)志只能指定一個函數(shù)。

-z 顯示使用次數(shù)為零的例程(按照調(diào)用計數(shù)和累積時間計算)。

到這為止你可能對gprof 有了一個比較感性的認(rèn)識了,你可能會問如何用它去分析一個真正的Open Source 呢!下面就讓我們?nèi)ビ胓prof去分析一個Open Source,看看如何去在真實的環(huán)境中使用它。

使用Gprof 分析 Cflow開源項目
CFlow 是程序流程分析工具,該工具可以通過分析C源代碼,產(chǎn)生程序調(diào)用圖!有點跟Gprof差不多,不過CFlow是通過源代碼進(jìn)行的靜態(tài)分析并且 不能分析C++ 程序,你可以到http://www.gnu.org/software/cflow/去下載源代碼。

假設(shè)你已經(jīng)下載了該源代碼(cflow-1.1.tar.gz),并把它放置在/home目錄下,讓我們看看如何在這個應(yīng)用上使用gprof。

1. 使用 -pg 編譯和鏈接該應(yīng)用程序,請輸入下列命令。

 

[linux /home/]tar zxvf cflow-1.1.tar.gz
[linux /home/cflow-1.1/src]$./configure
[linux /home]$make CFLAGS=-pg LDFLAGS=-pg 

如果沒有出錯你會在/home/cflow-1.1/src 目錄下發(fā)行一個名為cflow的可執(zhí)行文件,這就是我們加入-pg編譯選項后編譯出來的可以產(chǎn)生供gprof提取信息的可執(zhí)行文件。記住一定要在編譯和鏈接的時候都使用-pg選項,否則可能不會產(chǎn)生gmon.out文件。對于cflow項目,CFLAGS=-pg 是設(shè)置它的編譯選項,LDFLAGS=-pg是設(shè)置它的鏈接選項。當(dāng)然你也可以直接修改它的Makefile來達(dá)到上述相同的目的,不過一定要記住編譯和鏈接都要使用-pg選項。

 

2. 運行cflow 程序使之生成gmon.out 文件供gprof使用。

 

[linux /home/cflow-1.1/src]$cflow parser.c

查看/home/cflow-1.1/src目錄下有沒有產(chǎn)生gmon.out文件,如果沒有請重復(fù)第一步,并確認(rèn)你已經(jīng)在編譯和鏈接程序的時候使用了-pg 選項。Cflow的使用請參考http://www.gnu.org/software/cflow/manual/cflow.html

 

3. 使用gprof分析程序
[linux /home/cflow-1.1/src]$gprof -b cflow gmon.out | less
恭喜你,不出意外你會在屏幕上看到gprof的輸出,函數(shù)消耗時間和函數(shù)調(diào)用圖,下面是我從我的輸出中摘抄出來的一小段。

 

%   cumulative   self              self     total time   seconds   seconds    calls  Ts/call  Ts/call  name 0.00      0.00     0.00   118262     0.00     0.00  include_symbol 0.00      0.00     0.00    92896     0.00     0.00  is_printable 0.00      0.00     0.00    28704     0.00     0.00  set_level_mark 0.00      0.00     0.00    28703     0.00     0.00  is_last 0.00      0.00     0.00    19615     0.00     0.00  auto_processor 0.00      0.00     0.00    15494     0.00     0.00  gnu_output_handler 0.00      0.00     0.00    12286     0.00     0.00  delete_parm_processor 0.00      0.00     0.00     7728     0.00     0.00  newline 0.00      0.00     0.00     7728     0.00     0.00  print_function_name 0.00      0.00     0.00     7728     0.00     0.00  print_level

。。。。。。 。。。。。。

Call graph

granularity: each sample hit covers 4 byte(s) no time propagated

index % time    self  children   called     name [1]      0.0    0.00    0.00     79+855  [1] 0.00    0.00    166     dcl [52] 0.00    0.00    163     parse_dcl [53] 0.00    0.00    150     dirdcl [56] 0.00    0.00    129     parse_declaration [63] 0.00    0.00     98     parse_variable_declaration [66] 0.00    0.00     63     maybe_parm_list [69] 0.00    0.00     63    parse_function_declaration [70] 0.00    0.00     39    func_body [74]

。。。。。。 。。。。。。

 


通過分析%time你就知道了那個函數(shù)消耗的時間最多,你可以根據(jù)這個輸出信息做有目的的優(yōu)化,不過cflow執(zhí)行的速度是在是太快了,以至%time都是0 (消耗時間是以秒為單位進(jìn)行統(tǒng)計的)。

 

生成圖形化的函數(shù)調(diào)用圖

1.Graphviz 工具
看到這里你也可能覺得上面的函數(shù)調(diào)用圖實在是不方便察看,也看不出來一個程序調(diào)用的整體框架。沒有關(guān)系,我再介紹一個有用的工具給你,使用 Graphviz,Graphviz or Graph Visualization 是由 AT&T 開發(fā)的一個開源的圖形可視化工具。它提供了多種畫圖能力,但是我們重點關(guān)注的是它使用 Dot 語言直連圖的能力。在這里,將簡單介紹如何使用 Dot 來創(chuàng)建一個圖形,并展示如何將分析數(shù)據(jù)轉(zhuǎn)換成 Graphviz 可以使用的規(guī)范, Dot 使用的圖形規(guī)范。

使用 Dot 語言,你可以指定三種對象:圖、節(jié)點和邊。為了讓你理解這些對象的含義,我將構(gòu)建一個例子來展示這些元素的用法。


下圖給出了一個簡單的定向圖(directed graph),其中包含 3 個節(jié)點。第一行聲明這個圖為 G,并且聲明了該圖的類型(digraph)。接下來的三行代碼用于創(chuàng)建該圖的節(jié)點,這些節(jié)點分別名為 node1、node2 和 node3。節(jié)點是在它們的名字出現(xiàn)在圖規(guī)范中時創(chuàng)建的。邊是在在兩個節(jié)點使用邊操作(->)連接在一起時創(chuàng)建的,如第 6 行到第 8 行所示。我還對邊使用了一個可選的屬性 label,用它來表示邊在圖中的名稱。最后,在第 9 行完成對該圖規(guī)范的定義。
使用 Dot 符號表示的示例圖(test.dot)

 

digraph G {
    node1;
    node2;
    node3;

    node1 
-> node2 [label="edge_1_2"];
    node1 
-> node3 [label="edge_1_3"];
    node2 
-> node3 [label="edge_2_3"];
 }

要將這個 .dot 文件轉(zhuǎn)換成一個圖形映像,則需要使用 Dot 工具,這個工具是在 Graphviz 包中提供的。清單 6 介紹了這種轉(zhuǎn)換。
清單 6. 使用 Dot 來創(chuàng)建 JPG 映像
[linux /home]$ dot -Tjpg test.dot -o test.jpg
在這段代碼中,我告訴 Dot 使用 test.dot 圖形規(guī)范,并生成一個 JPG 圖像,將其保存在文件 test.jpg 中。所生成的圖像如圖1所示。在此處,我使用了 JPG 格式,但是 Dot 工具也可以支持其他格式,其中包括 GIF、PNG 和 postscript等等。

 


Dot創(chuàng)建的實例圖

Dot 語言還可以支持其他一些選項,包括外形、顏色和很多屬性。有興趣可以查看graphviz相關(guān)文檔。
2.從gprof的輸出中提取調(diào)用圖信息,產(chǎn)生可供Graphviz使用的dot文件。
這樣的腳本有人已經(jīng)實現(xiàn)了,我們只要下載一個現(xiàn)成的就可以了,首先從http://www.ioplex.com/~miallen/ 網(wǎng)站下載一個mkgraph腳本。解壓該腳本到包含gmon.out文件的目錄下。使用mkgraph0.sh產(chǎn)生調(diào)用的jpg圖像文件。例如:使用上面的例子,生成cflow的調(diào)用圖。
[linux /home/cflow-1.1/src]$ mkgraph0.sh cflow gmon.out
部分調(diào)用圖如下,有了這個圖是不是對程序整體框架有了個清晰地了解,如果你對生成的調(diào)用圖效果不滿意,你還可以通過修改mkgraph0腳本使之產(chǎn)生合適的dot文件即可:

總結(jié):
使用gprof , Graphviz , mkgraph 生成函數(shù)調(diào)用圖
1. 使用 -pg 編譯和鏈接你的應(yīng)用程序。
2. 執(zhí)行你的應(yīng)用程序使之生成供gprof 分析的數(shù)據(jù)。
3. 使用mkgraph腳本生成圖形化的函數(shù)調(diào)用圖。

相關(guān)資料:
文檔:用 Graphviz 可視化函數(shù)調(diào)用
文檔:Speed your code with the GNU profiler
文檔:gropf 幫助文件
Mkgraph 腳本:http://www.ioplex.com/~miallen/
Graphviz 工具:http://www.graphviz.org
Cflow         :http://www.gnu.org/software/cflow/
(責(zé)任編輯:城塵 68476636-8003)

原文地址:點擊打開鏈接http://os.51cto.com/art/200703/41426_2.htm








posted @ 2012-10-21 12:36 jackdong 閱讀(530) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/6303282

在上一節(jié)中我們講的是一個常用的并行化編程方法(for的并行化),其實它只是并行化編程的一個特例,只是它的地位較高,或者說它比其它并行化更重要。在本節(jié)中我們將討論一般的并行區(qū)域編程。

并行區(qū)域的編譯指導(dǎo)語句一般格式

    一般格式:#pragma omp parallel [clause[clause]…]{…}

    其中{…}中為每個線程都執(zhí)行的部分,在parallel后面可以跟隨一些指導(dǎo)子句,例如:threadprivate、copyin等,本節(jié)中將以一些實例來依次講解這些語句的作用。

    時刻記住,主線程就是0號線程,這個與for不同,另外private、firstprivate、lastprivate是for并行的東西最好不要拿來比較,盡管我在本文里比較了,但是我還是感覺有些頭痛啊。

例子實例

例1 不帶指導(dǎo)子句的并行程序

      #pragma omp parallel指示它下面的一對大括號內(nèi)的程序復(fù)制執(zhí)行threads個數(shù)次。默默人情況下,所有并行區(qū)域中的變量是共享的,所以一定要謹(jǐn)防數(shù)據(jù)競爭的發(fā)生。


 

#include 
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    #pragma omp parallel 
    
for (int i = 0; i < 2; i++
    

        printf(
"Hello World! i = %d, Thread Num = %d/n", i, omp_get_thread_num()); 
    }
 
    
return 0
}

 

image

圖1、例1的執(zhí)行結(jié)果

例1的執(zhí)行結(jié)果可以看出四個線程分別執(zhí)行了一遍#pragma omp parallel下面的語句,想想一下如果使用#pragma omp parallel for會是什么樣的結(jié)果。

例2 使用threadprivate子句

     此命令表示所有并行線程使用指定變量為各自私有的,能被定義為各線程私有變量的變量只能是靜態(tài)變量和全局變量。看下面的程序,希望你能發(fā)現(xiàn),其實#pragma omp threadprivate()是可以單獨使用的。

    說明一下:被定義為threadprivate的變量對于每個線程永遠(yuǎn)是活的,你在任何時候再次重新啟動各線程時,前面并行時最后得到的變量值仍然保留他的值,如果你用private代替threadprivate,那么你重新啟動各線程時,變量的值仍然為0。如果你不初始化要聲明為private的變量,那么在串行程序中,你就不能再沒有任何賦值的情況下使用它,否則會引起異常的(VS2010)。而且private不能單獨像threadprivate那樣定義某個變量。

    如果你使用另外#pragma omp threadprivate(var),那么var必須是靜態(tài)變量或者全局變量,如過你在并行開始之前并沒有初始化賦值,那么每個線程中默認(rèn)var的值為0.如果你賦了初值,那么每個線程中var的初值都是你賦的初始值。其中主線程就是0號線程。如果你使用了#pragma omp private(var),那么var并不會賦初值,即使你在并行之前賦了初值。想想原先#pragma omp parallel for 的firstprivate就知道了,呵呵。在#pragma omp parallel中可以使用lastprivate,但是不能使用lastprivate,使用firstprivate(var)后,串行部分的var并不是并行時0號線程的var值,它仍未你原先賦的初值。是不是很繞啊?呵呵,你可以這樣理解,使用firstprivate和private的并行都不是純真的聯(lián)合主線程的編號。這樣就混不了了。

 

#include 
#include 
"omp.h" 
int sum = 0
#pragma omp threadprivate(sum) 
int main(int argc, char* argv[]) 

    #pragma omp parallel 
    

        sum 
+= omp_get_thread_num(); 
        printf(
"parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num()); 
    }
 
    printf(
"/nserial sum = %d; thread num = %d/n/n", sum, omp_get_thread_num()); 
    #pragma omp parallel 
    printf(
"parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num()); 
    
return 0
}



 

image

圖2、例2執(zhí)行結(jié)果

threadprivate指定了sum這個變量屬于每個線程,每個線程都有自己的sum變量,各個線程結(jié)束后他們的sum變量并沒有注銷,在此啊執(zhí)行時,他們各自的sum值還保持原值。

例3 使用copyin

指定主線程的值拷貝到各線程中去,下面的例子中,sum是每個線程獨有的,并且初始值都是0,main中第一行代碼將0號線程的sum值賦為100,其它線程的sum值并沒有變。

 

#include <stdio.h>
#include 
"omp.h" 
int sum; 
#pragma omp threadprivate(sum) 
int main(int argc, char* argv[]) 

    sum 
= 100
    #pragma omp parallel copyin(sum) 
    

        sum 
+= omp_get_thread_num(); 
        printf(
"parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num()); 
    }
 
    printf(
"/nserial sum = %d; thread num = %d/n/n", sum, omp_get_thread_num()); 
    #pragma omp parallel 
    printf(
"parallel sum = %d; thread num = %d/n", sum, omp_get_thread_num()); 
    
return 0
}



 

image

圖3、例3的執(zhí)行結(jié)果

image

圖4、例3中將copyin(sum)刪除后的執(zhí)行結(jié)果

通過以上圖3、4可以看出copyin的用處是初始化各個線程中自己私有的sum變量。實際上定義sum為全局量時的初始值就是原sum值(如果不使用copyin的話)。

我想了想threadprivate和private以及firstprivate的區(qū)別。寫出來大家討論下。

1、threadprivate,限制變量為每個線程私有。被限制的變量必須具有全局特性,他的生命周期是整個程序。

2、private,可以限制變量為每個線程私有,但是他的生命周期是一次啟動并行計算。

3、firstprivate,可以將穿行程序中的初值帶進(jìn)每個線程,變量為每個線程私有。生命周期與private相同。

4、還有個lastprivate的問題,他并不能在區(qū)域并行中使用。

大家實驗把。。。

posted @ 2012-10-21 11:55 jackdong 閱讀(388) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/6303100

   openMP并不是只能對循環(huán)來并行的,循環(huán)并行化單獨拿出來說是因為它在科學(xué)計算中非常有用,比如向量、矩陣的計算。所以我單獨拿出這一部分給大家講講。這里主要講解的是for循環(huán)。

編譯指導(dǎo)語句:

    一般格式:

    #pragma omp parallel for [clause[clause…]]

    for(index = first; qualification; index_expr)

    {…}

    第一句中[]的部分是可選的,由自己的程序并行特點而定。大家先不要把精力放到這里面。后面的文章中會繼續(xù)講解的。

并行化for的編寫規(guī)則

    1、index的值必須是整數(shù),一個簡單的for形式:for(int i = start; i < end; i++){…} 。

    2、start和end可以是任意的數(shù)值表達(dá)式,但是它在并行化的執(zhí)行過程中值不能改變,也就是說在for并行化執(zhí)行之前,編譯器必須事先知道你的程序執(zhí)行多少次,因為編譯器要把這些計算分配到不同的線程中執(zhí)行。

    3、循環(huán)語句只能是單入口但出口的。這里只要你避免使用跳轉(zhuǎn)語句就行了。具體說就是不能使用goto、break、return。但是可以使用continue,因為它并不會減少循環(huán)次數(shù)。另外exit語句也是可以用的,因為它的能力太大,他一來,程序就結(jié)束了。

例子講解

例1、for循環(huán)并行:

#include 
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    
int i; 
    #pragma omp parallel 
for 
    
for (i = 0; i < 12; i++
    
{        printf("i = %d  %d/n", i, omp_get_thread_num());    } 
    
return 0
}

 

例1的執(zhí)行結(jié)果如圖1所示:

image

圖1、例1的執(zhí)行結(jié)果

從結(jié)果中可以看出 i 屬于{0,1,2}時由0號線程執(zhí)行,i 屬于{3,4,5}時由1號線程執(zhí)行,i 屬于{6,7,8}時由2號線程執(zhí)行,i 屬于{9,10,11}時由3號線程執(zhí)行。omp_get_thread_num()這個函數(shù)通過執(zhí)行結(jié)果大家也知道了,他返回每個線程的編號。

并行編譯子句

    openMP中有多種并行化子句,這些子句都是為控制循環(huán)并行化編譯而設(shè)定的,這里我們主要關(guān)注數(shù)據(jù)作用域子句,這里的數(shù)據(jù)作用域是指各個線程是否對某一變量有權(quán)訪問。shared子句用來標(biāo)記變量在各個線程之間是共享的,private子句標(biāo)記變量在各個線程之間是私有的,實際上它會在在每個線程中保存一個副本。默認(rèn)情況下,并行執(zhí)行的變量是共享的。至于其它編譯子句將在后面的文章中介紹。

用實例講解數(shù)據(jù)作用域子句

實際上我很難想到一個綜合的例子來講解這種子句的限制異同,所以我寫了幾個例子。

例2、private

#include
#include "omp.h"
int main(int argc, char* argv[])
{
    float x = 4.3f;
    int i;
    #pragma omp parallel for private(x)
    for (i = 0; i < 12; i++)
    {
        x = 0;
        printf("parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
    }
    printf("/nserial   x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());
    return 0;
}

image

圖2、例2執(zhí)行結(jié)果

例3 firstprivate(var):指定var在每個線程中都有一個副本,并且var的初始值在并行執(zhí)行開始之前定義,每個并行線程的var的副本初值就是串行時定義的初始值。程序結(jié)束后串行程序中的var值并不會改變。

#include 
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    
float x = 4.3f
    
int i; 
    #pragma omp parallel 
for firstprivate(x) 
    
for (i = 0; i < 12; i++
    

        x 
+= 1.0f
        printf(
"parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());        
    }
 
    printf(
"/nserial   x = %.1f, thread nummber:%d/n", x, omp_get_thread_num()); 
    
return 0
}

 

 

image

圖3、例3的執(zhí)行結(jié)果

例4 lastprivate(var):指定最后多線程執(zhí)行完后原串行循環(huán)最后一次var的值帶到主線程(串行部分)

#include 
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    
float x = 4.3f
    
int i; 
    #pragma omp parallel 
for lastprivate(x) 
    
for (i = 0; i < 12; i++
    
{        
        x 
= 0.0f
        printf(
"parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());        
    }
 
    printf(
"/nserial   x = %.1f, thread nummber:%d/n", x, omp_get_thread_num()); 
    
return 0
}

image

圖4、例4的執(zhí)行結(jié)果

例5 firstprivate與lastprivate聯(lián)用,很奇怪openMP很多情況下是不允許某個變量被指定兩次規(guī)則的,他倆卻可以,呵呵,而且配合效果還不錯。

#include 
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    
float x = 4.3f
    
int i; 
    #pragma omp parallel 
for firstprivate(x) lastprivate(x) 
    
for (i = 0; i < 12; i++
    
{        
        x 
+= (float)omp_get_thread_num(); 
        printf(
"parallel x = %.1f, thread nummber:%d/n", x, omp_get_thread_num());        
    }
 
    printf(
"/nserial   x = %.1f, thread nummber:%d/n", x, omp_get_thread_num()); 
    
return 0
}

image

圖5、例5的執(zhí)行結(jié)果

    從上面的例2、3的程序中可以看出例2中每個線程中x都是私有的,它屬于每個線程,在主線程的定義并不能帶入到各個線程中,使用firstprivate后,x在主線程的初始值可以帶到各個線程中,在圖3可以看出每個線程x的輸出結(jié)果實際是相同的,但是在并行執(zhí)行結(jié)束后,主線程中的x值仍然為4.3。從例4的執(zhí)行結(jié)果可以看出最后x的值帶出到了主線程中,這個x值到底是哪個線程中的哪?答案是最后一句x賦值后的值,哪個線程執(zhí)行完的最晚就是哪個x的值。例5顯示firstprivate與lastprivate聯(lián)合使用的執(zhí)行結(jié)果。

例6 reduction規(guī)約操作,

    執(zhí)行reduction的變量要特別注意,以reduction(+:sum)為例。

    第一種情況:sum為局部變量。這是你必須為sum在串行程序中賦初值,sum 被設(shè)置為每個線程私有,先各自執(zhí)行完算出各自的sum值,最后主線程會將 《線程數(shù)+1》個sum變量規(guī)約,比如你num_thread(4),在開始并行執(zhí)行之前你對規(guī)約變量賦初值為10,并行時假設(shè)每個線程算的的sum值為1,那么最終sum帶到串行程序中的變量值為14(串行的10+四個線程的1)。

    第二種情況:sum為全局變量。這是你不必為sum賦初始值,因為此時默認(rèn)串行的sum值為0,進(jìn)入每個線程的sum值也是0,規(guī)約時仍然是將《線程數(shù)+1》個sum值相加,因為你并沒有對全局的sum賦初值,所以最后規(guī)約的結(jié)果看著像是只有各線程的sum參加了規(guī)約操作。其實當(dāng)你將全局的sum賦初值時,你會發(fā)現(xiàn)最后規(guī)約的sum值又多加了全局變量sum的串行程序結(jié)果。

    重要提醒:不管你怎樣設(shè)計sum的串行聲明形式,只要他在被定義為規(guī)約變量,每次進(jìn)入并行線程的sum值都是0;

    也許你想把每個并行線程的sum值初始化成一個非0的值,然后再各自線程中在使用,那么我可以告訴你,別想了(至少我沒有做到)。因為我規(guī)約sum值,如果這個規(guī)約有意義你的每個線程應(yīng)該是各自獨立未回各自的sum的,那么這個初始值使用0就已經(jīng)非常好了,因為各自的sum計算如果結(jié)果一樣,你為何不直接用一句乘法哪(線程數(shù)*一個線程計算的sum值)。

#include 
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    
float x = 0.0f
    
int i; 
    
float sum = 0.0f
#pragma omp parallel 
for private(x) reduction(+:sum) 
    
for (i = 0; i < 12; i++
    
{        
        x 
= (float)omp_get_thread_num(); 
        sum 
+= x; 
        printf(
"parallel sum = %.1f, thread nummber:%d/n", sum, omp_get_thread_num());        
    }
 
    printf(
"/nserial   sum = %.1f, thread nummber:%d/n", sum, omp_get_thread_num()); 
    
return 0
}

image

圖6、例6執(zhí)行結(jié)果

    在例6中我使用了reduction(+:sum),這表示每個線程對sum這個共享變量執(zhí)行加操作時其它任何線程不能對它進(jìn)行加操作,實際上我們這樣理解是有偏差的,真正的機(jī)理在執(zhí)行結(jié)果中不難看出,實際每個線程都拷貝了一個sum的副本,先在自己執(zhí)行時加完sum,等所有線程都執(zhí)行結(jié)束后,主線程再將每個線程的sum副本的值加起來返回給主線程中sum。

小結(jié)

    本節(jié)主要講述了for語句的并行化。現(xiàn)在為止大家應(yīng)該可以熟練使用for并行化了。文章中可能還有些不全面的地方,熱切期望各位讀者能給出批評和指正,期待中……


posted @ 2012-10-21 11:54 jackdong 閱讀(625) | 評論 (0)編輯 收藏

http://blog.csdn.net/bendanban/article/details/6302857

 在學(xué)習(xí)并行編程之前,你應(yīng)該知道進(jìn)程、線程、主線程、從線程等基本概念。進(jìn)程是一個大型應(yīng)用程序的基本單位,在任務(wù)管理器里進(jìn)程都有一個名稱,后面跟隨的是與他有關(guān)的資源。線程是程序執(zhí)行的基本單位,它必須從屬與一個進(jìn)程,一個進(jìn)程可以有多個線程,同一個進(jìn)程的線程可以共享進(jìn)程的資源,例如他們可以引用同一個變量的值。一個進(jìn)程一般會與一個.EXE文件關(guān)聯(lián),所以我把程序和進(jìn)程不加區(qū)分。一個程序中有多個線程時,它必然會有一個主線程,主線程執(zhí)行完后,其它從線程也應(yīng)該結(jié)束執(zhí)行。

    并行化編程一般可以理解為多個線程的創(chuàng)建和并行化編程,并行化編程的東西很多,但他們都會有兩個必須的規(guī)定:1、程序執(zhí)行模型。2、存儲模型。

    程序執(zhí)行模型,他規(guī)定了并行化線程的執(zhí)行方式,規(guī)則,或者說邏輯結(jié)構(gòu)。openMP的執(zhí)行采用了Fork-Join模型。主線程在執(zhí)行過程中遇到要并行處理的部分,根據(jù)openMP的編譯指導(dǎo)語句來創(chuàng)建,執(zhí)行多個線程,創(chuàng)建的線程個數(shù)一般與計算機(jī)的核心數(shù)成正比,可以通過添加一個環(huán)境變量(OMP_NUM_THREADS)來規(guī)定創(chuàng)建線程的個數(shù),注意環(huán)境變量添加后要注銷或者重啟系統(tǒng)才會生效。

image

圖1 omp程序執(zhí)行模型

    存儲模型,omp針對的是一個計算機(jī)或者分布式計算機(jī)的并行,在一臺計算機(jī)上他采用共享存儲的方式,多個線程共享一塊進(jìn)程的內(nèi)存資源。

    下面先寫個程序例子,能讓大家有個初步認(rèn)識。這個程序是在VS2008中編譯的,項目類型為Win32ConsoleApplication。

例1、并行HelloWorld程序:

#include <stdio.h>
#include 
"omp.h" 
int main(int argc, char* argv[]) 

    printf(
"Hello World! Serial Begin./n"); 
    #pragma omp parallel    
//開始并行執(zhí)行 
    {        printf("Hello World! Parallel/n");    } 
    printf(
"Hello World! Serial again./n"); 
    
return 0
}

 

此程序編譯之前,還需要你對你的編譯器項目屬性設(shè)置一下。這里我們以VS2008為例,首先設(shè)置項目支持openMP。右擊項目->屬性->C/C++->語言->openMP支持修改為是,如圖2所示,然后代碼生成修改為多線程調(diào)試,如圖3所示。執(zhí)行結(jié)果如圖4所示。

image

圖2、添加openMP支持

image

圖3、多線程調(diào)試支持

image

圖4、執(zhí)行結(jié)果

以上程序我并沒有設(shè)置環(huán)境變量,因為我的計算機(jī)是雙核的,所以他的并行部分輸出了兩行Hello World! Parallel,這說明他有兩個線程執(zhí)行并行部分,每個線程完全執(zhí)行了相同的一段程序。我們在設(shè)置一下環(huán)境變量后在執(zhí)行一下。順便說明一下怎樣設(shè)置環(huán)境變量。

計算機(jī)右擊-》屬性-》高級-》環(huán)境變量-》系統(tǒng)變量-》新建。。。如圖5所示。

image

圖5、Win7環(huán)境下設(shè)置環(huán)境變量

設(shè)置完環(huán)境后,注銷或重啟系統(tǒng)后,再次執(zhí)行例1的程序后得到的結(jié)果中Hello World! Parallel 將被執(zhí)行四遍。因為你已經(jīng)設(shè)置了四個線程了。

到現(xiàn)在為止,大家可以模仿著例1寫幾個小程序了,可是還有一句話大家可能還不大明白吧,#pragma omp parallel這句話標(biāo)記{}中的程序?qū)⒃贠MP_NUM_THREADS個線程中執(zhí)行。

在下面的幾篇文章中我將繼續(xù)講解openMP編程的基礎(chǔ)知識。歡迎繼續(xù)關(guān)注。


posted @ 2012-10-21 11:49 jackdong 閱讀(393) | 評論 (0)編輯 收藏

僅列出標(biāo)題
共10頁: First 2 3 4 5 6 7 8 9 10 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久国产精品99精品国产| 亚洲视频在线一区观看| 亚洲少妇最新在线视频| 欧美日韩一区二区三| 国产精品99久久久久久久vr | 亚洲男女自偷自拍| 激情久久久久久久| 亚洲精品国产品国语在线app | 亚洲欧美一级二级三级| 久久综合色一综合色88| 欧美成va人片在线观看| 亚洲欧美日韩国产一区| 蜜桃av综合| 午夜精品电影| 欧美激情免费在线| 久久久久九九九| 欧美日韩综合久久| 亚洲大胆在线| 国产亚洲精品久久久| 最新高清无码专区| 伊人成综合网伊人222| 亚洲视频999| 日韩午夜精品| 蜜臀久久99精品久久久画质超高清| 先锋亚洲精品| 欧美小视频在线| 亚洲精品久久久久久下一站| 狠狠爱综合网| 欧美在线视屏| 欧美在线免费播放| 国产精品wwwwww| 亚洲狼人综合| 91久久久精品| 久久成人国产精品| 欧美一区二区三区在线视频| 欧美日韩另类综合| 91久久久一线二线三线品牌| 激情久久综合| 久久久99精品免费观看不卡| 久久国产精品一区二区三区四区| 欧美午夜精品久久久久久久| 亚洲人成在线观看网站高清| 亚洲日韩成人| 欧美黑人多人双交| 最新国产乱人伦偷精品免费网站| 亚洲国产视频a| 女女同性精品视频| 欧美高清视频免费观看| 1769国产精品| 欧美成人嫩草网站| 亚洲欧洲久久| 亚洲色图制服丝袜| 欧美午夜免费影院| 亚洲无线观看| 欧美在线首页| 韩日在线一区| 久久在线免费观看| 亚洲成人资源| 日韩一级二级三级| 欧美系列精品| 性欧美暴力猛交69hd| 久久久久久久国产| 亚洲第一网站| 欧美韩日视频| 亚洲一二三四久久| 久久久综合免费视频| 在线日韩中文| 欧美日韩精品一区二区| 亚洲视频导航| 久久这里有精品15一区二区三区| 亚洲国产精品成人久久综合一区| 欧美激情欧美激情在线五月| 一区二区三区www| 欧美在线二区| 亚洲动漫精品| 欧美日韩综合久久| 久久精品免费| 亚洲精品在线观看免费| 欧美一级理论片| 在线视频国内自拍亚洲视频| 欧美激情视频一区二区三区在线播放| 一区二区福利| 麻豆av一区二区三区| 一区二区三区偷拍| 国产一区二区三区最好精华液| 久久亚洲免费| 在线视频欧美精品| 免费成人av在线看| 亚洲午夜免费视频| 黄色综合网站| 国产精品ⅴa在线观看h| 久久久久9999亚洲精品| 亚洲精品欧美日韩| 久久在线免费| 亚洲一区二区免费在线| 精品成人a区在线观看| 欧美日韩一卡二卡| 久久深夜福利| 亚洲欧美综合国产精品一区| 亚洲激情视频网站| 久久午夜激情| 亚洲视频在线播放| 亚洲国产综合在线看不卡| 国产精品欧美激情| 欧美v日韩v国产v| 亚洲电影网站| 亚洲一二三区精品| 亚洲级视频在线观看免费1级| 欧美视频精品在线| 欧美不卡一区| 久久精品国产v日韩v亚洲| 亚洲午夜激情在线| 亚洲国产精品一区二区第四页av | 欧美大片在线观看一区| 久久青青草原一区二区| 亚洲一区二区三区中文字幕 | 亚洲一级在线观看| 亚洲激情午夜| 欧美1区3d| 老牛嫩草一区二区三区日本| 销魂美女一区二区三区视频在线| 亚洲美女福利视频网站| 亚洲激情成人在线| 在线观看亚洲视频啊啊啊啊| 国产女人18毛片水18精品| 国产精品国产成人国产三级| 欧美日韩一区二区三区免费看| 欧美激情一区二区三区成人| 美日韩丰满少妇在线观看| 久久亚洲一区| 亚洲欧美在线看| 亚洲一区二区免费| 亚洲一品av免费观看| 亚洲桃花岛网站| 在线综合亚洲欧美在线视频| 亚洲第一主播视频| 亚洲国产老妈| 亚洲经典自拍| 欧美激情女人20p| 亚洲激情不卡| 亚洲精品你懂的| 亚洲国产日韩欧美一区二区三区| 欧美.com| 91久久国产综合久久蜜月精品 | 一区免费观看视频| 韩日欧美一区二区三区| 在线不卡中文字幕播放| 亚洲国产美女久久久久| 亚洲日本中文| 亚洲视频中文| 午夜视频在线观看一区二区| 欧美一区二区三区四区夜夜大片| 久久精品二区亚洲w码| 久久综合中文字幕| 亚洲电影av| 一区二区三区久久网| 亚洲一区二区三区在线看| 欧美亚洲日本网站| 久久综合一区| 欧美日韩国产限制| 国产精品一区二区视频| 狠狠色狠狠色综合日日tαg| 亚洲欧洲日韩综合二区| 亚洲午夜激情网站| 性亚洲最疯狂xxxx高清| 久久久精品2019中文字幕神马| 欧美xxx在线观看| 日韩午夜电影在线观看| 欧美一级视频免费在线观看| 久久综合久久久久88| 欧美日韩亚洲另类| 国产一区二区三区四区| 性久久久久久久| 欧美国产激情| 麻豆精品视频在线观看| 亚洲精品1区| 亚洲在线成人| 久久久久久久999| 欧美精品手机在线| 欧美色综合天天久久综合精品| 国产欧美一区二区精品忘忧草| 精品动漫3d一区二区三区免费版| 亚洲精品视频免费| 欧美一区2区三区4区公司二百| 免费在线观看日韩欧美| 中文一区字幕| 欧美成人情趣视频| 国产女精品视频网站免费| 99re热这里只有精品视频| 久久久7777| 99国产一区二区三精品乱码| 欧美在线免费视屏| 欧美日韩精品二区第二页| 国语精品一区| 中国成人黄色视屏| 六月丁香综合| 亚洲欧美综合v| 欧美日韩在线播放三区四区| 在线看片第一页欧美| 亚洲欧美综合网|