• Nenhum resultado encontrado

AbouGhazaleh et al. (2003) propõem a utilização de ambas as abordagens da DVFS em um ambiente colaborativo entre o sistema operacional e o compilador. Os autores dividem a proposta em duas fases: off-line, onde ocorre a identificação dos pontos para troca de frequência e tensão; e on-line, na qual a troca de frequência ocorre durante a

execução de um processo.

A parte off-line utiliza o compilador para extrair informações sobre o possível com- portamento temporal de uma tarefa. Então, divide-se o fluxo de execução em segmentos e impõe-se a chamada de uma interrupção em um período de tempo estimado. Instruções também são inseridas no código fonte de uma tarefa para manter o controle de quantos ciclos já foram realizados. A parte on-line já fica a cargo do sistema operacional, o qual manterá o controle das chamadas de interrupção.

Uma vez alcançado o tempo da interrupção definido na parte off-line, interrompe-se a tarefa e avalia se o número de ciclos realizados até o momento permite a alteração da tensão com o cumprimento da restrição temporal. A adição dos overheads nesta abordagem é um ponto a ser destacado já que o cálculo da nova tensão e o tempo gasto para adotá-la influenciam na energia consumida e no desempenho das tarefas em execução. Além disso, os autores ainda obtiveram uma economia de 57% no consumo da energia.

A implementação do trabalho relatado por AbouGhazaleh et al. (2003) não é trivial, pois não só o compilador deve sofrer alterações, como também o sistema operacional, onde é necessário a implementação de novas chamadas de sistema e alterações no escalonador.

Outro estudo sobre a utilização da DVFS inter-tarefa e intra-tarefa encontra-se em Seo et al. (2005). A primeira parte deste trabalho consiste em analisar estaticamente o conjunto de tarefas do sistema e produzir o grafo de fluxo de controle.

Ainda neste processo, determina-se o número de ciclos para cada bloco e atribui-se uma probabilidade do fluxo de execução em adotar um desvio. Com base nas frequências disponíveis pelo processador, os autores determinam o tempo de computação da tarefa e, em seguida, os tempos inicial e final da execução, de modo a otimizar o consumo de energia. A frequência utilizada para calcular o tempo de computação de uma tarefa corresponde ao limite inferior das possíveis frequências a serem adotadas.

Deste modo, os autores garantem que qualquer valor de frequência abaixo deste limite não respeitará a restrição temporal. Ainda na análise intra-tarefa, cada desvio no fluxo de execução é um possível candidato para troca de frequência e tensão.

A parte inter-tarefa do estudo de Seo et al. (2005) necessita de três informações essenciais: o tempo de chegada, o deadline e o número de ciclos restantes para o término

3. Trabalhos Correlatos 29

da execução da tarefa.

O algoritmo proposto por Seo et al. (2005) identifica um intervalo crítico onde um conjunto de tarefas deve ser completado sem sofrer alteração de outras tarefas fora deste conjunto, a fim de minimizar o consumo de energia. As tarefas neste intervalo crítico executam com a maior frequência disponível e são ordenadas com base na política de escalonamento EDF. A desvantagem da proposta de Seo et al. (2005) está em não considerar cenários onde as tarefas possam ser dependentes ou mesmo compartilhar recursos.

Método Proposto

Este capítulo define a metodologia proposta para a análise estática do comportamento de uma tarefa, a partir da geração do grafo de fluxo de controle de um programa em C. Ainda, propõe-se uma estratégia para determinar o número de ciclos a serem consumidos no pior caso do fluxo de execução de uma tarefa. O cálculo da nova frequência a ser utilizada durante a execução de uma tarefa e qual a frequência inicial também são tópicos abordados neste capítulo.

4.1

Grafo de Fluxo de Controle

O projeto de compiladores normalmente está sujeito a três principais fases: front-end, otimização e back-end.

O front-end é responsável pela análise léxica, sintática, semântica e geração do código intermediário.

A análise léxica encarrega-se de reconhecer os símbolos aceitos pela linguagem. Já a sintática, verifica se a estrutura gramatical está correta, enquanto a semântica analisa o contexto das operações (e.g. operação de soma com dados de tipos diferentes). A última etapa do front-end, é responsável por gerar o código intermediário a ser utilizado na fase de otimização do compilador.

As otimizações, no código intermediário, têm como objetivo melhorar o desempenho do código final a partir da aplicação de heurísticas ou reescrita de código. Já a última fase, o back-end, é o responsável por transformar o código intermediário em código de máquina (Cooper & Torczon, 2012).

Dentre as três principais fases de compilação, a do front-end é a que melhor permite identificar a estrutura de um código. Isto ocorre devido a etapa de análise sintática em que os símbolos de uma linguagem, já reconhecidos, são comparados com a estrutura

4. Método Proposto 31

gramatical. Assim, se uma determina linha de código corresponder a uma regra válida da gramática, então esta linha pertence a linguagem. Uma das formas de se produzir o CFG é justamente pela análise da gramática de uma linguagem, mais especificamente as gramáticas livres de contexto.

Gramáticas livres de contexto são aquelas cujas regras de produção possuem um ou mais símbolos não-terminais, os quais serão decompostos em um elemento vazio ou um ou mais símbolos terminais ou outros não-terminais. Porém, a forma como essas regras são decompostas influencia diretamente na eficiência da análise estática do código. Mais detalhes sobre o desenvolvimento de uma gramática pode ser visto em Levine (2009).

O presente estudo assume a utilização de gramática genérica para a linguagem C. O termo genérico, neste caso, faz referência ao reconhecimento de blocos – conjunto de instruções, estruturas comuns – iteração e seleção, e das definições das funções, pois são estes elementos que alteram o fluxo de execução de uma tarefa.

Ao mapear essas características para um CFG, têm-se as seguintes definições: ◦ Um bloco corresponde a um nó;

◦ Os desvios condicionais são as arestas;

◦ Qualquer condição dos desvios corresponde a um único nó. Assim, se a condição tiver como origem uma estrutura de seleção (ex: if ), então ela será um nó pai com dois filhos de destino: o then e o else;

◦ Se a condição tiver como origem uma estrutura de iteração (ex: while), ela também será um nó pai com outros dois filhos, o then – que se refere à execução do laço, e o nó de saída do laço – que indica a continuação do fluxo;

◦ Como um código em C pode conter a definição de uma ou mais funções, cada função é tratada como um subgrafo do CFG da tarefa.

É possível obter o grafo de fluxo de controle, como uma abstração da análise estática do comportamento de uma tarefa, a partir das definições listadas acima. A Figura 4.1 apresenta graficamente esses pontos.

O grafo de fluxo de controle, contudo, carece de informações, pois não há como determinar qual dos possíveis caminhos do CFG demandará maior processamento. Para

(a) Código exemplo. (b) Divisão em blocos. B1 B2 B3 B4 B5 B6 B7

(c) Grafo de fluxo de controle.

Figura 4.1: Visualização do código em blocos e no CFG.

isto, utiliza-se o número de ciclos necessários para execução de cada nó do grafo. Uma vez que cada nó corresponde a um conjunto de instruções, caso se conheça o custo de execução de cada instrução, a soma delas corresponderá ao custo total do nó.

Por fim, com o custo dos nós associados, é possível determinar o custo total dos caminhos no CFG, inclusive o pior caso.

Documentos relacionados