• Aucun résultat trouvé

8. PROCEDURES TO FOLLOW WHEN ESTIMATED DOSES

8.1. An iterative approach to evaluation

Benchmarks(EPB) criados por Pinto et al. (2016). Os EPBs são benchmarks que servem para aferir o consumo de energia e desempenho de 16 implementações de coleções seguras a threads. Para cada coleção é analisado o perfil de consumo de energia das operações de inserção, remoção e leitura simulando um ambiente concorrente e com intenso uso dessas coleções. Para medir o consumo de energia, foi utilizada a biblioteca jRAPL (LIU; PINTO; LIU, 2015). Como resultado dessas medições, tem-se o perfil de consumo de energia de cada coleção. Esses perfis serão utilizados posteriormente para realizar a recomendação de qual melhor implementação de coleção utilizar. Além disso, esses perfis de consumo de energia são específicos para a máquina em que a aplicação vai rodar. Dessa forma, caso as aplicações rodem em hardware com configurações diferentes, é necessário novamente medir esses perfis de consumo de energia. Os perfis dependem do ambiente devido às diferenças entre plataformas de hardware e variações entre as versões da Máquina Virtual Java (JVM). Já foi demonstrado (PINTO et al., 2016), por exemplo, que o consumo de energia e o tempo de execução da classe ConcurrentHashMap mudaram significativamente entre as versões 7 e 8 da linguagem Java.

3.3 Análise Estática das Aplicações

Essa seção explica a etapa da análise estática, a qual extrai informações das aplicações, como a frequência de uso das operações e o contexto no qual essas operações são chamadas.

Para ilustrar as próximas etapas, a Figura 3.2 apresenta um exemplo de código, retirado da biblioteca Xalan (Xalan - The Apache XML Project, 2016), que realiza inserções e leituras na variável imports do tipo Vector. Esse exemplo será referenciado ao longo do texto como “Exemplo Base”. O código foi simplificado para facilitar o entendimento.

Nesse exemplo, a variável imports (variável coleção) da classe Stylesheet é uma coleção de objetos na qual são realizas inserções e leituras (linhas 6 e 10 respectivamente). A classe Stylesheet possui os métodos getImports e addImports (linhas 13 e 20), que chamam os métodos setImport e getImport para realizar as inserções e leituras na variável imports. Estes dois métodos são chamados dentro de loops. Além disso, a variável imports também pode ser lida a partir do método recomposeImports() (linha 34), que por sua vez é chamado pelo método recompose(). Neste caso a operação de leitura, elementAt, está sendo realizada dentro de dois loops aninhados (linha 28 e linha 35). Logo, para a variável importstem-se (1) um método para inserção sendo chamado dentro de apenas um loop e (2) duas ocorrências de leitura, uma dentro de um loop e outra dentro de dois loops aninhados. Apesar de estarem em métodos diferentes, o aninhamento é levado em consideração por esta abordagem.

3.3. ANÁLISE ESTÁTICA DAS APLICAÇÕES 30

1 public class Stylesheet extends ElemTemplateElement{

2 ...

3 private Vector imports;

4

5 public void setImport(StylesheetComposed v){

6 imports.addElement(v);

7 }

8

9 public StylesheetComposed getImport(int i){

10 return (StylesheetComposed) imports.elementAt(i);

11 }

12

13 protected void getImports(Stylesheet stylesheet){

14 for (int i = 0; i < n; i++)

15 {

16 Stylesheet imported = stylesheet.getImport(i);

17 }

18 }

19

20 public void addImports(Stylesheet stylesheet, ...){

21 for (int i = 0; i < n; i++)

22 {

23 stylesheet.setImport(style);

24 }

25 }

26

27 public void recompose() throws TransformerException{

28 for (int i = 0, j= importList.size() -1; i < importList.size();

i++) 29 { 30 globalImportList[j--].recomposeImports(); 31 } 32 } 33 34 void recomposeImports(){ 35 while (count > 0)

36 m_endImportCountComposed += this.getImport(--count);

37 }

38 ...

39 }

3.3. ANÁLISE ESTÁTICA DAS APLICAÇÕES 31 3.3.1 Estimativa da Frequência de Uso

A estimativa da frequência de uso das operações de inclusão, remoção e consulta é realizada através de análise estática do bytecode das aplicações. Essa análise estática é inter- procedural.

