• Nenhum resultado encontrado

Comunicação Ponto a Ponto

N/A
N/A
Protected

Academic year: 2021

Share "Comunicação Ponto a Ponto"

Copied!
89
0
0

Texto

(1)

Comunicação Ponto a Ponto

Transferência de dados entre processos 

específicos, que não se encaixam em um  padrão global pré­definido;

Sempre ocorre entre dois processos, um  processo que envia e outro que recebe a  mensagem;

Como sempre no MPI, o processo que envia é  quem define os parâmetros da mensagem: 

o que e para quem;

Há muitas e muitas variações com semântica  distinta;

(2)

MPI_SEND

Operação “bloqueante”;

Envia mensagem para um destinatário  específico;

Mensagem é encapsulada em um 

“envelope”;

Endereço do remetente (implícito);

Endereço do destinatário;

Etiqueta;

Comunicador (implícito no C++);

(3)

MPI_SEND

C:

int MPI_Send(void* buf, int count, MPI_Datatype datatype,

int dest, int tag, MPI_Comm comm) Fortran:

MPI_SEND(BUF, COUNT, DATATYPE,

DEST, TAG, COMM, IERROR)

<type> BUF(*)

INTEGER COUNT, DATATYPE, DEST INTEGER TAG, COMM, IERROR

(4)

MPI_SEND

C++:

MPI::Comm::Send(

const void* buf, int count,

const MPI::Datatype& datatype, int dest, int tag) const

(5)

MPI_RECV

C:

int MPI_Recv(void* buf, int count,

MPI_Datatype datatype, int source, int tag, MPI_Comm comm,

MPI_Status *status)

(6)

MPI_RECV

Fortran:

MPI_RECV(BUF, COUNT, DATATYPE,

SOURCE, TAG, COMM, STATUS, IERROR)

<type> BUF(*)

INTEGER COUNT, DATATYPE, SOURCE, INTEGER TAG, COMM

INTEGER STATUS(MPI_STATUS_SIZE), IERROR

(7)

MPI_RECV

C++:

void MPI::Comm::Recv(void* buf, int count, const MPI::Datatype& datatype,

int source, int tag,

MPI::Status& status) const

void MPI::Comm::Recv(void* buf, int count, const MPI::Datatype& datatype,

int source, int tag) const

(8)

MPI_RECV - status

C:

MPI_Status stat;

stat.MPI_SOURCE;

stat.MPI_TAG;

stat.MPI_ERROR;

Fortran:

MPI_STATUS stat(3) stat(MPI_SOURCE) stat(MPI_TAG)

stat(MPI_ERROR)

C++:

MPI::Status stat;

stat.Get_source();

stat.Set_source();

stat.Get_tag();

stat.Set_tag();

stat.Get_error();

stat.Set_error();

(9)

MPI_RECV - source

Seleciona qual o processador de origem  que esta chamada deve receber;

É possível não especificar um processador  específico usando MPI_ANY_SOURCE;

Todos os apenas um, não é possível  especificar um subconjunto diferente  destes (outro comunicador ou outra  etiqueta);

(10)

ETIQUETAS ­ “TAGS”

As rotinas de recepção podem usar as 

etiquetas para selecionar e discriminar as  mensagens que devem receber;

Ex: mensagens que carregam dados e  mensagens de terminação;

É apenas um número inteiro, entre 0 e  MPI::UB;

Pode­se receber qualquer mensagem com  MPI_ANY_TAG;

(11)

MPI_GET_COUNT

Número de elementos recebidos fica  armazenado em “stat”;

Não pode ser acessado diretamente, mas  necessita chamada explícita (já é assim em  C++);

Por motivos de eficiência da 

implementação, o tipo de dados é  necessário na chamada;

(12)

MPI_GET_COUNT

Número de elementos em “stat”, mas  necessita chamada explícita:

C:int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) Fortran:

MPI_GET_COUNT(STATUS, DATATYPE, COUNT, IERROR)

INTEGER STATUS(MPI_STATUS_SIZE) INTEGER DATATYPE, COUNT, IERROR

(13)

MPI_GET_COUNT

C++:

int MPI::Status::Get_count(

const MPI::Datatype& datatype) const

(14)

IGNORANDO STATUS

Há um custo em processar o status das  mensagens, o que às vezes é 

desnecessário;

Pode­se evitar este custo com  MPI_STATUS_IGNORE e 

