memcpy



  • Hi,

    ich suche den schnellsten memcpy algo. Ich habe vor kurzem eine recursive implementierung gesehen, welche mehrer bytes auf einmal kopiert...

    koennt die bekannten memcpy versionen posten, die euch bekannt sind?



  • Die schnellsten nutzen spezielle Maschinenbefehle.

    Rekursiv bedeutet aber auch, dass du Funktionsaufrufe machst.
    Das braucht auch Zeit.



  • ich kann mich an sowas erinnern, ist das undefined behavior?

    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    
    void *fast_memcpy(void *dst, const void *src, size_t len) {
    	void *d = (void*)dst;
    	void *s = (void*)src;
    
    	if (len == 0) {
    		return d;
    	}
    
    	int select = len % 8;
    	switch (select) {
    		case 2:
    			*((uint16_t*)d) = *((uint16_t*)s);
    			((uint16_t*&)d)++;
    			((uint16_t*&)s)++;
    			len -= 2;
    			break;
    		case 4:
    			*((uint32_t*)d) = *((uint32_t*)s);
    			((uint32_t*&)d)++;
    			((uint32_t*&)s)++;
    			len -= 4;
    			break;
    		case 8:
    			*((uint64_t*)d) = *((uint32_t*)s);
    			((uint64_t*&)d)++;
    			((uint64_t*&)s)++;
    			len -= 8;
    			break;
    		default:
    			*((uint8_t*)d) = *((uint8_t*)s);
    			((uint8_t*&)d)++;
    			((uint8_t*&)s)++;
    			len -= 1;
    			break;
    	}
    
    	return fast_memcpy(d, s, len);
    }
    
    int main(void) {
    	// your code goes here
    
    	const uint16_t src[] = {12,13,14,15,16};
       	uint16_t dst[10] = {0};
    
    	fast_memcpy(&dst, src, sizeof(src));
    
    	for (int i = 0; i < sizeof(src)/sizeof(uint16_t); i++) {
    		printf("%d", (uint32_t)dst[i]) << endl;
    	}
    
    	return 0;
    }
    


  • DirkB schrieb:

    Die schnellsten nutzen spezielle Maschinenbefehle.

    Ja, die schnellsten benutzen Hardware-spezifische Features wie DMA. 🙂



  • ist das den legaler code?

    ((uint8_t*&)d)++;
    


  • in c++ bekomme ich folgenden fehler:

    (uint16_t*)d++;
    error: ISO C++ forbids incrementing a pointer of type ‘void*’
    

    folgendes klappt aber:

    (uint16_t*&)d++;
    

    wie macht man das in c11?



  • der code hat noch einen bug, jemand eine idee wie ich das select fixen kann?

    #include <stdio.h> 
    #include <string.h> 
    #include <stdint.h> 
    
    void *fast_memcpy(void *dst, const void *src, size_t len) { 
        void *d = (void*)dst; 
        void *s = (void*)src; 
    
        if (len == 0) { 
            return d; 
        } 
    
        int select = sizeof(uint64_t);
    
        switch (select) { 
            case 2: 
                *(uint16_t*)d = *(uint16_t*)s;
                (uint16_t*)d++; 
                (uint16_t*)s++; 
                len -= sizeof(uint16_t); 
                break; 
            case 4: 
                *(uint32_t*)d = *(uint32_t*)s;
                (uint32_t*)d++; 
                (uint32_t*)s++; 
                len -= sizeof(uint32_t); 
                break; 
            case 8: 
                *(uint64_t*)d = *(uint64_t*)s;
                (uint64_t*)d++; 
                (uint64_t*)s++;
                len -= sizeof(uint64_t); 
                break; 
            default: 
                *(uint8_t*)d = *(uint8_t*)s;
                (uint8_t*)d++; 
                (uint8_t*)s++;
                len -= sizeof(uint8_t); 
                break; 
        } 
    
        return fast_memcpy(d, s, len); 
    } 
    
    int main(void) { 
        // your code goes here 
    
        const uint64_t src[] = {12,13,14,15,16}; 
        uint64_t dst[10] = {0}; 
    
        fast_memcpy(&dst, src, sizeof(src)); 
    
        for (int i = 0; i < sizeof(src)/sizeof(uint64_t); i++) { 
            printf("%d", (uint32_t)dst[i]); 
        } 
    
        return 0; 
    }
    


  • int select = sizeof(uint64_t);
    

    Das wird halt immer 8 ergeben, auch wenn nur noch 1 byte übrig bleibt.



  • ich weiss, copy paste error:

    warum klappt das hier nicht? der output ist: 1213000

    #include <stdio.h> 
    #include <string.h> 
    #include <stdint.h> 
    
    void *fast_memcpy(void *dst, const void *src, size_t len) { 
        void *d = (void*)dst; 
        void *s = (void*)src; 
    
        if (len == 0) { 
            return d; 
        }
    
        int select1 = len / sizeof(uint64_t);
        int select2 = len / sizeof(uint32_t);
        int select3 = len / sizeof(uint16_t);
        int select4 = len / sizeof(uint8_t);
    
        if (select1 > 0) { 
                *(uint64_t*)d = *(uint64_t*)s;
                (uint64_t*)d++; 
                (uint64_t*)s++;
                len -= sizeof(uint64_t);
        } 
        else if (select2 > 0) {
                *(uint32_t*)d = *(uint32_t*)s;
                (uint32_t*)d++; 
                (uint32_t*)s++; 
                len -= sizeof(uint32_t); 
        }
        else if (select3 > 0) {
                *(uint16_t*)d = *(uint16_t*)s;
                (uint16_t*)d++; 
                (uint16_t*)s++; 
                len -= sizeof(uint16_t); 
        }
        else if (select4 > 0) {
                *(uint8_t*)d = *(uint8_t*)s;
                (uint8_t*)d++; 
                (uint8_t*)s++;
                len -= sizeof(uint8_t); 
        }
    
        return fast_memcpy(d, s, len);
    } 
    
    int main(void) { 
        // your code goes here 
    
        const uint64_t src[] = {12,13,14,15,16}; 
        uint64_t dst[10] = {0}; 
    
        fast_memcpy(&dst, &src, sizeof(src)); 
    
        for (int i = 0; i < sizeof(src)/sizeof(uint64_t); i++) { 
            printf("%d", (uint64_t)dst[i]); 
        } 
    
        return 0; 
    }
    


  • rep movs* / rep stos*
    


  • wie meinen? wie kann ich meinen code zum laufen bekommen?



  • hi, folgender code funktioniert soweit, ist aber nicht portabel. wie bekomme ich das memory alginment hin?

    #include <stdio.h> 
    #include <string.h> 
    #include <stdint.h> 
    
    void *fast_memcpy(void *dst, const void *src, size_t len) { 
        uint8_t *d = (uint8_t*)dst; 
        uint8_t *s = (uint8_t*)src; 
    
        if (len == 0) { 
            return d; 
        } 
    
        int select1 = len % sizeof(uint64_t);
        int select2 = len % sizeof(uint32_t);
        int select3 = len % sizeof(uint16_t);
    
        if (select1 == 0) {
            *(uint64_t*)d = *(uint64_t*)s; 
            d+=sizeof(uint64_t);
            s+=sizeof(uint64_t);
            len -= sizeof(uint64_t); 
        }
        else if (select2 == 0) {
            *(uint32_t*)d = *(uint32_t*)s; 
            d+=sizeof(uint32_t);
            s+=sizeof(uint32_t);
            len -= sizeof(uint32_t); 
        }
        else if (select3 == 0) {
            *(uint16_t*)d = *(uint16_t*)s; 
            d+=sizeof(uint16_t);
            s+=sizeof(uint16_t);
            len -= sizeof(uint16_t);
        }
        else {
            *(uint8_t*)d = *(uint8_t*)s; 
            d+=sizeof(uint8_t);
            s+=sizeof(uint8_t);
            len -= sizeof(uint8_t);
        } 
    
        return fast_memcpy(d, s, len); 
    } 
    
    int main(void) { 
        // your code goes here 
    
        char *src = "cloud";
        char dst[10]; 
    
        fast_memcpy(&dst, src, strlen(src)); 
    
        for (int i = 0; i < strlen(src); i++) { 
            printf("%c", dst[i]); 
        } 
    
        return 0; 
    }
    


  • any idea?



  • hi,
    kann mir jemand feedback zum memory alignment check geben? wie kann ich sowas testen?

    (uintptr_t)src % sizeof(uint64_t) == 0 &&
    (uintptr_t)dst % sizeof(uint64_t) == 0
    
    #include <stdio.h> 
    #include <string.h> 
    #include <stdint.h> 
    
    void *fast_memcpy(void *dst, const void *src, size_t len) { 
        uint8_t *d = (uint8_t*)dst; 
        uint8_t *s = (uint8_t*)src; 
    
        if (len == 0) { 
            return d; 
        } 
    
        bool select1 = len % sizeof(uint64_t); 
        bool select2 = len % sizeof(uint32_t); 
        bool select3 = len % sizeof(uint16_t); 
    
        if ((uintptr_t)src % sizeof(uint64_t) == 0 && // check memory alignment
            (uintptr_t)dst % sizeof(uint64_t) == 0 &&
            select1 == 0) { 
            *(uint64_t*)d = *(uint64_t*)s; 
            d+=sizeof(uint64_t); 
            s+=sizeof(uint64_t); 
            len -= sizeof(uint64_t); 
        } 
        else if ((uintptr_t)src % sizeof(uint32_t) == 0 && 
                 (uintptr_t)dst % sizeof(uint32_t) == 0 &&
                 select2 == 0) { 
            *(uint32_t*)d = *(uint32_t*)s; 
            d+=sizeof(uint32_t); 
            s+=sizeof(uint32_t); 
            len -= sizeof(uint32_t); 
        } 
        else if ((uintptr_t)src % sizeof(uint16_t) == 0 &&
                 (uintptr_t)dst % sizeof(uint16_t) == 0 &&
                 select3 == 0) { 
            *(uint16_t*)d = *(uint16_t*)s; 
            d+=sizeof(uint16_t); 
            s+=sizeof(uint16_t); 
            len -= sizeof(uint16_t); 
        } 
        else { 
            *(uint8_t*)d = *(uint8_t*)s; 
            d+=sizeof(uint8_t); 
            s+=sizeof(uint8_t); 
            len -= sizeof(uint8_t); 
        } 
    
        return fast_memcpy(d, s, len); 
    } 
    
    int main(void) { 
        // your code goes here 
    
        char *src = "cloud"; 
        char dst[10]; 
    
        fast_memcpy(&dst, src, strlen(src)+1); 
    
        for (int i = 0; i < strlen(src); i++) {
            printf("%c", dst[i]); 
        }
    
        return 0; 
    }
    


  • Das könnte dir helfen:
    https://www.c-plusplus.net/forum/289488-full

    Lies dir einfach alles durch auch wenn du nicht asm kannst.

    Ansonsten:
    https://www.google.de/search?q=fast+memcpy


Anmelden zum Antworten