memcpy - AugustinLopez/libft GitHub Wiki
From The Open Group Base Specifications issue 7, 2018:
#include <string.h>
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
- The memcpy() function shall copy n bytes from the object pointed to by s2 into the object pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.
- The memcpy() function shall return s1; no return value is reversed to indicate an error.
- No error are defined.
Relevant concepts: Operator precedence, type casting, restrict keyword: the use of the restrict keyword is forbidden by the libft subject.
#include <string.h>
void *ft_memcpy(void *s1, const void *s2, size_t n)
{
unsigned char *cs1;
unsigned char *cs2;
cs1 = (unsigned char *)s1;
cs2 = (unsigned char *)s2;
while (n--)
*cs1++ = *cs2++;
return (s1);
}
For more information, please refer to the Optimization Concepts page.
#include <string.h>
#include <stdint.h>
void *ft_memcpy(void *s1, const void *s2, size_t n)
{
unsigned char *cs1;
unsigned char *cs2;
uint64_t *lls1;
uint64_t *lls2;
cs1 = (unsigned char *)s1;
cs2 = (unsigned char *)s2;
if ((n >= 8) && (((uintptr_t)s1 & 0x7) == ((uintptr_t)s2 & 0x7)))
{
while ((uintptr_t)cs1 & 0x7)
{
*cs1++ = *cs2++;
--n;
}
lls1 = (uint64_t *)cs1;
lls2 = (uint64_t *)cs2;
while (n >= 8)
{
*lls1++ = *lls2++;
n -= 8;
}
cs1 = (unsigned char *)lls1;
cs2 = (unsigned char *)lls2;
}
while (n--)
*cs1++ = *cs2++;
return (s1);
}
- Result are a percentage of the performance against a glibc memcpy [ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27].
- Compiler is gcc [(Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0].
- for each size the test runtime is 5 seconds.
- Memory is aligned.
| Size\flag | -O3 -fno-builtin | -O2 | -Os | (none) |
|---|---|---|---|---|
| 1 | 99% | 101% | 100% | 99% |
| 10 | 99% | 102% | 100% | 98% |
| 100 | 99% | 100% | 96% | 88% |
| 1K | 97% | 76% | 75% | 40% |
| 10K | 96% | 30% | 27% | 7% |
| 100K | 100% | 15% | 12% | 3% |
| 1M | 83% | 15% | 12% | 3% |
| Size\flag | -O3 -fno-builtin | -O2 | -Os | (none) |
|---|---|---|---|---|
| 1 | 99% | 98% | 101% | 99% |
| 10 | 99% | 98% | 101% | 97% |
| 100 | 99% | 100% | 99% | 96% |
| 1K | 98% | 98% | 94% | 83% |
| 10K | 98% | 86% | 74% | 38% |
| 100K | 99% | 85% | 61% | 19% |
| 1M | 83% | 77% | 67% | 19% |
# include <time.h>
# include <string.h>
# include <stdlib.h>
size_t memcpy_speed_test(int len, int second, void *(mem)(void *, const void *, size_t))
{
clock_t chrono = 0;
clock_t start = 0;
size_t i = 0;
void *dst;
void *src1;
void *src2;
dst = malloc(len);
src1 = malloc(len);
src2 = malloc(len);
if (!dst || !src1 || !src2)
exit(1);
memset(src1, 0xff, len);
memset(src2, 0, len);
memset(dst, 0, len);
start = clock();
while (chrono < second * CLOCKS_PER_SEC)
{
if (i % 2)
mem(dst, src1, len);
else
mem(dst, src2, len);
i++;
chrono = clock() - start;
}
free(dst);
free(src1);
free(src2);
return (i);
}
- Optimizing Memcpy improves speed: Michael Morrow, April 2004.
- What's missing/sub-optimal in this memcpy implementation?: question by einpoklum, October 2014.