MPI_STATUSES_IGNORE em C e Fortran;

Em C++ simplesmente usa­se a função  sobrecarregada sem status;

(15)

Comunicação MPI com

Buffer

(16)

Modos de Comunicação

Quatro modos:

Padrão: MPI decide se/quanto buffer  usar;

“Buffered”: o usuário fornece o buffer  para uso do MPI;

Síncrono: completa quando a mensagem  começa a chegar no destino;

Pronto (“Ready”): só pode enviar se 

necessariamente já tiver sido chamada  a rotina de recepção correspondente;

(17)

Modos de Comunicação

Há rotinas de envio para cada tipo de  modo, com nomes diferentes, mas a  mesma assinatura:

MPI_SEND;

MPI_BSEND;

MPI_SSEND;

MPI_RSEND;

Há apenas uma rotina de recepção, que  funciona para qualquer modo:

MPI_RECV;

(18)

Modo Padrão

É um modo não local;

O envio pode ser requisitado sem que a  recepção tenha sido;

Como o sistema decide, não é possível 

garantir que o programa irá funcionar em  qualquer situação;

“Deadlock” é possível;

Programas “normais” são escritos no modo   padrão, mas isto não é portátil;

(19)

Modo “Buffered”

O usuário fornece ao sistema MPI espaço  para usar como buffer;

O MPI usa este espaço para copiar as 

mensagens de saída, e as rotinas de envio  retornam imediatamente;

É um modo local;

Se o espaço for insuficiente, um erro  ocorre e é sinalizado;

(20)

MPI_BUFFER_ATTACH

Associa um buffer com o MPI;

Apenas um buffer pode ser associado;

Pode não ser fácil estimar o tamanho 

necessário para um programa complexo;

Só mensagens enviadas no modo buffered  usam este buffer;

(21)

MPI_BUFFER_ATTACH

C:

int MPI_Buffer_attach(

void* buffer, int size) Fortran:

MPI_BUFFER_ATTACH(BUFFER, SIZE, IERROR) <type> BUFFER(*)

INTEGER SIZE, IERROR C++:

void MPI::Attach_buffer(

void* buffer, int size)

(22)

MPI_BUFFER_DETACH

Desassocia o buffer fornecido pelo usuário  do MPI;

Necessário antes de liberar a memória!

(23)

MPI_BUFFER_DETACH

C:int MPI_Buffer_detach(

void* buffer_addr, int* size) Fortran:

MPI_BUFFER_DETACH(

BUFFER_ADDR, SIZE, IERROR) <type> BUFFER_ADDR(*)

INTEGER SIZE, IERROR

C++:int MPI::Detach_buffer(void*& buffer)

(24)

Modo Síncrono

O envio só retorna quando a mensagem  começa a ser recebida;

É um modo não local;

Se funcionar, funciona funciona sempre, e  os programas são realmente portáteis!

Conhecido como o modo seguro, pois  independe do tamanho dos buffers  internos do MPI;

(25)

Modo Pronto

É necessário garantir via programação que  a função de recepção seja chamada antes  da função de envio correspondente;

Isto pode permitir que a comunicação seja  mais eficiente;

É claramente não local;

(26)

Propriedades da

Comunicação Ponto a Ponto

Não há ultrapassagem;

Não há “justiça”;

Recursos são limitados e sua exaustão  causa erros;

Um programa que funciona na ausência  de buffers é um programa seguro;

(27)

Comunicação Não Bloqueante

Permite que a comunicação ocorra  simultaneamente com a computação;

Pode esconder a latência e os custos de  comunicação;

Pode tornar os programas mais eficientes;

Comunicações divididas em duas etapas:

Início;

Teste para término;

(28)

Comunicação Não Bloqueante

Envio e recepção podem ser não  bloqueantes;

Uma rotina não bloqueante pode ter na 

outra ponta uma rotina bloqueante ou não  bloqueante;

As rotinas de envio não bloqueante podem  ter os quatro modos: padrão, “buffered”,  síncrono e pronto;

(29)

Comunicação Não Bloqueante

As rotinas de envio são sempre locais, e  retornam imediatamente;

O envio, no entanto, e as funções que  testam a comunicação, funcionam 

segundo o modo;

As rotinas de envio e teste de término são  conectadas por objetos do tipo 

MPI::Request;

(30)

Comunicação Não Bloqueante

