Pergunta

Eu gostaria de copiar um período relativamente curto seqüência de memória (menos de 1 KB, tipicamente 2-200 bytes) em uma função crítica tempo. A melhor código para isso no lado CPU parece ser rep movsd. No entanto, eu de alguma forma não posso fazer o meu compilador para gerar este código. Eu esperava (e eu vagamente lembro de ter visto isso) usando memcpy faria isso usando o compilador embutido intrínsecos, mas com base na desmontagem e depuração parece compilador está usando chamada para memcpy / implementação da biblioteca memmove vez. Eu também esperava que o compilador pode ser inteligente o suficiente para reconhecer seguinte loop e uso rep movsd por conta própria, mas parece que isso não acontece.

char *dst;
const char *src;
// ...
for (int r=size; --r>=0; ) *dst++ = *src++;

Existe alguma maneira de fazer o compilador Visual Studio para gerar seqüência rep movsd à excepção de usar linha de montagem?

Foi útil?

Solução 3

Usando memcpy com um tamanho constante

O que eu encontrei enquanto isso:

Compiler usará intrínseca quando o tamanho do bloco copiado é tempo de compilação conhecida. Quando não é, é chama a implementação da biblioteca. Quando o tamanho é conhecido, o código gerado é muito agradável, selecionado com base no tamanho. Pode ser um único mov, ou movsd, ou movsd seguido por movsb, conforme necessário.

Parece que se eu realmente quero usar movsb ou movsd sempre, mesmo com um tamanho "dinâmico" Vou ter de usar em linha de montagem ou especial intrínseca (veja abaixo). Eu sei que o tamanho é "bastante curto", mas o compilador não sabe disso e eu não posso comunicar isso a ele - Eu até tentei usar __assume (tamanho <16), mas não é o suficiente

.

código de demonstração, de compilação com "-Ob1 (expansão de linha apenas):

  #include <memory.h>

  void MemCpyTest(void *tgt, const void *src, size_t size)
  {
    memcpy(tgt,src,size);
  }

  template <int size>
  void MemCpyTestT(void *tgt, const void *src)
  {
    memcpy(tgt,src,size);
  }

  int main ( int argc, char **argv )
  {
    int src;
    int dst;
    MemCpyTest(&dst,&src,sizeof(dst));
    MemCpyTestT<sizeof(dst)>(&dst,&src);
    return 0;
  }

Especializada intrínsecos

Eu descobri recentemente existe maneira muito simples como fazer do Visual Studio personagens cópia compilador usando movsd - muito natural e simples: intrínsecos usando. Seguintes intrínsecos podem vir a calhar:

Outras dicas

Várias perguntas vêm à mente.

Em primeiro lugar, como você sabe movsd seria mais rápido? Você já olhou para sua latência / débito? A arquitetura x86 é cheio de antigas instruções intrincada que não devem ser usados ??porque eles simplesmente não são muito eficientes na moderna CPU.

Em segundo lugar, o que acontece se você usar std::copy vez de memcpy? std::copy é potencialmente mais rápido, uma vez que pode ser especializado em tempo de compilação para o tipo de dados específico.

E em terceiro lugar, não é habilitado funções intrínsecas sob propriedades do projeto -> C / C ++ -> Otimização

É claro que eu assumir outras otimizações também estão ativados.

Você está executando uma compilação otimizada? Ele não vai usar uma intrínseca a menos que a otimização está ligado. Vale a pena também notar que ele provavelmente irá usar um melhor ciclo de cópia de movsd rep. Deve tentar usar MMX, pelo menos, para realizar um de 64 bits para uma cópia do tempo. Na verdade 6 ou 7 anos atrás eu escrevi um loop cópia MMX otimizado para fazer esse tipo de coisa. Infelizmente memcpy intrínseca do compilador superou minha cópia MMX por cerca de 1%. Isso realmente me ensinou a não fazer suposições sobre o que o compilador está fazendo.

Você cronometrado memcpy? Nas versões recentes do Visual Studio, a implementação memcpy usa SSE2 ... que deve ser mais rápido do que rep movsd. Se o bloco que você está copiando é de 1 KB, então não é realmente um problema que o compilador não está usando um intrínseca desde o tempo para a chamada de função será insignificante comparado com o tempo para a cópia.

Note-se que, a fim de utilização movsd, src deve apontar para uma memória alinhadas para 32 bits de limite e o seu comprimento deve ser um múltiplo de 4 bytes.

Se for, por que seu uso char * código em vez de int * ou algo assim? Se não for, sua pergunta é discutível.

Se você alterar char * para int *, você pode obter um melhor resultado de std::copy.

Edit: você medida que a cópia é o gargalo ?

Use memcpy. Este problema já foi resolvido.

FYI rep movsd nem sempre é o melhor, representante movsb pode ser mais rápido em algumas circunstâncias e com SSE e similares o melhor é movntq [edi], XMM0. Você pode até mesmo otimizar ainda mais para grande quantidade de memória no uso de página localidade movendo dados para um buffer e, em seguida, movê-lo para o seu destino.

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