• Nenhum resultado encontrado

APÊNDICE C – LISTAGENS DE CÓDIGO

2 FUNDAMENTAÇÃO TEÓRICA

2.1 CARACTERIZAÇÃO DE SOFTWARE SEQUENCIAL E SOFTWARE PARALELO

A fundamentação relativa a arquiteturas de computadores, relevante para a concepção da ARQPON, não pode ser abordada somente do ponto de vista de hardware. De fato, existe uma necessidade de sinergia entre o hardware e o software, em relação aos recursos que aquele oferece e de que forma este os aproveita, tanto em aplicações que apresentam características de execução sequencial quanto em aplicações que pretendam fazer uso de paralelismo. Levando-se então em consideração que alguns conceitos relativos à concepção de software para execução sequencial são diferentes dos conceitos relativos à concepção de software para execução paralela, propõe-se, nesta seção, apresentar uma caracterização dos dois tipos.

Denomina-se software sequencial todo software que é concebido segundo técnicas de programação sequencial. Estas, por sua vez, geralmente são aplicadas partindo-se da premissa de que o software será executado por uma máquina computacional que aloca todos os seus recursos de hardware disponíveis para processamento e execução de uma única instrução em determinado instante de tempo. Ou seja, não existe a execução simultânea de várias instruções nem mesmo de partes de uma instrução.

Uma arquitetura que possua uma única unidade central de processamento (CPU, ou

Central Processing Unit) seguindo o modelo de execução sequencial é comumente

denominada de arquitetura sequencial. A característica de execução sequencial de instruções por uma única CPU implica em que o desempenho de execução de um software sequencial seja dependente do número de instruções que a CPU é capaz de executar em determinada unidade de tempo. Utiliza-se comumente o termo MIPS (millions of instructions per second, ou milhões de instruções por segundo) para quantificar este desempenho em arquiteturas modernas, embora outras métricas possam ser utilizadas (ver Seção 2.5 para maiores detalhes).

O aumento do número de MIPS executadas por uma CPU é influenciado pelos seguintes fatores:

Aumento na frequência do clock da CPU.

• Utilização de técnicas mais sofisticadas de paralelização executadas em nível de

hardware, ou seja, que paralelizem a execução de partes do software sequencial de

forma transparente para o modelo de programação. Portanto, neste caso descarta-se a premissa de que todos os recursos de hardware são alocados simultaneamente

para a execução de uma única instrução, porém ainda deve ser possível executar corretamente o software que foi concebido segundo uma abordagem sequencial.

Dentre as técnicas de paralelização em nível de hardware que mais têm sido utilizadas em arquiteturas de processadores sequenciais, destacam-se a paralelização em nível de bit (DLP, ou data level parallelism) e paralelização em nível de instrução (ILP, ou

instruction level parallelism). O conceito de DLP se refere à possibilidade de se processar

simultaneamente conjuntos múltiplos de dados, por meio do uso de barramentos e registradores com grande capacidade de bits. A ILP, por sua vez, é baseada na disponibilização de recursos de hardware que permitam dividir a execução de uma instrução em vários estágios e executar diversos estágios de diferentes instruções simultaneamente (conhecido por pipelining) (HENNESSY; PATTERSON, 2007).

Em contraposição, denomina-se software paralelo os programas que são explicitamente compostos, total ou parcialmente, por comandos ou sequências de comandos que podem apresentar execução simultânea com outros comandos ou sequências de comandos. Ou seja, software paralelo não é composto por uma única linha de execução (thread) obrigatoriamente executada sequencialmente no tempo, mas sim por potenciais múltiplas linhas de execução que podem ser executadas simultaneamente umas às outras. Esta visão do software paralelo sendo composto por múltiplas linhas de execução é denominada de TLP (thread level parallelism, ou paralelismo em nível de thread).

Seguindo raciocínio similar ao aplicado na definição de arquitetura sequencial, denomina-se arquitetura paralela um ambiente, composto por múltiplas unidades de execução/processamento (CPUs) interconectadas, capaz de executar efetivamente de forma simultânea e concorrente as múltiplas threads definidas por um software paralelo. Ou seja, uma arquitetura paralela deve idealmente executar software paralelo atendendo as premissas a partir das quais ele foi concebido.

O aproveitamento do paralelismo oferecido pela arquitetura em qualquer dos níveis possíveis (TLP, ILP etc.) deve levar em consideração possíveis problemas de concorrência e sincronização, sendo uma questão a ser abordada e considerada cuidadosamente quando da concepção do software. Pode-se citar, como exemplo, o acesso a variáveis compartilhadas que, em um programa que utiliza técnicas de TLP, pode requerer algum tipo de sincronização ou exclusão mútua por meio do uso de primitivas tais como semáforos ou mutexes.