As rotinas de envio não bloqueante tem  nomes baseados nas rotinas bloqueantes:

MPI_ISEND;

MPI_IBSEND;

MPI_ISSEND;

MPI_IRSEND;

A rotina de recepção não bloqueante é  chamada:

MPI_IRECV;

(31)

Comunicação Não Bloqueante

A comunicação é completada com uma  das duas rotinas (ou suas derivadas):

MPI_WAIT;

MPI_WAITSOME;

MPI_WAITALL;

MPI_WAITANY;

MPI_TEST;

MPI_TESTSOME;

MPI_TESTALL;

MPI_TESTANY;

(32)

MPI_ISEND

C:

int MPI_Isend(

void* buf, int count, MPI_Datatype datatype, int dest,

int tag, MPI_Comm comm, MPI_Request *request)

(33)

MPI_ISEND

Fortran:

MPI_ISEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM,

REQUEST, IERROR) <type> BUF(*)

INTEGER COUNT, DATATYPE, DEST

INTEGER TAG, COMM, REQUEST, IERROR

(34)

MPI_ISEND

C++:

MPI::Request MPI::Comm::Isend(

const void* buf, int count,

const MPI::Datatype& datatype, int dest,

int tag) const

(35)

MPI_I[BSR]SEND

Análogos, apenas retornam (ou 

acrescentam para C e Fortran) um objeto  do tipo MPI_REQUEST;

(36)

MPI_IRECV

C:int MPI_Irecv(

void* buf, int count,

MPI_Datatype datatype, int source,

int tag,

MPI_Comm comm,

MPI_Request *request)

(37)

MPI_IRECV

Fortran:

MPI_IRECV(

BUF, COUNT, DATATYPE,

SOURCE, TAG, COMM,REQUEST, IERROR)

<type> BUF(*)

INTEGER COUNT, DATATYPE INTEGER SOURCE, TAG, COMM INTEGER REQUEST, IERROR

(38)

MPI_IRECV

C++:

MPI::Request MPI::Comm::Irecv(

void* buf, int count,

const MPI::Datatype& datatype, int source, int tag) const

(39)

MPI_WAIT

Espera até que a comunicação “complete”;

O que é “completar”, depende do modo:

Padrão: mensagem foi copiada para um  buffer local;

Síncrono: mensagem começou a ser  copiada para o buffer de recepção;

Etc.;

Esta chamada desaloca o objeto  MPI_REQUEST criado!;

(40)

MPI_TEST

Também é possível verificar o resultado de  uma comunicação não bloqueante com 

MPI_TEST;

Retorna imediatamente, é uma operação  local;

DESALOCA objeto Request!

Não deve ser usada para “busy waiting!”

O objeto request deve ser liberado 

explicitamente com MPI_REQUEST_FREE;

(41)

MPI_TEST

C:

int MPI_Test(

MPI_Request *request, int *flag,

MPI_Status *status) Fortran:

MPI_TEST(REQUEST, FLAG, STATUS, IERROR) LOGICAL FLAG

INTEGER REQUEST

INTEGER STATUS(MPI_STATUS_SIZE) INTEGER IERROR

(42)

MPI_TEST

C++:

bool MPI::Request::Test(

MPI::Status& status) bool MPI::Request::Test()

(43)

MPI_WAIT

C:

int MPI_Wait(

MPI_Request *request, MPI_Status *status) Fortran:

MPI_WAIT(REQUEST, STATUS, IERROR) INTEGER REQUEST

INTEGER STATUS(MPI_STATUS_SIZE), IERROR

(44)

MPI_WAIT

C++:

void MPI::Request::Wait(

MPI::Status& status) void MPI::Request::Wait()

(45)

Testes Múltiplos

Muitas vezes é conveniente iniciar várias  comunicações, e verificar qual delas 

completou, em qualquer ordem;

Pode­se fazer isto com um vetor de  MPI_REQUEST, e com as funções:

MPI_WAITANY

MPI_WAITSOME

MPI_WAITALL

(46)

MPI_WAITANY

C:

int MPI_Waitany(

int count,

MPI_Request *array_of_requests, int *index,

MPI_Status *status)

(47)

MPI_WAITANY

Fortran:

MPI_WAITANY(

COUNT, ARRAY_OF_REQUESTS, INDEX, STATUS, IERROR)

INTEGER COUNT, ARRAY_OF_REQUESTS(*)

