Pergunta

O que é a diferença entre o acesso à memória alinhada e não alinhada?

Eu trabalho em um TMS320C64x DSP, e eu quero usar as funções intrínsecas (funções C para instruções de montagem) e tem

ushort & _amem2(void *ptr);
ushort & _mem2(void *ptr);

onde _amem2 faz um acesso alinhadas de 2 bytes e _mem2 faz o acesso não alinhado.

Quando devo usar o que?

Foi útil?

Solução

Um meio de memória de acesso alinhadas que o ponteiro (como um número inteiro) é um múltiplo de um valor específico do tipo chamado de alinhamento. O alinhamento múltiplo é o endereço natural onde o tipo deve ser, ou deve ser armazenado (por exemplo, por motivos de desempenho) em uma CPU. Por exemplo, uma CPU pode exigir que todas as cargas de dois bytes ou lojas são feitas através de endereços que são múltiplos de dois. Para pequenos tipos de primitivas (com menos de 4 bytes), o alinhamento é quase sempre o tamanho do tipo. Para estruturas, o alinhamento é geralmente o alinhamento máximo de qualquer membro.

O compilador C sempre coloca variáveis ??que você declara em endereços que satisfaçam o alinhamento "correto". Então, se ptr aponta para, por exemplo, uma variável uint16_t, ele será alinhado e você pode usar _amem2. Você precisa usar _mem2 somente se você está acessando por exemplo uma matriz de bytes embalado recebido através de I / O, ou bytes no meio de uma cadeia de caracteres.

Outras dicas

Muitas arquiteturas de computador armazenar a memória em "palavras" de vários bytes cada. Por exemplo, o Intel arquitetura de 32 bits armazena palavras de 32 bits, cada um dos 4 bytes. A memória é abordada no nível de byte único, no entanto; portanto, um endereço pode ser "alinhado", o que significa que começa em um limite de palavra, ou "desalinhado", o que significa que não.

Em certas arquiteturas de certas operações de memória pode ser mais lenta ou completamente nem mesmo permitido em endereços desalinhadas.

Então, se você sabe que seus endereços estão alinhados nos endereços certos, você pode usar _amem2 (), para a velocidade. Caso contrário, você deve usar _mem2 ().

endereços Alinhados são aqueles que são múltiplos do tamanho do acesso em questão.

  • Acesso de 4 palavras de bytes em endereços que são múltiplos de 4 será alinhado
  • Acesso de 4 bytes a partir do endereço (digamos) 3 será o acesso desalinhado

É muito provável que o _mem2 função que irá trabalhar também para acessos não alinhados será menos ideal para obter os alinhamentos corretos que trabalham em seu código. Isto significa que o _mem2 função é provável que seja mais caro, em seguida, a sua _amem2 versão.

Então, quando você precisa de desempenho (especialmente quando você sabe que a latência de acesso é alta), seria prudente para identificar quando você pode usar o acesso alinhados. O _amem2 existe para este fim -. Para dar-lhe o desempenho quando você sabe que o acesso está alinhada

Quando se trata de 2 acessos byte, identificando operações alinhadas é muito simples.
Se todos os endereços de acesso para a operação são 'even' (isto é, sua LSB é zero), você tem o alinhamento de 2 bytes. Isto pode ser facilmente verificado com,

if (address & 1) // is true
    /* we have an odd address; not aligned */
else
    /* we have an even address; its aligned to 2-bytes */

Eu sei que isto é uma questão antiga com uma resposta selecionada, mas não viu ninguém explicar a resposta para o que é a diferença entre o acesso à memória alinhada e não alinhada ...

Seja dram ou SRAM ou Flash ou outro. Tome uma SRAM como um exemplo simples é construído a partir de pedaços de uma SRAM específico serão construídas a partir de um número fixo de bits de largura e um número fixo de linhas de profundidade. digamos que 32 bits de largura e vários / muitas linhas de profundidade.

se eu fizer uma gravação de 32 bits para o endereço 0x0000 neste SRAM, o controlador de memória em torno deste SRAM pode simplesmente fazer um único ciclo de gravação para a linha 0.

se eu fizer uma gravação de 32 bits para o endereço 0x0001 neste SRAM, assumindo que é permitido, o controlador precisa fazer uma leitura da linha 0, modificar três dos bytes, preservando um, e escrever que a remar 0, em seguida, ler a linha 1 um byte Modificar deixando os outros três como encontrado e escrever de volta. qual bytes são modificados ou não tem a ver com endianness para o sistema.

O primeiro é alinhado e este último não alinhado, claramente uma diferença de desempenho mais precisa a lógica extra para ser capaz de fazer os quatro ciclos de memória e mesclar as pistas bytes.

Se eu fosse para ler 32 bits de endereço 0x0000, em seguida, uma única leitura de linha 0, feito. Mas leia de 0x0001 e eu tenho que fazer duas leituras row0 e row1 e, dependendo do projeto do sistema basta enviar esses 64 bits voltar ao processador, possivelmente, dois relógios de ônibus em vez de um. ou o controlador de memória tem a lógica extra para que os 32 bits estão alinhados no barramento de dados em um ciclo de ônibus.

