Escrevendo algoritmos DSP diretamente em C ou assembly? [fechadas]

18

Estou trabalhando em um projeto DSP (filtragem IIR) em um processador de sinal digital da Analog Devices (BF706) com o conjunto de compiladores que vem com ele, o CrossCore Studio. Ele contém alguns exemplos de itens DSP simples, como filtros FIR e IIR e funções de biblioteca. O manual do processador descreve o conjunto de instruções de montagem e não comenta sobre C.

Minha pergunta surge dessa aplicação específica, mas achei que havia uma prática recomendada que os desenvolvedores do DSP seguem. Então, eu vou enquadrar de uma maneira geral:

O que percebi pelos exemplos que acompanham este DSP é que, se eu quiser usar os circuitos projetados para aplicativos DSP, preciso programar em montagem para executar diretamente essas instruções (como multiplicar e adicionar, etc.). Eu apenas programa em C, o compilador (que também vem da empresa de chips DSP) não o otimizaria para esse DSP e usaria seus recursos? Ou eu realmente preciso escrever rotinas DSP diretamente na montagem?

doubleE
fonte
17
Passei muitos anos escrevendo assembléias para o ADSP-21xx (e assemblagens e C para o Blackfin, mais tarde). Você não divulga o que está usando, então qualquer resposta será mais um palpite e opinião do que qualquer outra coisa. Mas os processadores DSP do AD são muito bons e é muito difícil para os escritores do compilador C preencher o cano corretamente, por assim dizer. Eu tenho duas décadas de experiência nessa área (incluindo alguma experiência muito modesta ao escrever um compilador C) e até o momento em que parei de escrever código (alguns anos atrás), os compiladores C não podiam chegar perto da codificação manual. Mas o que você faz depende de seus objetivos.
21417
11
@jonk espero que você vai escrever uma resposta a este - eu só fiz um incondicional projeto DSP Blackfin, mas tenho boas recordações de alguns dos hacks de desempenho que precisava :)
pericynthion
6
@pericynthion Não, não consigo imaginar escrever uma resposta a menos que o OP fale MUITO mais sobre o DSP específico e os objetivos do projeto. Caso contrário, seriam opiniões vagas e não orientadas que podem estar muito certas ou muito erradas, dependendo do que o OP escreveu sobre isso. Então eu vou esperar.
21417
11
Se você deseja executar o mais rápido, você pode otimizá-lo manualmente na montagem. Essa é uma troca de tempo \ dinheiro. Se você sabe escrever um bom C, pode percorrer a maior parte do caminho até lá.
Voltage Spike
2
Não tenho certeza sobre o DSP, mas para a maioria dos microprocessadores, você pode usar intrínsecos, que estão a meio caminho entre escrever assembler e código C.
Maciej Piechotka 01/08/19

Respostas:

20

É sempre melhor ter seu algoritmo implementado em uma linguagem de nível superior (que C é comparado ao assembly), mesmo que você planeje implementar tudo no assembly no final.

  • é provável que você nem precise de montagem . Se o código gerado pelo seu compilador atender aos seus objetivos de design, seu trabalho estará concluído.

  • caso contrário, você não iniciará a codificação da montagem do zero . Deixe o compilador gerar o código inicial para você e use-o como base para sua versão de montagem otimizada.

  • mais tarde, quando você precisar testar seu código de montagem otimizado , ficará feliz em ter a versão C. Em vez de calcular manualmente a saída correta para os dados de entrada de teste, você pode apenas alimentar esses dados com a implementação C não otimizada e verificar se a montagem produz exatamente a mesma saída após as otimizações que você fez.

Se, após alguns anos, um novo desenvolvedor precisar fazer modificações no seu algoritmo e tudo o que eles tiverem em mãos for um código de montagem altamente otimizado, há uma grande chance de que eles tenham que começar do zero.

Dmitry Grigoryev
fonte
23

Se os escritores do compilador se esforçarem para otimizá-lo para esse destino, ele fará pelo menos algum uso das instruções / arquitetura especiais do DSP. Mas, para obter o melhor desempenho, nunca será tão bom quanto a montagem ajustada à mão. Porém, pode ser bom o suficiente - depende da sua aplicação.

Outras alternativas incluem:

  1. Escreva a maioria do seu programa em C e apenas a parte numérica mais crítica da montagem.
  2. Escreva o programa em C e use as bibliotecas fornecidas pelo fabricante ou por terceiros - se você estiver executando tarefas DSP comuns, como FFTs, filtros FIR / IIR etc. alguém provavelmente já escreveu o código da máquina ajustado manualmente para fazê-lo, para que você você pode usá-lo (pode ter que pagar por isso) e vinculá-lo ao seu aplicativo.