INTEGER INDEX, STATUS(MPI_STATUS_SIZE) IERROR

(48)

MPI_WAITANY

C++:

static int MPI::Request::Waitany(

int count,

MPI::Request array_of_requests[], MPI::Status& status)

static int MPI::Request::Waitany(

int count,

MPI::Request array_of_requests[])

(49)

MPI_TESTANY

Análogo a MPI_WAITANY;

Análogo a MPI_TEST;

(50)

MPI_TESTANY

C:int MPI_Testany(int count,

MPI_Request *array_of_requests, int *index,

int *flag,

MPI_Status *status)

(51)

MPI_TESTANY

Fortran:

MPI_TESTANY(COUNT,

ARRAY_OF_REQUESTS, INDEX, FLAG, STATUS, IERROR)

LOGICAL FLAG INTEGER COUNT,

INTEGER ARRAY_OF_REQUESTS(*)

INTEGER INDEX, STATUS(MPI_STATUS_SIZE) INTEGER IERROR

(52)

MPI_TESTANY

C++:

static bool MPI::Request::Testany(

int count,

MPI::Request array_of_requests[], int& index,

MPI::Status& status)

static bool MPI::Request::Testany(

int count,

MPI::Request array_of_requests[], int& index)

(53)

MPI_WAITALL

Obviamente, espera até que todas as 

comunicações pendentes informadas a ela  completem;

(54)

MPI_WAITALL

C:

int MPI_Waitall(

int count,

MPI_Request *array_of_requests, MPI_Status *array_of_statuses)

(55)

MPI_WAITALL

Fortran:

MPI_WAITALL(COUNT,

ARRAY_OF_REQUESTS,

ARRAY_OF_STATUSES, IERROR)

INTEGER COUNT, ARRAY_OF_REQUESTS(*)

INTEGER ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*) INTEGER IERROR

(56)

MPI_WAITALL

C++:static void MPI::Request::Waitall(

int count,

MPI::Request array_of_requests[], MPI::Status array_of_statuses[]) static void MPI::Request::Waitall(

int count,

MPI::Request array_of_requests[])

(57)

MPI_TESTALL

Análogo a MPI_WAITALL;

Análogo a MPI_TEST;

(58)

MPI_TESTALL

C:

int MPI_Testall(int count,

MPI_Request *array_of_requests, int *flag,

MPI_Status *array_of_statuses)

(59)

MPI_TESTALL

Fortran:

MPI_TESTALL(COUNT,

ARRAY_OF_REQUESTS,

FLAG, ARRAY_OF_STATUSES, IERROR)

LOGICAL FLAG

INTEGER COUNT, ARRAY_OF_REQUESTS(*)

INTEGER ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*) INTEGER IERROR

(60)

MPI_TESTALL

C++:

static bool MPI::Request::Testall(

int count,

MPI::Request array_of_requests[], MPI::Status array_of_statuses[]) static bool MPI::Request::Testall(

int count,

MPI::Request array_of_requests[])

(61)

MPI_WAIT_SOME

Espera até que pelo menos uma das  comunicações pendentes tenham 

terminado;

Retorna um contagem e um vetor de  índices de comunicações completas;

Desaloca o “request” correspondente;

Normalmente, é melhor usar esta do que  MPI_WAIT_ANY;

(62)

MPI_WAIT_SOME

C:

int MPI_Waitsome(

int incount,

MPI_Request *array_of_requests, int *outcount,

int *array_of_indices,

MPI_Status *array_of_statuses)

(63)

MPI_WAIT_SOME

Fortran:

MPI_WAITSOME(INCOUNT,

ARRAY_OF_REQUESTS, OUTCOUNT, ARRAY_OF_INDICES,

ARRAY_OF_STATUSES, IERROR)

INTEGER INCOUNT, ARRAY_OF_REQUESTS(*) INTEGER OUTCOUNT, ARRAY_OF_INDICES(*)

INTEGER ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*) INTEGER IERROR

(64)

MPI_WAIT_SOME

C++:

static int MPI::Request::Waitsome(int incount, MPI::Request array_of_requests[],

int array_of_indices[],

MPI::Status array_of_statuses[])

static int MPI::Request::Waitsome(int incount, MPI::Request array_of_requests[],

int array_of_indices[])

(65)

MPI_TEST_SOME

Análogo a MPI_WAIT_SOME e  MPI_TEST_ANY;

Retorna imediatamente;

