Existem CPUs que executam essa possível otimização de gravação de cache L1?

9

Quando a CPU com um cache L1 faz uma gravação, o que normalmente acontece é que (assumindo que a linha de cache na qual está gravando já esteja no cache L1) o cache (além de atualizar os dados) marca essa linha de cache como suja , e gravará a linha com os dados atualizados mais tarde.

Uma otimização possível seria fazer com que o cache comparasse o conteúdo da gravação e o conteúdo anterior do cache e, se forem iguais, não marque a linha como suja. Como isso pode permitir que o cache evite retrocessos de vez em quando, posso ver como o fabricante da CPU pode ver isso valendo as portas necessárias para fazer essa lógica.

Minha pergunta: existem CPUs que realizam essa otimização?

Antecedentes do motivo pelo qual estou perguntando: estou escrevendo algum código que precisa ter acesso constante à memória; isto é, alguém que é capaz de ouvir o comportamento do cache não deve deduzir o que estou fazendo. Alguns dos meus acessos são gravações e, da maneira óbvia para implementar esse código, muitas gravações gravam os mesmos dados que já estão lá. Preciso fazer as gravações porque, dependendo dos dados, os dados que estou gravando podem ou não ser os mesmos, e é importante executar a mesma ação independentemente. Se a CPU otimizar realmente não escrevendo uma 'gravação sem alteração', isso significaria que o comportamento do cache variaria dependendo do que estou fazendo, o que subverteria meu objetivo.

Então, existe uma CPU que tenta otimizar as gravações dessa maneira?

poncho
fonte
11
Dizem que existem dois problemas realmente difíceis na ciência da computação: invalidação de cache, nomeação de coisas bem e erros pontuais. Este é um exemplo de por que o primeiro deles é complicado.
Mason Wheeler
@poncho, você diz que "alguém capaz de ouvir o comportamento do cache não deve deduzir o que estou fazendo". Agora, se algumas CPUs implementarem esse recurso de "write-back inteligente" que não invalida o cache, a menos que os dados sejam realmente atualizados, indo um nível mais longe da CPU na hierarquia de memória, seria possível observar o tráfego / tempo diferenças entre gravações reais e gravações fictícias. É com isso que você está preocupado?
TheCodeArtist
@poncho Além disso, sua verdadeira pergunta parece ser sobre a implementação de um modo melhor privilegiado / seguro que não vaze informações de uso. Talvez você devesse perguntar isso ...?
TheCodeArtist
1
@TheCodeArtist: bem, foram publicados ataques criptográficos de canal lateral em que uma rotina de criptografia pode ser atacada por outro programa em execução em um núcleo diferente da mesma CPU, fazendo com que o programa de ataque monitore o cache compartilhado. Acredito que esse programa possa detectar se as linhas de cache L1 foram liberadas e, portanto, deduzir informações sobre o programa em que estou interessado, se a CPU fizer a otimização em discussão. Não estou falando de um 'modo seguro', pois não assumo a capacidade de modificar a CPU ou o SO.
Poncho
4
Mesmo que isso seja verdade hoje, não é garantido que seja verdade amanhã.
Pjc50

Respostas:

4

Após horas de pesquisa, não consegui encontrar uma CPU que use essa otimização específica. A maioria das otimizações mencionadas geralmente está relacionada a acertos / erros com operações de leitura / gravação e acesso a dados:

(páginas 7 e) https://cseweb.ucsd.edu/classes/fa14/cse240A-a/pdf/08/CSE240A-MBT-L15-Cache.ppt.pdf

No entanto, isso não significa que essa otimização não possa ser executada. Em geral, é possível acessar programaticamente o tamanho de uma linha de cache da CPU. Também é possível acessar os valores atuais nos registros de cache - mas é um pouco perigoso fazê-lo. Se você acessar os registros incorretos em um momento ruim, poderá estar violando os relacionados a um programa em execução. Ou você pode inadvertidamente modificar o conteúdo das linhas que você está tentando ler.

Obtendo o valor atual no cache do registro

Além disso, todas as soluções teóricas requerem alguma forma de implementação de software (assembler). O mais próximo que encontrei se refere à arquitetura ARM, que parece permitir a manipulação de cache. Além disso, você também precisa saber o tamanho de uma linha de cache para a CPU desejada. Você pode ler cuidadosamente o conteúdo do cache para um local secundário na memória, em incrementos do tamanho da linha, e compará-lo com os dados que estão prestes a serem gravados nos registradores (ou linhas de cache L1, neste caso).

Ler o conteúdo do cache da CPU

A partir daí, você pode criar um sistema baseado em software que evite regravações idênticas. Embora isso seja um pouco simplificado, é assim porque a solução precisa ser aplicável a qualquer CPU existente.

Outra possibilidade que encontrei relacionada à coerência do cache:

Trecho relevante de um artigo da Wikipedia sobre coerência de acesso

O ponto principal que chamou minha atenção, em relação a esse problema, foi a descrição do Snarfing:

É um mecanismo em que um controlador de cache observa o endereço e os dados na tentativa de atualizar sua própria cópia de um local de memória quando um segundo mestre modifica um local na memória principal. Quando uma operação de gravação é observada em um local em que um cache possui uma cópia, o controlador de cache atualiza sua própria cópia do local da memória snarfed com os novos dados.