Além disso, software sequencial também pode ser paralelizado até certo ponto. Segundo Ferlin (2008), esta paralelização pode ser executada implicitamente de forma

automática ou semi-automática pelo próprio compilador, por meio de algumas fases adicionais no processo de compilação tais como a detecção de paralelismo e alocação de recursos. Ainda, Ferlin (1997)(2008) descreve um conjunto de técnicas de paralelização implícita e lista um conjunto de compiladores que oferecem este recurso, o qual é explorado adequadamente mediante a utilização de linguagens de programação apropriadas (p. ex. SISAL) (SISAL, 2012) (HURSON; KAVI, 2008). No entanto, a transformação de software sequencial em paralelo incorre no consequente impacto em overhead de sincronização e comunicação entre as diversas threads oriundas do processo de paralelização (KLAUER et al., 2002), além do que a identificação das partes do software que são paralelizáveis pode não ser simples, inclusive devido a questões relativas ao paradigma de desenvolvimento utilizado.

Em relação à forma como detalhes arquiteturais influenciam na visão que o desenvolvedor aplica na concepção do software paralelo, a diferenciação mais visível ocorre entre arquiteturas baseadas em multiprocessadores e arquiteturas baseadas em multicomputadores. Segundo Tanenbaum (2013), a principal diferença entre os dois tipos de sistemas é que os sistemas baseados em multiprocessadores mantêm um espaço compartilhado de memória para utilização por todas as unidades paralelas de execução, ao passo que sistemas baseados em multicomputadores mantêm espaços de memória dedicados para cada unidade de execução. Esta organização de memória influencia nas técnicas e estratégias que devem ser implementadas no software paralelo para sincronização e comunicação entre as diferentes unidades de execução.

Além disso, embora não se constitua de fato em paralelismo real, existem técnicas para execução de software paralelo em arquiteturas sequenciais. Estas técnicas estão fundamentadas na sequencialização escalonada das múltiplas linhas de execução (atualmente

threads pertencentes a processos) que compõem o software paralelo, geralmente efetuada por

um sistema operacional. Isto permite que, em determinado instante de tempo, uma determinada linha de execução (aqui chamada de thread) esteja ocupando exclusivamente os recursos computacionais de hardware segundo alguma política de escalonamento. Embora o

software não seja, de fato, executado em paralelo segundo esta abordagem, ainda assim deve

ser concebido levando-se em consideração a comunicação e sincronização entre diferentes

threads e os problemas de concorrência que podem advir desta organização.

A principal dificuldade em relação ao desenvolvimento de software paralelo se refere ao alto grau de abstração necessário para se estruturar a lógica de forma coerente com os objetivos a serem alcançados por meio da paralelização. De fato, conforme lembrado por Irwin e Shen (2005), a lógica aplicada no desenvolvimento de software de maneira geral é

influenciada pela forma de pensar dos seres humanos, e estes têm dificuldade natural em abstrair concorrência ou paralelismo, o que dificulta inclusive a análise e a prova de correção de software paralelo. Ainda, a execução de software paralelo geralmente demanda mais recursos e gerenciamento mais complexo, haja vista a necessidade de se utilizar estruturas algorítmicas mais complexas e de tratar questões relacionadas ao determinismo de execução, tais como a ocorrência de deadlocks (CULLER; ARVIND, 1988)(GUPTA; SOHI, 2011). Isto pode influenciar negativamente o desempenho, principalmente no que diz respeito à necessidade de abstrações mais complexas e de mecanismos de comunicação/sincronização adequados.

Em adição a estas questões, deve-se levar em consideração que um algoritmo originalmente implementado de forma sequencial não é, necessariamente, totalmente paralelizável. A diminuição da fração executável em paralelo pode ocorrer não somente pela dificuldade ou impossibilidade de se paralelizar o software por completo, mas também por interdependências existentes entre as partes paralelizáveis, requerendo pontos de sincronização que forcem a execução sequencial em determinados trechos. Uma métrica útil para se avaliar quantitativamente o grau de paralelização é denominada “eficiência” e pode ser calculada por meio da razão entre o speedup total obtido por meio da paralelização, obtida segundo os princípios da “Lei de Amdahl” (HENNESSY; PATTERSON, 2007), e o número de unidades disponíveis para execução em paralelo. Um valor de eficiência próximo de 1 indica que a ocupação das unidades paralelas na execução do programa é próxima de 100%.

Tendo em vista esta conceituação apresentada, as seções a seguir discorrem sobre temas que estão intimamente relacionados ao contexto do software paralelo. Mais especificamente, apresenta-se o Paradigma Orientado a Notificações (PON), enfatizando-se a sua adequação para o desenvolvimento de software paralelo ou distribuído, bem como conceitos de arquitetura de computadores com enfoque nas tecnologias envolvidas para viabilizar a computação paralela.