pericynthion
fonte
Geralmente, os fornecedores de DSP fornecem o código-fonte para as funções comuns. Se o código deles for "bom o suficiente", você poderá inseri-lo. Se não estiver certo, será necessário ajustá-lo. Eu tive que fazer uma camada de FFT alguns anos atrás, para obter uma FFT real apenas de frequência. Existe um truque que permite fazer uma FFT real de 2N pontos como uma FFT complexa de ponto N, mas é preciso fazer uma passagem final sobre a saída complexa para recuperar os dados de frequência real. A Analog Devices não tinha esse caso específico em seu código de exemplo.
John R. Strohm
21

Otimização prematura é a raiz de todo o mal. - Donald Knuth

Quando você achar que não obtém desempenho suficiente do seu código, analise primeiro o seu programa, encontre os gargalos, analise seus requisitos de desempenho e só então comece a fazer otimizações. Escrever código de montagem é o último recurso.

Minha pergunta é: se eu apenas programa em C, o compilador (que também vem da empresa de chips DSP) não o otimiza para esse DSP e usa seus recursos?

Sim, o compilador C pode fazer uma boa quantidade de otimização. Mas isso depende da qualidade do compilador. Freqüentemente, um humano pode escrever um código de montagem mais rápido que o código C compilado. Com grande despesa de dor e sofrimento humano, isso é.

Ou eu realmente preciso escrever rotinas DSP diretamente na montagem?

Primeiro escreva em C, depois perfil e, em seguida, decida se você precisa escrever na montagem. Felizmente, você não precisaria da montagem.

Nick Alexeev
fonte
20
Na programação geral, esse é certamente um bom conselho, mas o DSP é um pouco diferente - se o OP realmente quiser fazer uso eficiente de um DSP, provavelmente precisará haver algum código manuscrito em algum lugar ao longo da linha. E, de fato, com projetos DSP, às vezes você quer começar escrevendo esse núcleo numérico principal, para validar que o processador será adequado para a tarefa em questão.
pericynthion
11
Sua declaração final é um bom conselho geral. Mas é meio pálido ao considerar os detalhes específicos das ALUs do AD DSP. Acho que você nunca os examinou.
21417
18

Seu DSP será anunciado com um máximo de MACs sustentados, assumindo que todos os pipes estejam preenchidos. Obviamente, esse é um limite superior ao que pode ser alcançado. Você sabe quantos MACs seus filtros e outros processamentos levarão da sua análise. Procure ter o primeiro pelo menos duas vezes o segundo, pois você não conseguirá manter o núcleo do DSP no máximo. Assim como você não tentaria preencher um FPGA acima de 70% do recurso (o PAR fica muito lento acima disso), o desenvolvimento pode ficar muito lento tentando extrair os últimos MACs teóricos de um DSP.

Você codificará todo o seu aplicativo em C. É impraticável escrever todo o material extra necessário em montador, injeção e visibilidade de teste, limpeza, etc. Escreva uma versão em C do filtro de teste. Escreva uma versão assembler do mesmo filtro, para verificar se você realmente pode escrever assembler para este animal.

Agora faça alguns intervalos. Use um RTOS aprovado pelo fornecedor. Compare o tempo de execução do seu módulo assembler de teste com uma versão C. Se eles estiverem dentro de alguns por cento, siga em frente. Se for triplo, leia a documentação, teste o fornecedor e descubra por que o compilador não o está ajustando. Pode ser necessário aprender a escrever seu sabor C, tanto quanto definir os sinalizadores corretos do compilador, será mais rápido descobrir como dirigir o compilador corretamente do que reescrever tudo no assembler.

Você já fez tudo isso antes de se comprometer com um DSP, com uma cadeia de ferramentas.

Depois de ter uma cadeia de ferramentas com a qual você pode trabalhar, um compilador com o qual você pode ajustar para ficar razoavelmente próximo do máximo, um DSP com algum espaço de tempo restante, então você pode estar razoavelmente confiante de que poucas partes do seu conjunto de códigos precisarão ser inseridas montador para concluir o trabalho.

Neil_UK
fonte
7

Mesmo que eu já tenha respondido a essa pergunta, adicionarei outra resposta para ilustrar um ponto de vista diferente:

Escreva em C, leia na montagem!

Portanto, em vez de escrever em assembly, você escreverá a lógica em C, certificando-se cuidadosamente de que a saída do código C do assembler seja ótima. Muitas vezes, você pode executar certos truques no código C para afetar a saída do assembler. Use funções embutidas estáticas quando isso fizer sentido. Se você precisar usar algumas instruções especiais suportadas pelo DSP, faça uma abstração estática da função em linha da instrução especial e chame a instrução especial usando a abstração.