Normalmente, é melhor usar esta do que  MPI_TEST_ANY;

(66)

MPI_TEST_SOME

C:

int MPI_Testsome(int incount,

MPI_Request *array_of_requests, int *outcount,

int *array_of_indices,

MPI_Status *array_of_statuses)

(67)

MPI_TEST_SOME

Fortran:

MPI_TESTSOME(INCOUNT,

ARRAY_OF_REQUESTS, OUTCOUNT, ARRAY_OF_INDICES,

ARRAY_OF_STATUSES, IERROR)

INTEGER INCOUNT, OUTCOUNT, IERROR INTEGER ARRAY_OF_REQUESTS(*)

INTEGER ARRAY_OF_INDICES(*),

INTEGER ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*)

(68)

MPI_TEST_SOME

C++:

static int MPI::Request::Testsome(

int incount,

MPI::Request array_of_requests[], int array_of_indices[],

MPI::Status array_of_statuses[]) static int MPI::Request::Testsome(

int incount,

MPI::Request array_of_requests[], int array_of_indices[])

(69)

MPI_REQUES_GET_STATUS

Com MPI_REQUEST_GET_STATUS é  possível verificar se uma comunicação  completou, sem invalidar o “request”;

O mesmo request pode ser reusado por  outras funções;

Útil no caso do desenvolvimento de  bibliotecas de comunicação;

(70)

MPI_PROBE – MPI_IPROBE

É possível verificar se uma mensagem está  para chegar, sem recebê­la efetivamente;

É possível portanto alocar buffers para  mensagens antes de recebê­las; 

MPI_PROBE bloqueia até que uma 

mensagem específica esteja preparada  para chegar;

 MPI_IPROBE retorna imediatamente, 

indicando se há uma mensagem específica  pronta para chegar;

(71)

MPI_PROBE

C:int MPI_Probe(

int source, int tag,

MPI_Comm comm,

MPI_Status *status)

(72)

MPI_PROBE

Fortran:

MPI_PROBE(

SOURCE, TAG, COMM, STATUS, IERROR)

INTEGER SOURCE, TAG, COMM, IERROR INTEGER STATUS(MPI_STATUS_SIZE)

(73)

MPI_PROBE

C++:

void MPI::Comm::Probe(int source,

int tag, MPI::Status& status) const void MPI::Comm::Probe(int source,

int tag) const

(74)

MPI_IPROBE

C:

int MPI_Iprobe(

int source, int tag,

MPI_Comm comm, int *flag,

MPI_Status *status)

(75)

MPI_IPROBE

Fortran:

MPI_IPROBE(SOURCE, TAG, COMM, FLAG, STATUS, IERROR)

LOGICAL FLAG

INTEGER SOURCE, TAG, COMM, IERROR INTEGER STATUS(MPI_STATUS_SIZE)

(76)

MPI_IPROBE

C++:

bool MPI::Comm::Iprobe(

int source, int tag,

MPI::Status& status) const bool MPI::Comm::Iprobe(

int source,

int tag) const

(77)

MPI_CANCEL

É possível cancelar uma comunicação  pendente com MPI_CANCEL;

Ainda é necessário completar a 

comunicação com MPI_WAIT, MPI_TEST,  etc!

O cancelamento da comunicação é  indicado no status;

Não é garantido que o cancelamento  ocorra!

Para ocasiões muito especiais apenas;

(78)

MPI_CANCEL

C:int MPI_Cancel(MPI_Request *request)

Fortran:

MPI_CANCEL(REQUEST, IERROR) INTEGER REQUEST, IERROR

C++:

void MPI::Request::Cancel() const

(79)

MPI_TEST_CANCELLED

C:

int MPI_Test_cancelled(

MPI_Status *status, int *flag) Fortran:

MPI_TEST_CANCELLED(STATUS, FLAG, IERROR) LOGICAL FLAG

INTEGER STATUS(MPI_STATUS_SIZE), IERROR C++:

bool MPI::Status::Is_cancelled() const

(80)

MPI_SENDRECV

Padrão típico: troca com vizinhos;

Recebe do anterior, envia para o próximo;

Pode ser feito com chamadas bloqueantes  e cuidado;

Pode ser feito com chamadas não  bloqueantes, e menos cuidado;

MPI_SEND_RECV cuida dos detalhes e  não há risco de deadlock;

Operação bloqueante, que retorna quando  ambas as operações estiverem completas;

