memcpy - AugustinLopez/libft GitHub Wiki

Introduction

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.

Implementation

Basic implementation

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);
}

Improved implementation

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);
}

Speed tests

  • 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.

Basic implementation

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%

Improved implementation

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%

Test function

# 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);
}

Other implementations

Further reading

⚠️ **GitHub.com Fallback** ⚠️