Em outras palavras, possivelmente existem mecanismos já existentes. Só que eles podem não ser usados ​​para a otimização que você sugeriu. Você precisaria implementar um software que executasse a comparação de leitura / gravação.

Comunidade
fonte
Também é possível acessar os valores atuais nos registros de cache - mas é um pouco perigoso fazê-lo. Huh, isso não faz sentido. Você quer dizer registros de CPU? Compiler gerado ou escritas à mão do código asm usos registros para valores de retenção que está operando em ...
Peter Cordes
Se você está tentando implementar isso no software, basta que o compilador gere o código que gera, em if (mem != x) { mem = x; }vez de mem = x;. Às vezes, isso é apenas uma otimização para linhas de cache compartilhadas em um programa multithread, porque a gravação interfere na leitura de outros threads.
Peter Cordes
1
"snarfing" não tem nada a ver com isso. É apenas bisbilhotar passivamente. Caches de CPU usam MESI para que eles possam ter caches de write-back coerentes.
Peter Cordes
@ PeterCordes Se você achar minha resposta desagradável, peço desculpas. No entanto, parece que você tem mais conhecimento do que eu sobre o assunto. Então, por que não responder à pergunta você mesmo? Minha resposta foi, obviamente, inadequada para os seus padrões ...
3

Gravar no cache L1 é uma operação muito, muito crítica.

Escrever exatamente os mesmos dados de volta parece ser bastante raro. Uma otimização que acelera as coisas nesse caso específico não terá muita aceleração no total.

Por outro lado, essa otimização requer uma comparação de dados antigos e novos em cada gravação na memória cache. O que piora isso é que ele exige que os dados a serem gravados estejam realmente disponíveis no momento da gravação!

Isso geralmente não é o caso em uma CPU moderna. Os dados a serem gravados ainda podem estar sendo calculados, por exemplo. O cache ainda pode prosseguir, carregar a linha de cache, se necessário, marcar a linha de cache como modificada e assim por diante, mesmo antes de o cálculo ser concluído. Toda a contabilidade já pode ser executada, exceto a modificação real da linha de cache. Se você deseja comparar resultados recém-gravados e dados antigos da linha de cache, isso não é possível.

Como exemplo, se você tiver o código C a [i] = x / y; a divisão x / y leva um tempo extraordinário para ser executada na maioria das CPUs. No entanto, a maior parte do trabalho necessário para armazenar o resultado em um [i] aconteceu muito antes da divisão terminar; a única coisa que falta é a movimentação de oito bytes de resultado para a linha de cache. Uma operação que libera a linha de cache espera automaticamente até que a divisão seja concluída. Uma operação que lê um [i] provavelmente será redirecionada para obter o resultado direto do divisor.

gnasher729
fonte
Um cache usando o MESI para coerência ainda pode fazer a RFO, mas se os dados forem comparados da mesma forma quando estiverem prontos, deixe a linha no estado Exclusivo em vez de Modificado. O verdadeiro motivo para isso não ser feito no hardware é que ele custa leituras extras de cache à medida que os dados se comprometem com o cache, e exigiria uma espécie de ciclos atômicos de leitura / comparação / gravação (com configuração opcional do bit sujo) que faz com que seja uma tarefa difícil. implementação em pipeline.
Peter Cordes
1

Uma otimização possível seria fazer com que o cache comparasse o conteúdo da gravação e o conteúdo anterior do cache e, se forem iguais, não marque a linha como suja

Essa otimização não dobrará o tempo que a CPU precisa para gravar algo no cache? Como cada gravação de linha de cache agora será acompanhada de uma operação de comparação, que não é gratuita.

Portanto, atualmente a otimização dependerá do fator muito vago: quantas vezes um software médio reescreve sua memória armazenável em cache com os mesmos dados.

Vladislav Rastrusny
fonte
Essa comparação seria implementada dentro da lógica da CPU. Não exigiria uma operação adicional da CPU, mas o tempo do sinal pode aumentar, o que pode ser um problema ou não.
Ziggystar
@ ziggystar Bem, eu não sou um mestre em hardware, mas me acostumei com o pensamento de que tudo tem um custo. O mesmo compara a operação com a linha de cache. Pode ser rápido. Mas isso ainda é custo. E acho que os implementadores decidiram não pagar. Pode acontecer mesmo depois de pensar e medir.
Vladislav Rastrusny
1
Mas você está falando de tempo, onde o custo pode ser apenas um aumento no número de portões.
Ziggystar #
1
@ ziggystar: Este não é apenas mais portões. Quando os dados são enviados para o cache, normalmente o processo de envio dos dados pode marcar a linha do cache como modificada. Com essa "otimização", os dados antigos e os novos devem passar por esses portões, o que causará algum atraso, e somente então o cache poderá ser invalidado. Você precisa compactar tudo isso em um ciclo do processador; caso contrário, a gravação em uma linha de cache leva subitamente dois ciclos. E agora, para tornar as coisas mais complicadas, considere o que acontece quando escrevo oito palavras consecutivas em uma linha de cache.
gnasher729
1
E cada uma dessas gravações atrasa a decisão de a linha de cache ser modificada. Portanto, quando a segunda gravação acontece, a linha de cache não sabe se está modificada ou não (ainda). Isto vai ser divertido.
gnasher729