16 bit leituras são um pouco melhor, uma leitura de 0x0000, 0x0001 e 0x0002 seria apenas uma leitura a partir row0 e poderia baseado no projeto do sistema / processador de enviar esses 32 bits trás e os extratos de processamento-los ou transferi-los no controlador de memória para que eles pousar em pistas específicas byte modo que o processador não tem que em torno de rotação. Um ou outro tem que se não ambos. Uma leitura de 0x0003 embora é como acima, você tem que ler linha 0 e row1 como um de seus bytes está em cada e em seguida, enviar 64 bits de volta para o processador ao extrato ou as colheitadeiras controlador de memória os bits em uma resposta barramento de 32 bits ( assumindo o bus entre o controlador de processador e de memória é de 32 bits de largura para estes exemplos).

A 16 bit gravação que sempre acaba com pelo menos um read-modify-write neste exemplo SRAM, endereço 0x0000, 0x0001 e 0x0002 leitura row0 modificar dois bytes e escrever de volta. endereço 0x0003 ler duas linhas modificar um byte cada um e escrever de volta.

8 bits só precisa ler uma linha que contém esse byte, escreve, porém, são uma leitura-modificação-gravação de uma linha.

A não funcionavam ARMV4 como não alinhado embora você poderia desativar a armadilha e o resultado não é como seria de esperar acima, não é importante, braços atuais permitem desalinhado e dar-lhe o comportamento acima você pode mudar um pouco em um registo de controlo e, em seguida, abortará transferências desalinhadas. mips usados ??para não permitir que, sem saber o que fazer agora. x86, 68K etc, era permitido e o controlador de memória pode ter tido para fazer a maior parte do trabalho.

Os desenhos que permitem não faça isso claramente são para desempenho e menos lógica para o que alguns diriam que é um fardo para os programadores de outros poderiam dizer que há trabalho extra sobre o programador ou mais fácil para o programador. alinhado ou não você também pode ver por que ele pode ser melhor não tentar salvar qualquer memória, fazendo 8 variáveis ??bit mas vá em frente e queimar uma palavra de 32 bits ou qualquer que seja o tamanho natural de um registo ou o ônibus é. Pode ajudar o seu desempenho em um pequeno custo de alguns bytes. Sem mencionar o código extra o compilador precisa adicionar para fazer a digamos 32 bits registrar pouco variável de 8 imitar, mascarando e, por vezes assinar extensão. Onde o uso de tamanhos nativos de registro dessas instruções adicionais não são necessários. Você também pode embalar várias coisas em um ônibus / memória ampla local e fazer um ciclo de memória de coletar ou escrevê-los, em seguida, usar algumas instruções extra para manipulate entre registos não custando carneiro e uma possível lavagem do número de instruções.

Eu não concordo que o compilador será sempre alinhar o direito de dados para o alvo, existem maneiras de quebrar isso. E se o apoio alvo doesnt desalinhada você vai bater a falta. Os programadores nunca precisa falar sobre isso, se o compilador sempre fez o certo baseado em qualquer código legal que você poderia vir acima com, não haveria razão para esta pergunta a menos que fosse para o desempenho. Se você não controlar o endereço ptr vazio a ser alinhado ou não, então você tem que usar o MEM2 () acesso desalinhado o tempo todo ou você tem que fazer um if-then-else em seu código com base no valor do ptr como nik fora pontudo. declarando nulos o compilador C agora não tem maneira de lidar correctamente com o seu alinhamento e não vai ser garantida. se você tomar um char * prt e alimentá-lo para essas funções, todas as apostas estão fora sobre o compilador acertar sem você adicionando código extra seja enterrado na função MEM2 () ou fora destas duas funções. assim como está escrito no seu MEM2 questão () é a única resposta correta.

DRAM dizem usado em seu desktop / laptop tende a ser 64 ou 72 (com ECC) bits de largura, e qualquer acesso a eles está alinhado. Embora os cartões de memória são na verdade composta de 8 bits de largura, 16 ou 32 bits chips de largura. (Isso pode estar mudando com telefones / tablets por várias razões) o controlador de memória e, idealmente, pelo menos, um cache de se senta na frente deste dram para que os acessos desalinhados ou até mesmo alinhados que são menores do que o ônibus largura ler-modificar gravações são tratados com no SRAM de cache que é a maneira mais rápida, e os acessos DRAM estão todos alinhados ônibus cheio largura acessos. Se você não tem de cache na frente do dram eo controlador é projetado para largura total de acessos, em seguida, que é o pior desempenho, se projetado para iluminar as pistas byte separadamente (assumindo 8 bits chips de largura), então você não tem o read-modify -writes mas um controlador mais complicado. se o caso de uso típico é com um cache (se houver no projeto), então ele não pode fazer sentido ter esse trabalho adicional no controlador para cada pista byte, mas tê-lo apenas saber como fazê-ônibus cheio largura transferências porte ou múltiplos de.

_mem2 é mais geral. Ele vai trabalhar, se ptr está alinhada ou não. _amem2 é mais rigoroso: exige que ptr ser alinhadas (embora presumivelmente é ligeiramente mais eficiente). Portanto, use _mem2 a menos que você pode garantir que ptr é sempre alinhados.

Muitos processadores têm restrições de alinhamento no acesso à memória. acesso não alinhado quer gera uma interrupção de excepção (por exemplo ARM), ou é apenas mais lento (por exemplo, x 86).

_mem2 é provavelmente implementado como buscar dois bytes e usando turno e ou operações bit a bit para fazer uma ushort 16-bit fora delas.

_amem2 provavelmente apenas lê o ushort 16-bit do ptr especificado.

Eu não sei TMS320C64x especificamente, mas eu acho que requer um alinhamento de 16 bits para acessos de memória de 16 bits. Assim você pode usar _mem2 sempre mas com penalidade de desempenho, e _amem2 quando você pode garantir que ptr é um endereço par.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top