2016-02-05 3 views
4

Je souhaite écrire un code memcpy qui copie mot par mot au lieu de byte by byte pour augmenter la vitesse. (Bien que j'ai besoin de faire un peu d'octet par octet pour les derniers octets ou quelques octets). Je veux donc que mon adresse source et destination soit correctement alignée. J'ai vu la mise en œuvre de memcpy dans la glibc https://fossies.org/dox/glibc-2.22/string_2memcpy_8c_source.html il ne alignement que pour l'adresse de destination. Mais même si l'adresse de la source n'est pas correctement alignée, cela entraînera une erreur de bus (la vérification de l'alignement est activée dans mon CPU). Je ne suis pas sûr de savoir comment aligner correctement la source et la destination. Parce que si j'essaie d'aligner la source en copiant quelques octets par octet par octet, cela changera aussi l'adresse de destination, donc d'abord l'adresse de destination qui a été alignée d'abord correctement pourrait ne pas être correctement alignée maintenant. Alors est-il possible d'aligner les deux? Aidez-moi, s'il vous plaît.Alignement de l'adresse source et de destination dans memcpy

void memcpy(void *dst, void *src,int size) 
{ 
    if(size >= 8) 
    { 
    while(size/8) /* code will give sigbus error if src = 0x10003 and dst = 0x100000 */ 
    { 
     *((double*)dst)++ = *((double*)src)++; 
     size = size - 8; 
    } 
    } 

    while(size--) 
    { 
    *((char*)dst)++ = *((char*)src)++; 
    } 
} 
+1

Je ne comprends pas comment vous pouvez aligner l'adresse source ET dest? Je suis désolé, je ne comprends pas? –

+0

@MartinJames Considérons que je passe src = 0x10003 dest = 0x100000 et la taille de 15. Si dans memcpy je veux faire mot par mot copie, je veux aligner src pour être multiple de 8 (64 bits OS) donc le prochain numéro qui est multiple de 8 est 0x10006, donc pour les 3 premiers octets je vais faire byte by byte copy, si je fais que src sera 0x10006 mais dest = 0x100003, encore une fois maintenant dest n'est pas un multiple de 8. ce problème continuera. Alors, comment puis-je aligner src et dest ici. Si ce n'est pas possible, existe-t-il un autre moyen de faire une copie mot par mot? – Praveen

+0

Vous ne pouvez pas. En supposant que vous déplacez un bloc de mots, si la source est étrange mais la cible est égale, vous êtes en quelque sorte en train d'aligner des mots mal alignés. D'un autre côté, si la source est paire et la cible est étrange, vous désalignez les mots alignés.Vous serez soit en train de lire ou d'écrire des mots mal alignés - n'est pas non plus impossible de copier un octet à la fois. –

Répondre

0

... donc tout d'abord l'adresse de destination qui a été aligné dans un premier temps bien pourrait ne pas être aligné correctement maintenant. Alors, y a-t-il un moyen d'aligner les deux?

J'ai trouvé cet article sur l'optimisation des memcpy que je crois discute de ce que vous essayez de faire en longueur ... (voir lien ci-dessous exemple de code)

modifié GNU algorithme:

void * memcpy(void * dst, void const * src, size_t len) 
{ 
    long * plDst = (long *) dst; 
    long const * plSrc = (long const *) src; 

    if (!(src & 0xFFFFFFFC) && !(dst & 0xFFFFFFFC)) 
    { 
     while (len >= 4) 
    { 
      *plDst++ = *plSrc++; 
      len -= 4; 
     } 
    } 

    char * pcDst = (char *) plDst; 
    char const * pcDst = (char const *) plSrc; 

    while (len--) 
    { 
     *pcDst++ = *pcSrc++; 
    } 

    return (dst); 
} 

ThisLa variation de l'algorithme GNU modifié utilise le calcul pour ajuster le désalignement d'adresse.

+1

Merci pour la réponse, mais ici, le code vérifie d'abord si la destination et la source sont alignées sur 4 octets. s'ils sont alignés, ils copient longtemps. sinon byte by byte copy. Mais si la taille est supérieure à 1000, pour la vitesse, jusqu'à un certain point, je ferai un byte by byte copy jusqu'à ce que mes deux src et dest soient alignés. alors mal faire le mot par mot copie et pour le mal restant faire octet by byte à la fin enfin. Pour faire une copie mot par mot, la source et la destination doivent être alignées sur le mot. Je veux un moyen de faire ça. – Praveen

+0

@Praveen: Et même si vous adoptez une approche gourmande, la vérification devrait être pour savoir si c'est le même désalignement, auquel cas vous pouvez le corriger par copie 1/2/3-byte initiale. – einpoklum

0

Avec le code de memoire glibc que vous avez inclus, il n'y a aucun moyen d'appeler la fonction sans que la mémoire soit déjà alignée. Si vous deviez écrire le vôtre, comme je le vois, il y a deux alignements possibles pour le memcpy:

1) Les deux tampons sont décalés d'une même limite de quatre octets, ou les deux sont déjà sur une limite de quatre octets. (src % 4 == dst % 4) Dans ce cas, la copie octet par octet des premiers octets, puis l'alignement de l'adresse de destination uniquement est correct.

2) Les tampons ne sont pas tous les deux sur la même frontière. (src % 4 != dst % 4) Dans ce cas, afin de copier d'un alignement à l'autre, un mot à la fois, le processeur devrait suivre un processus similaire à celui ci-dessous:

Load the new word 
Split it into an upper half and lower half. 
Shift the upper half down 
Shift the lower half up 
Add the upper half the previous lower half. 
Store the combined copy to memory 
Repeat 

Je ne suis pas sûr que ce serait plus rapide que de simplement copier octet par octet. Halfword-by-halfword peut être plus rapide si l'architecture de votre processeur le permet et que les deux tampons sont alignés sur le demi-mot, bien que la plupart des implémentations memcpy que j'ai vues sur les architectures supportent déjà.