Tolerância de latência
A velocidade dos microprocessadores aumentou em mais de um fator de dez por década, mas a velocidade das memórias commodity (DRAMs) apenas dobrou, ou seja, o tempo de acesso caiu pela metade. Portanto, a latência de acesso à memória em termos de ciclos de clock do processador aumenta seis vezes em 10 anos. Os multiprocessadores intensificaram o problema.
Em sistemas baseados em barramento, o estabelecimento de um barramento de alta largura de banda entre o processador e a memória tende a aumentar a latência de obtenção dos dados da memória. Quando a memória é distribuída fisicamente, a latência da rede e da interface de rede é adicionada àquela do acesso à memória local no nó.
A latência geralmente aumenta com o tamanho da máquina, à medida que mais nós implicam em mais comunicação em relação à computação, mais salto na rede para comunicação geral e provavelmente mais contenção. O principal objetivo do design de hardware é reduzir a latência do acesso aos dados, mantendo uma largura de banda alta e escalonável.
Visão geral da tolerância à latência
A maneira como a tolerância à latência é tratada é melhor compreendida observando os recursos na máquina e como eles são utilizados. Do ponto de vista do processador, a arquitetura de comunicação de um nó para outro pode ser vista como um pipeline. Os estágios do pipeline incluem interfaces de rede na origem e no destino, bem como nos links de rede e switches ao longo do caminho. Existem também estágios no assistente de comunicação, o sistema de memória / cache local e o processador principal, dependendo de como a arquitetura gerencia a comunicação.
O problema de utilização na estrutura de comunicação da linha de base é que o processador ou a arquitetura de comunicação estão ocupados em um determinado momento e, no pipeline de comunicação, apenas um estágio está ocupado por vez, pois a única palavra sendo transmitida faz seu caminho da origem ao destino. O objetivo da tolerância à latência é sobrepor o uso desses recursos o máximo possível.
Tolerância de latência na passagem explícita de mensagens
A transferência real de dados na passagem de mensagens é normalmente iniciada pelo remetente, usando uma operação de envio. Uma operação de recebimento não motiva por si só os dados a serem comunicados, mas sim copia os dados de um buffer de entrada para o espaço de endereço do aplicativo. A comunicação iniciada pelo receptor é feita através da emissão de uma mensagem de solicitação para o processo que é a fonte dos dados. O processo então envia os dados de volta por meio de outro envio.
Uma operação de envio síncrono tem latência de comunicação igual ao tempo que leva para comunicar todos os dados na mensagem ao destino, e o tempo para o processamento de recebimento e o tempo para o retorno de uma confirmação. A latência de uma operação de recepção síncrona é sua sobrecarga de processamento; que inclui a cópia dos dados para o aplicativo e a latência adicional caso os dados ainda não tenham chegado. Gostaríamos de ocultar essas latências, incluindo overheads, se possível, em ambas as extremidades.
Tolerância de latência em um espaço de endereçamento compartilhado
A comunicação da linha de base é feita por meio de leituras e gravações em um espaço de endereço compartilhado. Por conveniência, é chamada de comunicação de leitura e gravação. A comunicação iniciada pelo receptor é feita com operações de leitura que resultam no acesso aos dados da memória ou cache de outro processador. Se não houver cache de dados compartilhados, a comunicação iniciada pelo remetente pode ser feita por meio de gravações nos dados alocados em memórias remotas.
Com a coerência do cache, o efeito das gravações é mais complexo: a gravação leva ao remetente ou a comunicação iniciada pelo receptor depende do protocolo de coerência do cache. Iniciada pelo receptor ou pelo remetente, a comunicação em um espaço de endereço compartilhado de leitura e gravação com suporte de hardware é naturalmente refinada, o que torna a latência de tolerância muito importante.
Bloquear transferência de dados em um espaço de endereçamento compartilhado
Em um espaço de endereço compartilhado, seja por hardware ou software, a união de dados e o início de transferências de bloco podem ser feitos explicitamente no programa do usuário ou de forma transparente pelo sistema. As transferências de blocos explícitas são iniciadas pela execução de um comando semelhante a um envio no programa do usuário. O comando de envio é explicado pelo assistente de comunicação, que transfere os dados de uma maneira pipeline do nó de origem para o destino. No destino, o assistente de comunicação puxa as palavras de dados da interface de rede e as armazena nos locais especificados.
Existem duas diferenças principais na passagem de mensagens de envio e recebimento, ambas surgindo do fato de que o processo de envio pode especificar diretamente as estruturas de dados do programa onde os dados devem ser colocados no destino, uma vez que esses locais estão no espaço de endereço compartilhado .
Processamento de eventos passados de longa latência em um espaço de endereçamento compartilhado
Se a operação de memória for feita sem bloqueio, um processador pode prosseguir após uma operação de memória para outras instruções. Para gravações, isso geralmente é bastante simples de implementar se a gravação for colocada em um buffer de gravação e o processador continuar enquanto o buffer se encarrega de emitir a gravação para o sistema de memória e rastrear sua conclusão conforme necessário. A diferença é que, ao contrário de uma gravação, uma leitura geralmente é seguida muito em breve por uma instrução que precisa do valor retornado pela leitura.
Pré-comunicação em um espaço de endereçamento compartilhado
A pré-comunicação é uma técnica que já foi amplamente adotada em microprocessadores comerciais e sua importância tende a aumentar no futuro. Uma instrução de pré-busca não substitui a leitura real do item de dados, e a própria instrução de pré-busca deve ser não bloqueadora, se quiser atingir seu objetivo de ocultar a latência por meio da sobreposição.
Nesse caso, como os dados compartilhados não são armazenados em cache, os dados pré-buscados são trazidos para uma estrutura de hardware especial chamada buffer de pré-busca. Quando a palavra é realmente lida em um registrador na próxima iteração, ela é lida do cabeçalho do buffer de pré-busca ao invés da memória. Se a latência para ocultar fosse muito maior do que o tempo para calcular a iteração de loop único, faríamos a pré-busca de várias iterações à frente e haveria potencialmente várias palavras no buffer de pré-busca por vez.
Multithreading em um espaço de endereçamento compartilhado
Em termos de ocultar diferentes tipos de latência, multithreading suportado por hardware é talvez a técnica versátil. Ele tem as seguintes vantagens conceituais sobre outras abordagens -
Não requer análise de software especial ou suporte.
Como é chamado dinamicamente, ele pode lidar com situações imprevisíveis, como conflitos de cache, etc., assim como outras previsíveis.
Como a pré-busca, ele não altera o modelo de consistência de memória, uma vez que não reordena os acessos em um encadeamento.
Embora as técnicas anteriores tenham como objetivo ocultar a latência de acesso à memória, o multithreading pode potencialmente ocultar a latência de qualquer evento de longa latência com a mesma facilidade, contanto que o evento possa ser detectado no tempo de execução. Isso inclui sincronização e latência de instrução também.
Essa tendência pode mudar no futuro, pois as latências estão se tornando cada vez mais longas em comparação com as velocidades do processador. Além disso, com microprocessadores mais sofisticados que já fornecem métodos que podem ser estendidos para multithreading e com novas técnicas de multithreading sendo desenvolvidas para combinar multithreading com paralelismo de nível de instrução, essa tendência certamente parece estar passando por alguma mudança no futuro.