Embora eu deva dizer que nunca programei DSPs, essa abordagem de escrever o código C enquanto observa cuidadosamente o assembly compilado funcionou extremamente bem para mim em máquinas x86. Tão bem, na verdade, que nunca precisei escrever nada em montagem para obter o melhor desempenho possível. Em vez de otimizar o código de montagem, modificarei o código C de maneira que a montagem seja ótima.

Obviamente, isso depende da disponibilidade de bons compiladores C. Para x86, esses compiladores estão disponíveis (você geralmente precisa especificar um nível de otimização mais alto que o padrão). Para os DSPs, sinceramente não sei se os compiladores são tão bons.

O benefício dessa abordagem é que você tem uma única base de código portátil, otimizada para resultar em uma montagem ideal para um determinado DSP, mas funciona também se o DSP for alterado para outra coisa. É claro que você pode precisar ajustar levemente o código C para obter o melhor desempenho possível no novo DSP.

juhist
fonte
Tenho uma pergunta sobre isso: trabalho nos processadores STM32F4 Cortex-M4 e uso as bibliotecas CMSIS / Cube. Eu também uso o sinalizador -O3 do compilador, porque ele provou ser eficiente do que qualquer coisa que eu pudesse produzir. O problema é que o assembly compilado é sempre muito caótico para uma análise adequada. Você sempre compila sem otimização do compilador? Ou você consegue entender a véspera da assembléia, se estiver em todo lugar?
Florent
2
@ FlorentEcochard: Se o montador do compilador não puder ser entendido por um programador, provavelmente será melhor do que o montador que esse programador pode escrever. Como resposta direta à sua pergunta: use a otimização máxima e a análise manual do montador, peças difíceis podem ser educativas.
pasaba por aqui
4

Em geral, não é necessário escrever fontes do assembler se:

  • você otimiza C nas seções críticas: um bom uso da palavra-chave "register", funções em linha, ...
  • pode haver algumas funções do programa C usando blocos asm

Isso significa revisar manualmente o assembler gerado pelo compilador C (para as partes críticas) e modificar a fonte até um nível suficiente de otimização.

pasaba por aqui
fonte
Praticamente todos os compiladores modernos ignoram a palavra-chave "register", independentemente da plataforma. É muito improvável que seja usado um código melhor.
Kef Schecter
@KefSchecter: eles não apenas levam em consideração a dica do registro, mas também permitem selecionar o registro a ser usado: gcc.gnu.org/onlinedocs/gcc-6.1.0/gcc/…
pasaba por aqui
11
@ KefSchecter: exceto para compiladores criados para dispositivos incorporados, onde é uma palavra-chave muito importante se você estiver programando em bare metal.
vsz
@pasabaporaqui: Eu esqueci esse pouco de sintaxe. Mas se você não especificar um nome de registro - em outras palavras, se você o usar da maneira padrão ISO - aposto que o GCC o ignorará.
Kef Schecter
3

Eu diria aqui que, se você faz filtros FIR / IIR, é muito mais importante qual algoritmo você usa (o algoritmo trivial versus a transformada rápida de Fourier (FFT)) do que qual idioma você usa (C versus assembly).

Eu escreveria FFT na montagem? Provavelmente não.

Eu mesmo escreveria FFT? A resposta para isso também provavelmente não é, pois a FFT já foi implementada muitas vezes. Então é provável que você encontre alguma biblioteca que já tenha a FFT implementada. Considerando que C é uma linguagem portátil, enquanto o assembly não é, é muito mais provável que você encontre bibliotecas existentes já implementadas em C.

Se você deseja o desempenho mais extremo possível, obviamente pode ajustar manualmente um algoritmo FFT para funcionar o mais rápido possível na linguagem assembly. Mas realmente não acredito que faça sentido, exceto em circunstâncias muito excepcionais.

juhist
fonte
2

Na minha opinião, o FWIW é que sempre que você deseja velocidade / eficiência / taxa de transferência máximas, o montador é seu amigo, desde que você seja proficiente. Um compilador é burro; ele "sabe" apenas o que o autor pensou programar nele e o autor não conhecia sua aplicação.

Devo admitir que adoro assembler desde o início dos anos 80 micros de 8 bits (não muito diferentes dos MCUs modernos em muitos aspectos) em que aprender "código de máquina" era um pré-requisito para obter qualquer desempenho útil deles, mas acho que seu papel permanece como a maneira de programar para obter a máxima eficiência. Além disso, é altamente gratificante, pois você pode usar todos os tipos de atalhos de otimização que um compilador não pensa, porque um compilador não consegue pensar.

C está bem, eu acho. Mas se você realmente sabe o que deseja que sua máquina faça no nível do hardware, vá em assembler.

Ian Bland
fonte