<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Del&#039;Arco &#187; OpenMP</title>
	<atom:link href="http://blog.delarco.com.br/category/programacao/openmp-programacao/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.delarco.com.br</link>
	<description>The Pixel Company</description>
	<lastBuildDate>Mon, 07 Jun 2010 18:35:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>OpenMP: Repetição Distribuída – Parte 2</title>
		<link>http://blog.delarco.com.br/openmp-repeticao-distribuida-%e2%80%93-parte-2/</link>
		<comments>http://blog.delarco.com.br/openmp-repeticao-distribuida-%e2%80%93-parte-2/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 01:23:57 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[codeblocks]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[multicore]]></category>
		<category><![CDATA[múltiplos núcleos]]></category>
		<category><![CDATA[openmp]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=185</guid>
		<description><![CDATA[Nesse post não vou explicar as várias outras funcionalidades que a API oferece em relação aos loops. Aqui vou fazer uma pausa para testar o que foi explicado até agora. De que adianta a teoria sem um teste prático do que tá rolando?
Para testar um loop distribuído, resolvi criar uma função que calcula a multiplicação [...]]]></description>
			<content:encoded><![CDATA[<p>Nesse post não vou explicar as várias outras funcionalidades que a API oferece em relação aos loops. Aqui vou fazer uma pausa para testar o que foi explicado até agora. De que adianta a teoria sem um teste prático do que tá rolando?</p>
<p>Para testar um loop distribuído, resolvi criar uma função que calcula a multiplicação entre duas matrizes, colocando o resultado em uma terceira matriz (MC = MA * MB):</p>
<pre class="brush: cpp;">
const int MATRIX_SIZE = 1000;

int MA[MATRIX_SIZE][MATRIX_SIZE];
int MB[MATRIX_SIZE][MATRIX_SIZE];
int MC[MATRIX_SIZE][MATRIX_SIZE];

void multi()
{
    int soma;

    //percorre cada linha de MA
    for(int j = 0; j &lt; MATRIX_SIZE; j++)
    {
        //percorre cada coluna de MB
        for(int i = 0; i &lt; MATRIX_SIZE; i++, soma = 0)
        {
            //calcula
            for(int k = 0; k &lt; MATRIX_SIZE; k++)
            {
                soma += MA[j][k] * MB[k][i];
            }

            //coloca resoltado na matriz MC
            MC[j][i] = soma;
        }
    }
}

int main(int ac, char **av)
{
    multi();
    return 0;
}
</pre>
<p>Como o teste consiste em melhorar o desempenho do cálculo, não me dei ao trabalho de iniciar os elementos das matrizes e nem de verificar se o resultado está correto.</p>
<p>Executando o código anterior, o Code::Blocks retornou a mensagem:</p>
<p><strong>Process returned 0 (0&#215;0)   execution time : <span style="color: #ff0000">23.509 s</span><br />
Press any key to continue.</strong></p>
<p>Lembrando que executei a compilação debug sem nenhum tipo de otimização. Com certeza a release seria muito mais rápida.</p>
<p>Quem lembra das aulas de matemática do colegial, sabe que o cálculo de cada elemento resultante (MC) independe do cálculo de elementos anteriores. O laço <strong>for </strong>está de acordo com as restrições impostas pela API, então, pq não dividir a tarefa em várias threads?</p>
<pre class="brush: cpp;">
const int MATRIX_SIZE = 1000;

int MA[MATRIX_SIZE][MATRIX_SIZE];
int MB[MATRIX_SIZE][MATRIX_SIZE];
int MC[MATRIX_SIZE][MATRIX_SIZE];

void multi()
{
    //percorre cada linha de MA
    #pragma omp parallel for
    for(int j = 0; j &lt; MATRIX_SIZE; j++)
    {
        //percorre cada coluna de MB
        for(int i = 0; i &lt; MATRIX_SIZE; i++)
        {
            int soma = 0;

            //calcula
            for(int k = 0; k &lt; MATRIX_SIZE; k++)
            {
                soma += MA[j][k] * MB[k][i];
            }

            //coloca resoltado na matriz MC
            MC[j][i] = soma;
        }
    }
}

int main(int ac, char **av)
{
    multi();
    return 0;
}
</pre>
<p>Repare que, além do <em><strong>#pragma omp parallel for</strong></em> adicionado antes do primeiro loop, outras mudanças foram feitas para adaptar o código:</p>
<ul>
<li>A variável <strong>soma </strong>foi removida do começo da função e declarada dentro do segundo <strong>for, </strong>para evitar que seja compartilhada entre as threads;</li>
<li>Não é mais necessário zerar a variável soma no corpo do segundo <strong>for</strong>;</li>
</ul>
<p>Executando o código modificado, obtive o seguinte resultado:</p>
<p><strong>Process returned 0 (0&#215;0)   execution time : <span style="color: #ff0000">7.129 s</span><br />
Press any key to continue.</strong></p>
<p>Isso corresponde a, praticamente, um terço do tempo necessário para calcular pelo método tradicional. Surpreso? Requisitando 20 threads para executar o loop, obtive um resultado melhor ainda:</p>
<p><strong>Process returned 0 (0&#215;0)   execution time : <span style="color: #ff0000">6.692 s</span><br />
Press any key to continue.</strong></p>
<p>Okay, a diferença não é gritante, mas num sistema onde o desempenho é um faor crítico, esses ms podem fazer toda a diferença.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/openmp-repeticao-distribuida-%e2%80%93-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenMP: Repetição Distribuída &#8211; Parte 1</title>
		<link>http://blog.delarco.com.br/openmp-repeticao-distribuida-parte-1/</link>
		<comments>http://blog.delarco.com.br/openmp-repeticao-distribuida-parte-1/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 00:42:15 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[codeblocks]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[multicore]]></category>
		<category><![CDATA[múltiplos núcleos]]></category>
		<category><![CDATA[openmp]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=168</guid>
		<description><![CDATA[No post Programação Multicore com OpenMP, mostrei como fazer a API funcionar no Code::Blocks, compilando um exemplo simples que executa um trecho de código em várias threads, ou seja, nada muito útil.
Agora que vc já conseguiu compilar o &#8220;Hello World&#8221; do primeiro post, vamos fazer bom uso do processamento distribuído nos nossos laços da repetição.
Primeiramente, [...]]]></description>
			<content:encoded><![CDATA[<p>No post <a href="http://blog.delarco.com.br/programacao-multicore-com-openmp/" target="_blank">Programação Multicore com OpenMP</a>, mostrei como fazer a API funcionar no Code::Blocks, compilando um exemplo simples que executa um trecho de código em várias threads, ou seja, nada muito útil.</p>
<p>Agora que vc já conseguiu compilar o &#8220;Hello World&#8221; do primeiro post, vamos fazer bom uso do processamento distribuído nos nossos laços da repetição.</p>
<p>Primeiramente, vc deve entender que, na programação com OpenMP, temos variáveis (parte da memória) compartilhadas e privates.</p>
<blockquote><p>Quê?!</p></blockquote>
<p>No exemplo abaixo, a variável <strong>a</strong> é visível para todas as threads que executarão a tarefa do bloco. Já a variável <strong>b</strong> possui uma cópia exclusiva em cada thread, ou seja, cada thread possui sua variável <strong>b</strong>.</p>
<pre class="brush: cpp;">

void some_function()
{
    int a = 0;

    #pragma omp parallel
    {
        int b = 1;
    }
}
</pre>
<blockquote><p>Okay, entendi&#8230; e daí?</p></blockquote>
<p>Por enquanto, leve em conta que saber disso pode evitar várias dores de cabeça.</p>
<h2>Usando OpenMP nos laços de repetição</h2>
<p>Para tal operação, definimos a seguinte linha antes do nosso <strong>for</strong>:</p>
<p><em><strong>#pragma omp parallel for</strong></em></p>
<p>Ficando assim:</p>
<pre class="brush: cpp;">
#pragma omp parallel for
for(int i = 0; i &lt; 10; i++)
{
    printf(&quot;iteration %d on thread %d\n&quot;, i, omp_get_thread_num());
}
</pre>
<p>O resultado é:<br />
<img class="aligncenter size-full wp-image-169" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_parallel_for_01.jpg" alt="omp_parallel_for_01" width="677" height="342" /></p>
<p>Nesse exemplo, as iterações do for serão divididas em várias threads (na minha execução, 3 threads). O número de threads corresponde ao número padrão ou o valor que vc definiu com <strong>omp_set_num_threads(num_threads)</strong>. Para não ter o trabalho de chamar a função em cada parte do código que vc deseja alterar o número de threads, a seguinte sintaxe é permitida:</p>
<p><em><strong>#pragma omp parallel for num_threads(NUM_THREADS)</strong></em></p>
<p>Onde <em><strong>NUM_THREADS</strong></em> corresponde ao número de threads que devem executar a tarefa.</p>
<p>Se o exemplo anterior for modificado para:</p>
<pre class="brush: cpp;">
#pragma omp parallel for num_threads(2)
for(int i = 0; i &lt; 10; i++)
{
    printf(&quot;iteration %d on thread %d\n&quot;, i, omp_get_thread_num());
}
</pre>
<p>Então o loop vai ser dividido em, no máximo, duas threads como mostra o resultado:</p>
<p><img class="aligncenter size-full wp-image-170" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_parallel_for_02.jpg" alt="omp_parallel_for_02" width="677" height="342" /></p>
<p>Como podemos notar, apenas as threads de ID 0 e 1 executam o for.</p>
<p>Repare que as iterações não são executadas em ordem, então leve em conta que se uma iteração depende de outra,  como na soma de médias num vetor de alunos, por exemplo (existe um jeito de fazer isso, vou explicar mais pra frente), vc terá problemas.</p>
<p>A API OpenMP impõe  as seguintes restrições no uso de loops paralelos:</p>
<ol>
<li>A variável que controla o loop (no caso anterior, <strong>i</strong>) deve ser do tipo <em>signed integer</em>;</li>
<li>A operação de comparação no corpo<strong> for</strong> deve ser do tipo <em>loop_variable &lt;,  &lt;=, &gt;, &gt;= integer_invariável</em>;</li>
<li>A terceira expressão do corpo <strong>for </strong>deve ser do tipo que incrementa (x++) ou decrementa (x- -);</li>
<li>Se a operação de comparação usar os operadores &lt; ou &lt;=, então a variável de controle deve ser incrementada a cada iteração. No caso contrário, se forem utilizados os operadores &gt; ou &gt;=, então a variável de controle deve ser decrementada a cada iteração;</li>
<li>O loop deve consistir em um único bloco de código, sem <em>jumps</em> (goto, por exemplo)<em> </em>para fora do loop. Como exceção, podemos usar <strong>exit()</strong> que finaliza a aplicação e não apenas a thread em questão. Caso vc utilize um <strong>break </strong>ou <strong>goto</strong>, esses devem levar a algum lugar DENTRO do loop e não fora. O mesmo vale para exceptions, que devem ser tratadas dentro do loop e não fora dele;</li>
</ol>
<p>Para deixar mais claro aquele conceito de memória compartilhada e private, temos o exemplo abaixo que não é válido, pois a variável <strong>temp </strong>é compartilhada por todas as threads, ou seja, enquanto a thread de ID 0 escreve um valor X e espera ler esse valor algumas instruções adiante, a thread de ID 1 escreve um valor Y no mesmo endereço de memória:</p>
<pre class="brush: cpp;">
int a[4] = {1, 2, 4, 8};
int temp;

#pragma omp parallel for
for(int i = 0; i &lt; 4; i++)
{
    temp = a[i];
}
</pre>
<p>Para um resultado correto, o ideal seria declarar a variável <strong>temp </strong>dentro do laço for:</p>
<pre class="brush: cpp;">
int a[4] = {1, 2, 4, 8};

#pragma omp parallel for
for(int i = 0; i &lt; 4; i++)
{
    int temp;
    temp = a[i];
}
</pre>
<h2>Reductions</h2>
<p>Nos permite compartilhar uma variável sem que sua integridade seja comprometida pela concorrência entre threads. Veja o exemplo:</p>
<pre class="brush: cpp;">
int notas[10] = {7, 4, 8, 3, 6, 9, 10, 1, 2, 5};
int soma = 0;

#pragma omp parallel for
for(int i = 0; i &lt; 10; i++)
{
    soma += notas[i];
}

printf(&quot;soma = %d\n&quot;, soma);
</pre>
<p>Não podemos garantir que a soma seja 55, pois todas as threads estão usando a mesma variável. Criar um lock? Não é necessário, pois a API nos permite fazer da seguinte forma:</p>
<pre class="brush: cpp;">
int notas[10] = {7, 4, 8, 3, 6, 9, 10, 1, 2, 5};
int soma = 0;

#pragma omp parallel for reduction(+:soma)
for(int i = 0; i &lt; 10; i++)
{
    soma += notas[i];
}

printf(&quot;soma = %d\n&quot;, soma);
</pre>
<p>Nos bastidores, o OpenMP cria uma variável private <strong>soma </strong>para cada thread e, ao final, soma todas e coloca o valor na variável compartilhada (global) <strong>soma</strong>. Então vc pode ter certeza que o valor de <strong>soma </strong>é o esperado.</p>
<p>As outras operações disponíveis são:</p>
<ul>
<li><strong>+ (adição)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>- (subtração)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>* (multiplicação)</strong>: a variável private inicia com o valor 1;</li>
<li><strong>&amp; (operador AND)</strong>: a variável private inicia com o valor ~0;</li>
<li><strong>| (operador OR)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>^ (operador OR exclusivo)</strong>: a variável private inicia com o valor 0;</li>
<li><strong>&amp;&amp; (operador condicional AND)</strong>: a variável private inicia com o valor 1;</li>
<li><strong>|| (operador condicional OR)</strong>: a variável private inicia com o valor 0;</li>
</ul>
<p>A segunda parte eu deixo para outro post <img src='http://blog.delarco.com.br/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/openmp-repeticao-distribuida-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programação Multicore com OpenMP</title>
		<link>http://blog.delarco.com.br/programacao-multicore-com-openmp/</link>
		<comments>http://blog.delarco.com.br/programacao-multicore-com-openmp/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 02:21:37 +0000</pubDate>
		<dc:creator>Leandro Del&#39;Arco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[programação]]></category>
		<category><![CDATA[codeblocks]]></category>
		<category><![CDATA[instalação]]></category>
		<category><![CDATA[multicore]]></category>
		<category><![CDATA[múltiplos núcleos]]></category>
		<category><![CDATA[openmp]]></category>

		<guid isPermaLink="false">http://blog.delarco.com.br/?p=111</guid>
		<description><![CDATA[
Hoje em dia é normal ouvir do vendedor &#8220;Esse computador é ótimo! Tem 4 GB de RAM e é um Core Duo!&#8220;. Apesar de, na maioria das vezes, a pessoa nem fazer idéia do que diabos é um Core Duo. Mas tudo bem, esse é o papel do vendedor, certo? É claro que qualquer entendido [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center"><img class="aligncenter size-full wp-image-113" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/mc_processor.jpg" alt="multicore_processor" width="312" height="233" /></p>
<p>Hoje em dia é normal ouvir do vendedor &#8220;<em>Esse computador é ótimo! Tem 4 GB de RAM e é um Core Duo!</em>&#8220;. Apesar de, na maioria das vezes, a pessoa nem fazer idéia do que diabos é um Core Duo. Mas tudo bem, esse é o papel do vendedor, certo? É claro que qualquer entendido sabe que isso não qualifica o produto como &#8220;<em>bom</em>&#8220;, longe disso, temos que levar em conta muitos outros detalhes que pessoas que não são da área não entendem.</p>
<p>Com a chegada dos processadores de múltiplos núcleos, o marketing direcionou-se à  esse fator e esqueceu de que memória cache e barramento contam MUITO no desempenho. A maioria das pessoas não entendem, por exemplo, que um processador de 2 núcleos de 2.0 GHz NÃO significa 4.0 GHz ou que um sistema operacional de 32 bits não aproveita as vantagens do hardware de 64 bits.</p>
<p>O que me deixa triste é ouvir esse tipo de  <span style="text-decoration: line-through;">enganação</span> picaretagem de amigos/conhecidos da faculdade ( <a href="http://www.fatecriopreto.edu.br/php/index.php?option=com_content&amp;view=category&amp;id=34:info&amp;Itemid=34&amp;layout=default" target="_blank">Tecnologia em Informática com Ênfase em Gestão de Negócios &#8211; FATEC Rio Preto</a>). By the way, não quero desmerecer a faculdade, pois devo muito à vários professores que tiveram a paciência de aguentar alunos como eu e o <a href="http://terramel.org" target="_blank">bomba</a>.</p>
<p>Antes de entrar no assunto principal, entenda que não adianta ter um processador com 487564764 núcleos se o software não sabe como utilizá-los, okay?</p>
<p>Como recentemente adquiri um Phenom X3 (é, 3 núcleos) resolvi descobrir como aproveitar todo esse poder. Com uma busca aqui e uma ali (no <a href="http://google.com" target="_blank">oráculo</a>), trago o que aprendi.</p>
<h2>OpenMP?</h2>
<p>O <a href="http://openmp.org/" target="_blank">OpenMP</a> (Open Multi-Processing) é uma API aberta para programação paralela. De acordo com o site oficial:</p>
<blockquote><p>A API OpenMP auxilia na programação multiplataforma, paralela e com memória compartilhada em C/C++ e Fortran em todas as arquiteturas, incluindo plataformas Unix e Windows NT. Constituída por um grupo de grandes empresas de hardware e software, o OpenMP é um modelo portável e escalável que oferece ao programador uma interface flexível para o desenvolvimento de aplicações paralelas visando desktop até supercomputadores.</p></blockquote>
<p>A tradução no olhômetro ficou um lixo, mas dá pra ter uma idéia do que se trata.</p>
<blockquote><p>Beleza, nunca ouvi falar. Vale a pena alocar recursos (tempo) para aprender?</p></blockquote>
<p>Saiba que essa API (pelo menos a especificação) existe desde 1997, sendo os membros permanentes do Architecture Review Board (ARB):</p>
<ul>
<li> AMD (David Leibs)</li>
<li> Cray (James Beyer)</li>
<li> Fujitsu (Matthijs van Waveren)</li>
<li> HP (Uriel Schafer)</li>
<li> IBM (Kelvin Li)</li>
<li> Intel (Sanjiv Shah)</li>
<li> NEC (Kazuhiro Kusano)</li>
<li> The Portland Group, Inc. (Michael Wolfe)</li>
<li> SGI (Lori Gilbert)</li>
<li> Sun Microsystems (Nawal Copty)</li>
<li> Microsoft (-)</li>
</ul>
<p>(<em><a href="http://openmp.org/wp/about-openmp/" target="_blank">Retirado do site oficial</a></em>)</p>
<p><strong>Convencido(a)?</strong></p>
<h2>Instalando o OpenMP</h2>
<p>É simples, você não instala.</p>
<blockquote><p>Como assim?</p></blockquote>
<p>Você DEVE ter um compilador que tenha o OpenMP implementado.</p>
<blockquote><p>E o meu compilador implementa?</p></blockquote>
<p><a href="http://openmp.org/wp/openmp-compilers/" target="_blank">Aqui </a>vc pode ver a lista de compiladores que disponibilizam o recurso. Como, provavelmente, vc usa:</p>
<ul>
<li><strong>V</strong><strong>isual C++ 2008</strong>: apenas a versão Professional (ou sei lá o nome da versão que não seja a Express) possui os headers necessários. ACHO que se vc copiar os headers da versão paga para a Express, irá funcionar;</li>
<li><strong>Code::Blocks (MinGW)</strong>: apenas nas versões (do gcc) 4.3.2 ou superiores.</li>
</ul>
<p>Baixei o <a href="http://www.mingw.org/" target="_blank">MinGW</a> mais recente no site oficial e instalei para usar com o Code::Blocks. Porém, a versão do gcc era a <em>3.4.alguma-coisa</em> e é claro, não funcionou pois não possuia os headers necessários.</p>
<p>Então, resolvi instalar logo o <a href="http://www.tdragon.net/recentgcc/" target="_blank">TDM&#8217;s GCC/MinGW</a> que é uma build não oficial dos binários mais recentes do GCC. Faça o download do <a href="http://sourceforge.net/projects/tdm-gcc/files/TDM-MinGW%20Installer/1.908.0/tdm-mingw-1.908.0-4.4.1-2.exe/download" target="_blank">instalador mais recente</a> e, na hora da instalação, escolha o diretório MinGW que está dentro do diretório de instalação do seu Code::Blocks (no meu caso, E:\CodeBlocks\MinGW):</p>
<p><img class="aligncenter size-full wp-image-121" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/tdm_install1.jpg" alt="tdm_install1" width="513" height="399" /></p>
<p>Clique em &#8220;Next &gt;&#8221; e selecione um mirror:</p>
<p><img class="aligncenter size-full wp-image-122" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/tdm_install2.jpg" alt="tdm_install2" width="513" height="399" /></p>
<p>Clique em &#8220;Next &gt;&#8221; e selecione apenas os componentes que deseja instalar. No meu caso, deixei como está (todos):</p>
<p><img class="aligncenter size-full wp-image-123" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/tdm_install3.jpg" alt="tdm_install3" width="513" height="399" /></p>
<p>Após selecionar os componentes, clique em &#8220;Install&#8221; e espere a extração dos arquivos terminar.</p>
<h2>Hello World!</h2>
<p>Se tudo estiver certo, então será possível compilar o &#8220;Hello World&#8221; abaixo:</p>
<pre class="brush: cpp;">

#include &lt;omp.h&gt;
#include &lt;stdio.h&gt;

int main()
{
#pragma omp parallel
printf(&quot;Hello! (from thread %d, num. threads %d)\n&quot;,
omp_get_thread_num(),
omp_get_num_threads());
}
</pre>
<p>Antes de tentar rodar o exemplo, precisamos definir a compile-time flag <strong>-fopenmp</strong> para que o compilador saiba que o projeto utiliza o OpenMP. Se vc compilar pelo prompt de comando diretamente com o GCC, basta adicionar o parâmetro <strong>-fopenmp</strong>, ficando assim:</p>
<p><span style="color: #000000"><strong><em>gcc.exe hello_world.c -o hello_world.exe -fopenmp</em></strong></span></p>
<p>Já no Code::Blocks, vc também precisa linkar a <strong>libgomp.dll.a </strong>e ter o arquivo <strong>libgomp-1.dll</strong> na pasta BIN do seu compilador ou na pasta do seu projeto. Então, faça assim:</p>
<ul>
<li>Selecione a opção &#8220;Build options&#8230;&#8221; no menu &#8220;Project&#8221; do Code::Blocks;</li>
<li>Na lista da esquerda, selecione o seu projeto (o 1º item, não o Debug, nem o Release);</li>
<li>Procure a aba &#8220;Other options&#8221; dentro da aba &#8220;Compiler settings&#8221;. Adicione a flag <strong>-fopenmp</strong>;<br />
<img class="aligncenter size-full wp-image-125" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_hw1.jpg" alt="omp_hw1" width="680" height="525" /></li>
<li>Agora selecione a aba &#8220;Linker settings&#8221; e adicione o arquivo <strong>libgomp.dll.a</strong>. Na minha instalação, esse arquivo estava no diretório &#8220;<em>E:\CodeBlocks\MinGW\lib\gcc\mingw32\4.4.1\</em>&#8220;;<strong> </strong></li>
<li>É importante que vc linke o arquivo <strong>libgomp.dll.a</strong> e não o <strong>libgomp.a;</strong></li>
<li>O projeto já pode ser compilado, mas para que funcione, será necessário copiar o arquivo <strong>libgomp-1.dll</strong> para o diretório do seu executável. Assim como a lib, o diretório em que esse arquivo pode ser encontrado não é tão trivial. Na minha instalação, encontrei em &#8220;<em>E:\CodeBlocks\MinGW\lib\gcc\mingw32\bin</em>&#8220;;</li>
<li>Creio que não é necessário explicar a parte de copiar o arquivo (<em>CTRL + C, CTRL + V, a mesma coisa que vc usa para fazer os trabalhos da faculdade</em>).</li>
</ul>
<p>Btw, <a href="http://gcc.gnu.org/projects/gomp/" target="_blank">GOMP</a> é o projeto que implementou o OpenMP nos compiladores C, C++ e Fortran do GNU Compiler Collection.</p>
<p>Pronto, o Hello World deve (ou deveria) mostrar algumas mensagens &#8220;Hello!&#8221; com o ID da thread em que está sendo executado, seguido do número de threads. Aqui tive o seguinte resultado:</p>
<p><img class="aligncenter size-full wp-image-126" src="http://blog.delarco.com.br/wp-content/uploads/2009/10/omp_hw2.jpg" alt="omp_hw2" width="677" height="342" /></p>
<p>Mas por que 3 threads? Porque esse é o número padrão para a variável ambiente OMP_NUM_THREADS (na minha implementação, pelo menos). Para definir o número de threads, chame a função <strong>omp_set_num_threads(num_threads).</strong> Então, o &#8220;Hello World&#8221; modificado ficaria assim:</p>
<pre class="brush: cpp;">

#include &lt;omp.h&gt;
 #include &lt;stdio.h&gt;

 int main()
 {
 omp_set_num_threads(10);

 #pragma omp parallel
 printf(&quot;Hello! (from thread %d, num. threads %d)\n&quot;,
 omp_get_thread_num(),
 omp_get_num_threads());
 }
</pre>
<p>Agora vc verá 10 mensagens &#8220;Hello!&#8221;.</p>
<h2>É só isso?</h2>
<p>Não. Apesar de simples, o exemplo anterior usa eficientemente todos os núcleos disponíveis, de forma transparente. Pode parecer que não houve um grande ganho no desempenho, mas com alguns testes vamos ver que a programação multicore pode otimizar de forma significativa o aplicativo.</p>
<p>Para que o post não fique cansativo, deixo o resto para semana que vem.</p>
<p><strong>Fonte:</strong> <a href="http://openmp.org/wp/" target="_blank">OpenMP.org</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.delarco.com.br/programacao-multicore-com-openmp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- www.000webhost.com Analytics Code -->
<script type="text/javascript" src="http://analytics.hosting24.com/count.php"></script>
<noscript><a href="http://www.hosting24.com/"><img src="http://analytics.hosting24.com/count.php" alt="web hosting" /></a></noscript>
<!-- End Of Analytics Code -->
