O artigo da Wikipedia sobre EPIC já descreveu os muitos perigos comuns ao VLIW e EPIC.
Se alguém não captar o senso de fatalismo desse artigo, deixe-me destacar isso:
As respostas de carregamento de uma hierarquia de memória que inclui caches de CPU e DRAM não possuem um atraso determinístico.
Em outras palavras, qualquer projeto de hardware que não consiga lidar com (*) a latência não determinística do acesso à memória se tornará uma falha espetacular.
(*) Ao "lidar com", é necessário obter desempenho de execução razoavelmente bom (em outras palavras, "competitivo em termos de custo"), o que exige não deixar a CPU ficar ociosa por dezenas a centenas de ciclos com tanta frequência.
Observe que a estratégia de enfrentamento empregada pelo EPIC (mencionada no artigo da Wikipedia vinculado acima) não resolve o problema. Diz apenas que o ônus de indicar dependência de dados agora recai sobre o compilador. Isso é bom; o compilador já possui essas informações, portanto, é simples para ele cumprir. O problema é que a CPU ainda está ociosa por dezenas a centenas de ciclos em um acesso à memória. Em outras palavras, externaliza uma responsabilidade secundária, embora ainda não consiga lidar com a responsabilidade primária.
A questão pode ser reformulada como: "Dada uma plataforma de hardware destinada a ser uma falha, por que (1) não (2) os escritores do compilador não puderam fazer um esforço heróico para resgatá-la?"
Espero que minha reformulação torne a resposta a essa pergunta óbvia.
Há um segundo aspecto da falha que também é fatal.
As estratégias de enfrentamento (mencionadas no mesmo artigo) pressupõem que a pré-busca baseada em software possa ser usada para recuperar pelo menos parte da perda de desempenho devido à latência não determinística do acesso à memória.
Na realidade, a pré-busca só é lucrativa se você estiver executando operações de streaming (lendo a memória de maneira sequencial ou altamente previsível).
(Dito isto, se o seu código fizer acesso frequente a algumas áreas de memória localizada, o armazenamento em cache ajudará.)
No entanto, a maioria dos softwares de uso geral deve fazer muitos acessos aleatórios à memória. Se considerarmos os seguintes passos:
- Calcule o endereço e depois
- Leia o valor e depois
- Use-o em alguns cálculos
Para a maioria dos softwares de uso geral, esses três devem ser executados em rápida sucessão. Em outras palavras, nem sempre é possível (dentro dos limites da lógica do software) calcular o endereço antecipadamente ou encontrar trabalho suficiente para preencher as barracas entre essas três etapas.
Para ajudar a explicar por que nem sempre é possível encontrar trabalho suficiente para encher as bancas, eis como se pode visualizá-lo.
- Digamos que, para ocultar efetivamente as barracas, precisamos preencher 100 instruções que não dependem da memória (portanto, não sofrerão com latência adicional).
- Agora, como programador, carregue qualquer software de sua escolha em um desmontador. Escolha uma função aleatória para análise.
- Você consegue identificar em qualquer lugar uma sequência de 100 instruções (*) que são exclusivamente livres de acesso à memória?
(*) Se pudéssemos NOP
fazer um trabalho útil ...
As CPUs modernas tentam lidar com o mesmo usando informações dinâmicas - rastreando simultaneamente o progresso de cada instrução à medida que circulam pelos pipelines. Como mencionei acima, parte dessas informações dinâmicas se deve à latência não determinística da memória, portanto, não pode ser prevista com precisão pelos compiladores. Em geral, simplesmente não há informações suficientes disponíveis no momento da compilação para tomar decisões que possam preencher essas barracas.
Em resposta à resposta de AProgrammer
Não é que "compilador ... extrair paralelismo seja difícil".
Reordenar a memória e as instruções aritméticas dos compiladores modernos é a evidência de que ele não tem nenhum problema em identificar operações que são independentes e, portanto, executáveis simultaneamente.
O principal problema é que a latência não determinística da memória significa que qualquer "emparelhamento de instruções" codificado para o processador VLIW / EPIC acabará sendo paralisado pelo acesso à memória.
A otimização de instruções que não paralisam (somente registro, aritmética) não ajudará nos problemas de desempenho causados por instruções com grande probabilidade de paralisação (acesso à memória).
É um exemplo de falha na aplicação da regra de otimização 80-20: A otimização de coisas que já são rápidas não melhorará significativamente o desempenho geral, a menos que as coisas mais lentas também estejam sendo otimizadas.
Em resposta a resposta por Basile Starynkevitch
Não é "... (seja o que for) difícil", é que o EPIC é inadequado para qualquer plataforma que precise lidar com alto dinamismo na latência.
Por exemplo, se um processador tiver todo o seguinte:
- Sem acesso direto à memória;
- Qualquer acesso à memória (leitura ou gravação) deve ser agendado por transferência DMA;
- Toda instrução tem a mesma latência de execução;
- Execução em ordem;
- Unidades de execução ampla / vetorizada;
Então VLIW / EPIC será um bom ajuste.
Onde se encontra esses processadores? DSP. E é aqui que o VLIW floresceu.
Em retrospecto, o fracasso do Itanium (e o contínuo despejo dos esforços de P&D em um fracasso, apesar das evidências óbvias) é um exemplo de fracasso organizacional e merece ser estudado em profundidade.
É verdade que os outros empreendimentos do fornecedor, como hyperthreading, SIMD etc., parecem ter grande sucesso. É possível que o investimento no Itanium tenha tido um efeito enriquecedor nas habilidades de seus engenheiros, o que pode ter lhes permitido criar a próxima geração de tecnologia de sucesso.