A análise inter-procedural utiliza call graphs e control flow graphs para medir a quanti- dade de ocorrências das operações das coleções, além do obter o nível de aninhamento de loops em que essas operações são chamadas. Para cada método é verificado se existem chamadas a operações das coleções estudadas nesse trabalho (e disponíveis na Tabela 3.1). A quantidade de chamadas a cada uma é armazenada em um contador. Ao final de todo o fluxo de chamadas do call graph, obtém-se o número de vezes que estas operações são chamadas. Como podem existir vários caminhos a serem percorridos para uma determinada chamada, a contagem de ocorrências está relacionada a um determinado contexto de execução. Esse contexto é definido pelas seguintes variáveis:

 Tipo da coleção;

 Nome da variável que armazena a coleção na qual é realiza a operação;

 Número de ocorrências da operação;

 Nome da operação;

 Classe na qual a operação é realizada;

 Método no qual a operação é realizada;

 Linha de código da ocorrência da operação;

 Informações sobre os aninhamentos dos loops.

A Tabela 3.2 apresenta o contexto para a operação elementAt da variável imports do Exemplo Base, quando essa tem sua ocorrência dentro apenas de um loop. Enquanto a Tabela 3.3 apresenta o contexto para a mesma operação, quando chamada dentro de dois loops aninhados.

Portanto, chamadas à mesma operação podem ser contadas de formas diferentes de acordo com os contextos nos quais se encontram. Como percebe-se no Exemplo Base, a operação elementAt possui dois contextos: um no qual foi chamada dentro de um loop e outra no qual foi chamada dentro de dois loops aninhados.

3.3.2 Análise de Loops

A simples contagem das ocorrências das chamadas das operações não é suficiente para realizar uma boa recomendação, uma vez que essa contagem não representa o real uso das

3.3. ANÁLISE ESTÁTICA DAS APLICAÇÕES 32 Tabela 3.2: Exemplo de contexto aplicado à operação elementAt

Nome da variável imports

Nome da operação elementAt

Número de ocorrências 1

Tipo da estrutura de dados Vector

Classe na qual a operação foi realizada Stylesheet Método no qual a operação foi realizada getImport

Linha de código 10

Nível de Aninhamento do loop 1

Tabela 3.3: Exemplo de contexto aplicado à operação elementAt, dentro de dois loops aninhados

Nome da variável imports

Nome da operação elementAt

Número de ocorrências 1

Tipo da estrutura de dados Vector

Classe na qual a operação foi realizada Stylesheet Método no qual a operação foi realizada getImport

Linha de código 10

Nível de Aninhamento do loop 2

operações devido à quantidade de vezes que as operações podem ser executadas dentro de um loop. Desta forma, quando uma operação é chamada dentro de um loop, uma contagem mais realista seria multiplicar a quantidade de ocorrências pela quantidade de iterações do loop. Porém, na maioria das vezes a quantidade de iterações dos loops não pode ser determinada de forma precisa estaticamente, podendo, inclusive, variar ao longo da execução do programa.

A predição do número exato de iterações do loop é impossível, dado que é equivalente a resolver o problema da parada (RICE, 1953). Por exemplo, o loop foreach, muito comum em aplicações Java (DYER et al., 2013), itera sobre os elementos das estruturas de dados que implementam a interface Iterable. Desta forma ele percorre a estrutura de dados até o seu fim ou encontrar uma condição de saída. Isto torna difícil predizer quantas vezes esse loop executará, uma vez que o tamanho da estrutura de dados não está explicitamente disponível. A Figura 3.3 apresenta um exemplo real retirado da aplicação Tomcat do uso do foreach, no qual ele itera sobre o conjunto de chaves de um mapa. Vários estudos, por exemplo, (RODRIGUES, 2014), (HEALY et al., 1998), (WU; LARUS, 1994) e (BALL; LARUS, 1993), tratam sobre a predição de loops, no entanto, estes trabalhos estão longe de cobrir todos os possíveis usos dos loops de uma linguagem de alto nível, como Java.

Como abordagens existentes para estimar a número de iterações de um loop normalmente exigem a execução do programa (RODRIGUES, 2014), este trabalho não considera estas aborda- gens, uma vez que o objetivo aqui é analisar o consumo de energia de forma estática. Parte destes trabalhos levam em conta o nível de aninhamento dos loops como uma forma de dar peso às operações que são realizadas dentro de loops. Embora esta abordagem não estipule quantas vezes

3.4. RECOMENDAÇÃO 33

Documents relatifs