Exercício 4 - Avaliando o impacto do subsistema de memória

Motivação

Objetivos

Esse exercício vai ser dividido em partes e, ao final delas, vocês devem ser capazes de:

Atenção: Este exercício, assim como todos os demais, é individual. Isto significa que você não pode, em hipótese alguma, olhar o código de um de seus colegas. Você pode tirar dúvidas longe do computador ou pedir auxílio ao professor.

Antes de começar

Até agora, você já avaliou o desempenho dos programas considerando as informações disponíveis internamente no simulador. Agora você precisa capturar as informações sobre a hierarquia de memória. Procure pensar em respostas para as seguintes perguntas (não precisa colocá-las no seu relatório):

Atenção: Todos os arquivos que você precisa para essa atividade estão disponíveis em /home/staff/rodolfo/mc723/download.

Pré-atividade: Usando uma plataforma virtual

Uma plataforma virtual é um software capaz de simular um hardware com um bom nível de detalhes. Geralmente não é necessário modificar programas que rodam nesta plataforma virtual para executá-los numa plataforma real (hardware). Alguns componentes existentes em plataformas reais não aparecem nas versões virtuais para não afetar o desempenho. Outros componentes aparecem com versões bastante simplificadas. Entranto, dificilmente o software que está executando nesta plataforam virtual deve ser capaz de notar esta diferença. Como exemplos destes componentes que podem aparecer de forma diferente temos: caches (que pode não existir), periféricos (que podem apenas emular o que deveriam fazer), etc.

Vocês usarão, neste exercício, o pacote ARP (ArchC Reference Plataform) para gerenciar plataformas. Ele será exatamente o mesmo pacote que vocês utilizarão durante o restante do semestre para realizar os demais experimentos. A ARP nada mais é que um conjunto de Makefiles e uma estrutura de diretórios para facilitar o desenvolvimento de projetos maiores. Cada diretório tem um conteúdo específico:

Pegue a plataforma de exemplo (arp-rodolfo.tgz), descompacte-a e navegue pelos diretórios observando o conteúdo de cada um deles. Embora exista uma versão da ARP descompactada no meu homedir, vocês devem começar com a versão vazia indicada acima. Para executar a plataforma, basta utilizar os comandos:

make
make run

O primeiro comando compila a plataforma e o segundo executa. Se for necessário compilar o programa, você deve utilizar o compilador instalado em /l/archc/compilers/bin da máquina xaveco (o compilador está apenas nela, você pode executar os programas compilados em qualquer outra máquina, mas os compiladores para MIPS estão apenas na xaveco). Para facilitade, inclua o caminho anterior no PATH antes de executar os dois comandos acima.

Este simulador é mais lento que o anterior por conter mais componentes que você estava acostumado.

Você consegue executar outro programa? Você precisa criar um diretório na pasta sw e configurar também o arquivo defs.arp da pasta da plataforma.

Inserir um roteador entre o processador e a plataforma

Utilizando como base a plataforma acima, você deve incluir um roteador entre o processador e a memória. O código deste roteador deve ser colocado na pasta is da plataforma. Utilize um dos programas do exercício 3.

Veja um pouco mais de detalhes a seguir, sobre a plataforma, antes das recomendações para seu código.

Sua primeira plataforma possuia apenas dois módulos: um processador e uma memória. Agora é hora de incluir um terceiro módulo, o roteador, que fará o papel de barramento do sistema. Ele está sendo chamado de roteador pois não implementará as funcionalidades de contenção de tráfego de um barramento, nem algumas outras funcionalidades interessantes. Então vocês trabalharão com algo simplificado neste momento.

A comunicação entre o processador e a memória se faz através do padrão TLM que, basicamente, realiza a ligação entre os componentes do sistema. Só que o padrão TLM é ponto a ponto, exigindo uma porta de cada lado para cada canal de comunicação. Além disto, o TLM inclui o conceito de mestre e escravo, onde o mestre sempre faz as solicitações e o escravo apenas as atende. No caso original, o processador é o mestre e a memória é escravo. O grande problema desta configuração inicial é a dificuldade em incluir um novo periférico, pois será necessário modificar o processador para que ele se comunique com dois dispositivos diferentes. Assim, a solução é inluir um periférico no meio do caminho que apenas fará o papel de roteamento, este é o roteador que você vai fazer.

Do ponto de vista do TLM, as conexões são feitas sempre entre portas, o processador tem uma porta Mestre e a memória tem uma porta Escravo. No programa principal (main.cpp da plataforma), você vê a ligação entre o processador e a memória através da linha:

mips1_proc1.DM_port(mem.target_export);

esta linha liga a porta DM_port do processador à porta target_export da memória. Olhando um pouco antes neste código, você pode ver a declaração do processador mips1_proc1 e da memória mem. Sua tarefa é criar um novo componente, chamado roteador, que será conectado a mips1_proc1 e também à mem. Para isto, ele precisará ser Escravo na sua conexão com o processador e Mestre na sua conexão com a memória. Além disto, todas as solicitações do processador devem ser transferidas para a memória neste momento.

