Sizeof, memset, memcpy

Andrey Karpov has an article in which he explains how the worst function in C/C++ is memset. But he is only half right: all but one example he has there are invalid uses of sizeof, and all of the examples show that lack of structure produces bugs. He also doesn’t explain why memset is bad.

The issues that he enumerates there are all linked to invalid calculation of sizes – and not only memset is affected – but memcpy, memmove and a lot of other string.h/cstring functions. For any C/C++ programmer, memX calls might be code-smells. There are no good reasons to use memset like functions, not in this day and age – a simple for loop gets optimized just as well as one might expect – for constant parameters the code is incredibly well optimized:

How does the compiler see it?

Lines 12-14 translate the first for loop, while lines 17-19 translate the memset. Not necessarily inefficient, as Andrey suggests, but you definitely achieve the same result if you write your own loop – there’s no reason not to, and one needs to remember that the compiler is WAY smarter than you.

memset could be a drag because memset has a byte level granularity. The interface of memset (like a lot of C APIs) invite to lack of performance. A processor now wants to write things at least 128 bits at a time, but memset has to check at all times if it still has 128 bits, if not, it tries with 64 bits, then 32, and so on. The issue of memset is, therefore, the granularity of the call – which the standard implementation tries to break down as well as possible – but it cannot do miracles.

For a lot of time, C++ was blamed of being inefficient – it cannot be as efficient to copy an object field by field instead of doing a simple memcpy – but, as the API of memcpy suggests, it might be slower for memcpy to do that copying especially if the compiler doesn’t know the precise number of items beforehand. The default copy operations on classes, however, will be most likely optimized for that precise class. If you really want to optimize something, make sure you measure your results, because even if the code looks more optimal, the run on real machines might not be as performant as you think. There’s rarely the case to optimize – and, yes, C can be less efficient than C++ due to exactly this sort of issues.

Coming back to our issue – as I said, not necessarily memset is the problem – but there are not enough good scenarios where you want to perform such a call. Same goes for memcpy – and the problem is the granularity – you don’t usually work with bytes of random sizes, and memcpy is just a marker for the compiler to copy as much as possible. What you want is for the call to memcpy in your source code never to translate to a call to memcpy in the object code, because that has to go to a generic implementation of the function that has to deal with (possibly) an odd number of bytes. What you want there is to have the call translated into the best copying option possible – perhaps SSE2/3 code that will be able to copy more data at a time, involving the prefetcher as well.

And last of them, sizeof. sizeof is bad because it’s so easy to make mistakes with it, especially when applied to arrays. The solution is to know your data – sure, you might want to work independent of your architecture – but use things like uint64_t instead of basic primitives (they are supported in the standard, you know?), and if you’re copying objects check if it’s not possible that the default implementation of the copy and assignment operators to be faster than what you want. Don’t go for sizeof – because the one taking the code over from you might not understand what and how sizeof works.

If you’re in C++ you might actually be helped by the new array_view from the gsl library. This is still something I didn’t work with, but the recommendation from Bjarne Stroustrup is really strong. 🙂

So, if you feel like using things like sizeof or memset or memcpy, thing again. Maybe the plain and simple code is just as efficient, maybe there are ways to get more performance.

Performance


Comentariul tău