Na grande maioria dos casos, melhorias nos algoritmos fazem uma diferença maior do que melhorias na otimização. Os algoritmos também são mais portáteis que as otimizações de baixo nível. Meu conselho é seguir as práticas recomendadas gerais em relação ao layout da memória para reutilização do cache, evitando cópias ou comunicação excessivas, tratando o sistema de arquivos de maneira sadia e fazendo com que os kernels de ponto flutuante tenham granularidade suficiente para vetorização. Às vezes, isso é suficiente para atingir uma fração aceitavelmente alta de "pico" (para esta operação).
Sempre esboce um modelo de desempenho para operações que você considera importantes (ou que você descobre serem importantes por criação de perfil). Em seguida, você pode usar o modelo de desempenho para estimar o que uma implementação altamente ajustada poderia oferecer. Se você decidir que a aceleração vale a pena (em relação às outras coisas que você poderia estar fazendo), faça a otimização.
Talvez o desafio mais difícil seja projetar interfaces e estruturas de dados importantes e de alto nível (no sentido de que muito código dependerá dessas opções) para que você possa otimizar mais tarde sem precisar alterar a API. Ao contrário de otimizações específicas e diretrizes gerais, não sei como ensinar isso, exceto através da experiência. Trabalhar com software de código aberto sensível ao desempenho ajuda. Como em qualquer decisão da API, é importante entender o espaço do problema.