Pergunta

Existem mais rápidas alternativas para memcpy () em C ++?

Foi útil?

Solução

Não. Sua biblioteca de compilador / padrão provavelmente vai ter uma implementação muito eficiente e adaptado de memcpy. E memcpy é basicamente o menor api não é para copiar uma parte da memória para outro.

Se você quiser mais speedups, encontrar uma maneira de não precisar de qualquer tipo de cópia de memória.

Outras dicas

Em primeiro lugar, uma palavra de aconselhamento. Assuma que as pessoas que escreveram a sua biblioteca padrão não são estúpidos. Se houvesse uma maneira mais rápida para implementar um memcpy geral, eles teriam feito isso.

Em segundo lugar, sim, existem melhores alternativas.

  • Em C ++, use a função std::copy. Ele faz a mesma coisa, mas é 1) mais seguro, e 2) potencialmente mais rápida em alguns casos. É um modelo, o que significa que ele pode ser especializado para tipos específicos, tornando-se potencialmente mais rápido que o memcpy geral C.
  • Ou, você pode usar seu conhecimento superior de o situação específica. Os implementadores de memcpy tinha que escrevê-lo para que ele teve um bom desempenho no todas caso. Se você tem informações específicas sobre a situação em que você precisa, você pode ser capaz de escrever uma versão mais rápida. Por exemplo, a quantidade de memória que você precisa cópia? Como é alinhado? Isso pode permitir que você escrever uma memcpy mais eficiente para este caso específico. Mas não vai ser tão bom na maioria dos outros casos (se ele vai trabalhar em tudo)

especialista em otimização de Agner Nevoeiro publicou funções de memória otimizados: http://agner.org/optimize/#asmlib . É sob GPL embora.

Algum tempo atrás Agner disse que essas funções devem substituir builtins CCG, porque eles são muito mais rápido. Eu não sei se ele foi feito desde então.

Esta resposta para uma pergunta muito simiar (cerca memset()) aplica-se aos também.

basicamente diz que compiladores geram muito código óptimo para memcpy() / memset() -. E de código diferentes, dependendo da natureza dos objectos (tamanho, alinhamento, etc)

E lembre-se, apenas PODs memcpy() em C ++.

A fim de encontrar ou escrever uma rotina de cópia de memória rápida, devemos entender como os processadores de trabalho.

Processadores desde Intel Pentium Pro fazer “execução fora de ordem”. Eles podem executar muitas instruções em paralelo, se as instruções não tem dependências. Mas este é apenas o caso quando as instruções de operar com apenas registros. Se eles operam com memória, unidades de CPU adicionais são usados, chamados de “unidades de carga” (para ler dados da memória) e “unidades de loja” (para gravar dados para a memória). A maioria das CPUs tem duas unidades de carga e uma unidade de armazenamento, ou seja, eles podem executar em paralelo duas instruções que lê a partir da memória e uma instrução que escreve para a memória (de novo, se eles não afetam uns aos outros). O tamanho dessas unidades é geralmente o mesmo que o tamanho máximo do registo - se a CPU tem registros XMM (SSE) - é 16 bytes, se tem registros YMM (AVX) - que é de 32 bytes, e assim por diante. Todas as instruções que ler ou memória de gravação são convertidos para micro-operações (micro-ops) que vão para a piscina comum de micro-ops e esperar lá para as unidades de carga e armazenar para ser capaz de atendê-los. Uma única unidade de carga ou armazenamento pode servir apenas um micro-op ao mesmo tempo, independentemente do tamanho dos dados de que necessita para carregamento ou armazenamento, seja ele um byte ou 32 bytes.

Assim, cópia de memória mais rápido seria movimento de e para registros com tamanho máximo. Para processadores AVX habilitados, maneira mais rápida de memória de cópia seria repetir a sequência seguinte, loop-desenrolado:

vmovdqa     ymm0,ymmword ptr [rcx]
vmovdqa     ymm1,ymmword ptr [rcx+20h]
vmovdqa     ymmword ptr [rdx],ymm0
vmovdqa     ymmword ptr [rdx+20h],ymm1

O código do Google postou antes por hplbsh não é muito bom, porque eles usam todos os 8 registradores XMM para armazenar os dados antes de começar a escrevê-lo de volta, enquanto ele não é necessário - uma vez que só tem duas unidades de carga e uma loja unidade. Assim, apenas dois registros dar melhores resultados. Usando que muitos registros em nada melhora o desempenho.

A rotina de cópia de memória também pode usar algumas técnicas "avançadas" como “pré-busca” para instruir o processador à memória de carga no cache de antecedência e “escreve não-temporais” (se você está copiando muito grandes pedaços de memória e não fazer precisa dos dados da memória intermédia de saída para ser imediatamente lido), alinhado contra gravações não alinhadas, etc.

Os processadores modernos, lançados desde 2013, se tiverem os ERMOS mordeu na CPUID, têm os chamados “reforçada movsb rep”, de modo que para a grande cópia de memória, pode ser utilizado o “movsb rep” - a cópia será muito rápido, ainda mais rápido do que com os registros YMM, e ele vai trabalhar com o cache corretamente. No entanto, os custos de arranque desta instrução são muito elevados - cerca de 35 ciclos, assim que paga-se apenas em grandes blocos de memória

.

Espero que agora deve ser mais fácil para você escolher ou escrever a melhor rotina de cópia de memória necessária para o seu caso.

Você pode até mesmo manter o padrão memcpy / memmove, mas obter o seu próprio largememcpy especial () para suas necessidades.

Dependendo do que você está tentando fazer ... se é um memcpy grande o suficiente, e você está apenas ser escrito para a cópia de baixa densidade, um mmap com MMAP_PRIVATE para criar um mapeamento de copy-on-write poderia concebivelmente ser mais rápido .

Dependendo da sua plataforma pode haver para casos de uso específicos, como se você sabe a origem eo destino estão alinhados a uma linha de cache e o tamanho é um múltiplo inteiro do tamanho da linha de cache. Em geral a maioria dos compiladores irá produzir um código bastante ideal para que memcpy.

Eu não tenho certeza que a utilização do memcpy padrão é sempre a melhor opção. A maioria das implementações memcpy eu olhei tendem a tentar alinhar os dados no início, e depois fazer cópias alinhadas. Se os dados já estão alinhados, ou é muito pequena, então este é o desperdício de tempo.

Às vezes é benéfico ter cópia palavra especializada, cópia meia palavra, cópia byte de memcpy, desde que ele não tem um efeito muito negativo sobre os caches.

Além disso, você pode querer um melhor controle sobre o algoritmo de alocação real. Na indústria de jogos é extremamente comum para as pessoas a escrever suas próprias rotinas de alocação de memória, independentemente de quanto esforço foi gasto pelos desenvolvedores toolchain em primeiro lugar desenvolvê-lo. Os jogos que eu vi quase sempre tendem a usar de Doug Lea Malloc .

De um modo geral, porém, você estaria perdendo tempo tentando memcpy otimizar como não vai sem dúvida ficar muitos pedaços mais fáceis de código em seu aplicativo para acelerar.

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