A forma mais simples de implementar este roteador é começar pelo código da memória, removendo a parte relacionada ao armazenamento de dados e incluindo a parte da conexão Mestre que você poderá seguir o exemplo do código do processador (procure pela declaração da classe mips1). você trabalhará sempre ao redor e na implementação do método transport.

É esperado, nesta atividade, que você localize e monte o código correto do seu roteador. Todos os exemplos de código fonte já estão dados.

Inserindo uma cache entre o processador e o roteador

Parte 1: Preparando o processador para receber a cache

Você terá que realizar uma pequena alteração no código do processador para criar um segundo canal de comunicação com a memória já que vamos tratar da cache de instruções e também da cache de dados. No início do código do processador, existe uma declaração da forma ac_tlm_mem DM:5M;. Esta linha declara uma porta de comunicação externa com o nome DM e define o intervalo válido de valores (para programas) de 5MB. Você já deve ter relacionado o nome DM ao DM_port que tanto utilizou na parte anterior do exercício. O sufixo _port é adicionado a todas as portas declaradas desta forma (qualquer que for o nome, externamente ao processador, ele terá o sufixo). O ArchC considera a última porta declarada como o local onde o programa lido do disco será colocado (não se preocupe com isto) e, consequentemente, de onde as instruções serão lidas (esta parte é importante). Então, se você declarar duas ac_tlm_port, o programa será lido do disco e colocado na última porta declarada (esta não é a melhor forma de definir uma linguagem mas é assim que está implementado hoje).

Sua meta, nesta parte, é incluir outra porta (deixar o processador com duas portas de saída) e manter o simulador funcionando. As duas portas distintas serão utilizadas para separar os acessos às caches de instruções e de dados. Você deve se preocupar com os seguintes detalhes:

Parte 2: Incluindo a cache na plataforma

Agora é a hora de projetar uma cache. Olhando bem do alto nível, a cache serve para guardar dados que garantidamente estão na memória mas que têm sido frequentemente utilizados.

Sua cache deve ser configurável. Deve ser possível definir, em tempo de compilação:

O tamanho do bloco, como você já deve saber, tem que ser um múltiplo do tamanho da palavra do processador. Tanto o número de vias quanto o número de linhas devem ser maiores que zero.

Sua primeira versão da cache deve ter política write through pois é mais fácil de implementar. Também por facilidade de implementação, a política de substituição pode ser round robin com um único contador global por cache, desde que não existam blocos inválidos na cache (primeiro procure por um bloco inválido, se não encontrar, substitua um escolhido pelo round robin).

Um bom ponto de partida para sua cache é o roteador do início deste exercício, numa versão com apenas uma entrada e uma saída. Inclua uma cache de dados e uma cache de instruções na sua plataforma, teste com o programa hello world com vários parâmetros diferentes para certificar-se de que o funcionamento está ok. (sua cache deve ficar no diretório IP da ARP).

Programe sua cache para coletar estatísticas de hits e misses. Imprima estas estatísticas antes de encerrar o programa. Utilize o destrutor da classe da cache para realizar a impressão.

Como ficou o desempenho do simulador? Faz sentido?

Atenção: O processador MIPS que vocês estão utilizando faz acesso desalinhado à memória (isto significa que sua cache vai receber solicitações de leitura a endereços que não são múltiplos de 4). Isto não deveria acontecer, mas é um problema de implementação (bug) no modelo do processador. Você não precisa corrigir este bug, apenas esteja ciente desta requisição e trate corretamente na sua cache.

Parte 3 - Avaliando as caches

Como escolher a melhor cache? Para caches L1, são esperadas taxas de misses da ordem de 2% a 5%.

Você deve avaliar a melhor configuração de cache para o programa que você escolheu no exercício 3. Para isto, execute o programa diversas vezes, com configurações diferentes de caches de instruções e dados (elas podem ser diferentes entre si!) e escolha a melhor configuração. Coloque todas as configurações que você buscar no seu relatório, juntamente com a taxa de misses, indicando a direção da pesquisa. Atenção: No início da execução, o simulador lê o programa do disco e grava na memória, você não pode contabilizar estes primeiros acessos.

Dica: Utilize o conceito dos 3Cs das caches para te auxiliar na procura pela melhor configuração.

Atenção: O simulador utiliza uma cache de decodificação de instruções internamente. Esta é uma otimização que pode ser desligada através da opção -ndc do acsim.

Suponha que um acesso à memória principal tenha custo de 100 ciclos e um acesso à cache L1 seja instantâneo (seu custo já está computado no pipeline). Recalcule o número de ciclos gasto para executar seus 3 programas utilizando esta métrica e os dados do exercício 3.

Parte 4 - Avaliando uma cache L2 (opcional valendo bônus)

Com a melhor configuração que encontrou para as caches L1, agora inclua uma cache L2 e ache a melhor configuração para ela. Neste momento, seu miss deve ficar entre 1% e 2%. A cache L2 é unificada, não existe diferença entre instruções e dados nela.

Suponha que o acesso à cache L2 tenha custo de 10 ciclos. Recalcule o tempo de execução dos seus programas (numa nova coluna).

Entrega

Enviar um relatório de apenas 2 páginas descrevendo a atividade realizada e os resultados obtidos.