(81)

MPI_SENDRECV

C:

int MPI_Sendrecv(

void *sendbuf, int sendcount, MPI_Datatype sendtype,

int dest, int sendtag,

void *recvbuf, int recvcount, MPI_Datatype recvtype,

int source, int recvtag,

MPI_Comm comm, MPI_Status *status)

(82)

MPI_SENDRECV

Fortran:

MPI_SENDRECV(SENDBUF, SENDCOUNT, SENDTYPE, DEST, SENDTAG,

RECVBUF, RECVCOUNT, RECVTYPE,

SOURCE, RECVTAG, COMM, STATUS, IERROR) <type> SENDBUF(*), RECVBUF(*)

INTEGER SENDCOUNT, SENDTYPE, DEST

INTEGER SENDTAG, RECVCOUNT, RECVTYPE INTEGER SOURCE, RECVTAG, COMM

INTEGER STATUS(MPI_STATUS_SIZE), IERROR

(83)

MPI_SENDRECV

C++:

void MPI::Comm::Sendrecv(

const void *sendbuf, int sendcount, const MPI::Datatype& sendtype,

int dest, int sendtag,

void *recvbuf, int recvcount, const MPI::Datatype& recvtype, int source, int recvtag,

MPI::Status& status) const

(84)

MPI_SENDRECV

C++:

void MPI::Comm::Sendrecv(

const void *sendbuf, int sendcount, const MPI::Datatype& sendtype,

int dest, int sendtag,

void *recvbuf, int recvcount, const MPI::Datatype& recvtype, int source, int recvtag) const

(85)

MPI_SENDRECV_REPLACE

Análogo a MPI_SENDRECV, com um único  buffer para envio e recepção;

Mensagem que chega substitui a  mensagem enviada;

Operação bloqueante!

(86)

MPI_SENDRECV_REPLACE

C:

int MPI_Sendrecv_replace(

void* buf, int count, MPI_Datatype datatype, int dest, int sendtag,

int source, int recvtag, MPI_Comm comm,

MPI_Status *status)

(87)

MPI_SENDRECV_REPLACE

Fortran:

MPI_SENDRECV_REPLACE(BUF, COUNT, DATATYPE, DEST, SENDTAG,

SOURCE, RECVTAG,

COMM, STATUS, IERROR) <type> BUF(*)

INTEGER COUNT, DATATYPE, DEST, IERROR INTEGER SENDTAG, SOURCE, RECVTAG, COMM INTEGER STATUS(MPI_STATUS_SIZE)

(88)

MPI_SENDRECV_REPLACE

C++:

void MPI::Comm::Sendrecv_replace(

void* buf, int count,

const MPI::Datatype& datatype, int dest, int sendtag,

int source, int recvtag, MPI::Status& status) const

(89)

MPI_SENDRECV_REPLACE

C++:

void MPI::Comm::Sendrecv_replace(

void* buf, int count,

const MPI::Datatype& datatype, int dest, int sendtag,

int source, int recvtag) const

Referências

Documentos relacionados

História importa: o acidente histórico que levou ao qwerty capturou aproximadamente 100% dos digitadores e se autoperpetuou mesmo que a motivação original para usar qwerty não

A partir da identificação dos respondentes, o coordenador da IOGE disponibiliza o instrumento de avaliação de forma individual para preenchimento. Cada respondente submete a

De lá para cá, as pessoas ficaram muito mais ocupadas que o nobre inglês e a criação do criado virou mania universal. Atraente pelo visual, simples, o sanduíche viu passar

Neste novo modelo institucional do setor elétrico foram criados novos agentes, entre eles a Empresa de Pesquisa Energética – EPE, que tem entre uma de suas atribuições, a tarefa

A instrução MUL efectua a multiplicação de números não negativos, enquanto que o IMUL efectua a multiplicação de números negativos. (I)MUL &lt;origem&gt; em que &lt;origem&gt;

7ª etapa - as principais evidências de que o DNA existe pelo motivo de criar mais DNA, é comprovada pelo surgimento do nosso ancestral primata conhecido por

A classificação final do LVA em relação à taxonomia é dada pela marcação do ponto no plano cartesiano, indicado pelo Nível de Interatividade e Critério

iii) Na ausência da característica lubrificante dos fluidos preparados apenas com argila, os fatores primordiais para redução do risco de prisão diferencial são as