开发者

Replacing memcpy in a safe way

I want to replace memcpy with my own optimized version to do some benchmarks. I wouldn't like to modify each place in code which calls memcpy(it's a large code base and I want to avoid lots of changes). So what I did is the following:

// in a "common" header file which is included everywhere
#ifdef SHOULD_OPTIMIZE
    #define memcpy my_on_steroids_memcpy
#endif

The above works and replaces memcpy with my own implementation but it seems crude, forced and 开发者_StackOverflow社区not safe at all. Is it any other alternative so that I could replace the library memcpy without modifying the rest of the code? Should I forget about the above as it does not seem an adviseable thing to do and just modify all the other files(and why)?


Some compilers have a way to include a header from the command line. For example, g++ and gcc can be called with an -include option.

However, I'd be sure your code at least compiles and runs without the custom header, as it's considered "bad manners" for your code to fail without "mystery" compiler flags.

Also: the standard library implementations of memcpy usually already are optimized with SSE2 optimizations and the like. You probably won't be able to do better.


I'm going to assume that you're running linux...

The attached link is an example on how to use LD_PRELOAD to replace existing functions in an application. The example takes a normal malloc call, and then ensures that the memory has been zeroed out. This should be fairly obvious how to translate it to memcpy.

https://gist.github.com/701897


If you're on linux, memcpy is already very optimized, probably even too much so (I think we noticed a crash once with memcpy over a page border).

That said, you're perfectly allowed to define a replacement memcpy in your program. It will be called instead of the C library one. You don't have to do anything else than that.


I just found another way to replace the memcpy function call. It only works with GCC(I still need to find another way for VC++) but I think it's definitely better than the crude #define way. It uses the __REDIRECT macro(in sys/cdefs.h included via features.h), which from what I've seen it's used extensively in the glibc. Below follows an example with a small test:

// modified.h
#pragma once

#ifndef MODIF_H_INCLUDED_
#define MODIF_H_INCLUDED_

#include <cstddef>
#include <features.h>

extern "C"
{
void test_memcpy(void* __restrict to, const void* __restrict from, size_t size);
}

#if defined(__GNUC__)
void __REDIRECT(memcpy, (void* __restrict to, const void* __restrict from, size_t size),
                test_memcpy);
#endif /* __GNUC__ */

#endif /* MODIF_H_INCLUDED_ */

//modified.cpp
extern "C" void test_memcpy(void* __restrict to, const void* __restrict from, 
                            size_t size)
{
    std::cout << "Dumb memcpy replacement!\n";
}

//original.h
#pragma once

#ifndef ORIG_H_INCLUDED_
#define ORIG_H_INCLUDED_

void test_with_orig();

#endif /* ORIG_H_INCLUDED_ */

//original.cpp
#include <cstring>
#include <iostream>

void test_with_orig()
{
    int* testDest = new int[10];
    int* testSrc = new int[10];

    for (unsigned int i = 0; i < 10; ++i)
    {
            testSrc[i] = i;
    }

    memcpy(testDest, testSrc, 10 * sizeof(int));

    for (unsigned int i = 0; i < 10; ++i)
    {
            std::cout << std::hex << "\nAfter standard memcpy - " 
            << "Source: " << testSrc[i] << "\tDest: " << testDest[i] << "\n";
    }
}

// and a small test
#include "modified.h"
#include "original.h"

#include <iostream>
#include <cstring>

int main()
{
    int* testDest = new int[10];
    int* testSrc = new int[10];

    for (unsigned int i = 0; i < 10; ++i)
    {
            testSrc[i] = i;
            testDest[i] = 0xDEADBEEF;
    }

    memcpy(testDest, testSrc, 10 * sizeof(int));

    for (unsigned int i = 0; i < 10; ++i)
    {
            std::cout << std::hex << "\nAfter memcpy replacement - " 
            << "Source: " << testSrc[i] << "\tDest: " << testDest[i] << "\n";
    }

    test_with_orig();

    return 0;
}


If you do not want to change existing code, this seems to be the only available solution; and it should not be too bad, as the compiler will complain if the signature of your own memcpy does not match the default one.

That said, I would heavily doubt you will manage to squeeze out considerable better performance than the memcpy that comes with the standard library. But are you copying that much memory that it becomes an issue at all?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