views:

434

answers:

14

I mean, I malloc a segment of memory, maybe 1k maybe 20bytes.. assume the pointer is pMem How can I know the content pMem refered is all Zero or \0 . I know memcmp but the second parameter should another memory address... thanx

A: 

The function you want is called memset.

Call it like this:

memset(pMem, '\0', iMemSize);
Patrick
Sorry, my ques how to judge the content of the memory
Macroideal
+3  A: 

You can use calloc if you want all 0s in the memory you allocate

Himanshu
Sorry, i was misunderstood
Macroideal
+17  A: 

As others have already suggested you probably want memset or calloc.

But if you actually do want to check if a memory area is all zero, you can compare it with itself but shifted by one.

bool allZero = pMem[0] == '\0' && !memcmp(pMem, pMem + 1, length - 1);

where length is the number of bytes you want to be zero.

Mark Byers
Oh, this method is the most fantastic answer....thanx
Macroideal
+1.. very clever
Isak Savo
Yes, call `memcmp` in its slower case (two buffers with different alignments), in order to do twice the necessary memory accesses, for a memory-bound task... What a good idea!
Pascal Cuoq
The sarcasm wasn't necessary, Pascal.
Rob Kennedy
That's a really slower than simple for-loop.
Kirill V. Lyadvinsky
To Kirill V. Lyadvinsky. Really? what if it is a big memory space? it's also slower?
Macroideal
It will read each memory cell twice.
Kirill V. Lyadvinsky
@Rob Wasn't it? I'm sorry, I'm a little bit out of touch.
Pascal Cuoq
While clever, this answer is slower than necessary. A simple for-loop is the correct answer (be it hand-written or from `algorithm`). You *have* to look at each byte of memory to know it every byte of memory is 0. the only way that isn't true is if you can make assumptions like "If this byte is 0, the next 3 are". that is of course only an example and not present true in your situation.
GMan
Hi everyone, and thanks for all the interesting comments! When I wrote the comment I didn't care about performance - I thought the max length was about 1K and typically about 20 bytes. I think someone should profile both methods for lots of short strings, and then again for some longer ones. I think it can't be that hard to do, and would make for an interesting experiment! I would do it myself but I have to work. I hope someone can do this and post the results. Looking forward to seeing it!
Mark Byers
@Mark: No need to profile, really. Your code for sure checks each memory location twice, and probably does all sorts of nasty things with cache while it's at it.
GMan
You're ignoring the processor's own cache. You can't really guess this sort of thing, you have to measure it. It should be straight-forward, I jsut don't have time now. If no-one else does it, I'll do it when I get home.
Mark Byers
Hmm... I've done some preliminary measurements, and the memcmp method appears to be very slightly faster than the simple looping on my machine, but right now I'm using a non-standard PC. If we want to know what's fastest (I don't it's going to be the bottleneck in his program anyway) we really should test this properly with benchmark tests rather than just guessing and making assumptions.
Mark Byers
@Mark Sorry if I sounded sarcastic. I am convinced that `memcmp(p,p+1,size-1)` is good enough, I was just shocked to see comments here and in other answers that revealed some sort of "it's O(1) because it's a library call, the for-loop takes longer because it has to read the buffer" reasoning.
Pascal Cuoq
It's OK. I was surprised at the opposite: lots of people here seem to think that the *only* way to access memory is one byte at a time.
Mark Byers
I've written my own benchmark (posted in an answer). Interested to know how it compares with yours, Mark. I haven't yet got memcmp to go very fast...
Steve Jessop
My objection to this is that, while it's clever, it's not immediately obvious what it's doing. A `for` loop would be much clearer, in my opinion. Cleverness is no substitute for clarity.
David Thornley
The worst is that it forces one of the reads to be unaligned, so even a full-word-read optimization would suffer. Anyway, no -1 because it's cute.
peterchen
Since when did "clever" beat "efficient", or "readable"?
jalf
+2  A: 

If you need the memory to be zero, just memset() it to zero; it's a waste of time to check whether it's zero first, because it probably isn't and you'll end up doing more work overall, checking and then setting.

However, if you really want to efficiently check a region of memory to see if it's all zero, you can memcmp() it against something else that's known to be all zero. You could allocate and zero one chunk of memory, for example, and then keep a pointer to it for use in comparing against other chunks of memory.

Wyzard
memcmp against a preallocated region wouldn't be very efficient. It'd require two memory reads per address you want to compare. +1 for the first point though
jalf
Why would a memcmp - involving two reads - be efficient? (Fast enough, maybe, but not efficient)
peterchen
It's not terribly efficient, but it's correct and portable. One could also use a loop and check the value of each byte, but a `memcmp()` implementation may use a more efficient approach, comparing whole machine words rather than individual bytes.
Wyzard
+5  A: 

As you've noted, memcmp compares one block of memory to another. If you had another block of memory that you already knew was all zero, then you could use that reference block to compare with your candidate block to see whether they match.

It sounds like you don't have another block of memory, though. You just have one, and you want to know whether it's all zero. The standard libraries don't provide such a function, but it's easy to write your own:

bool is_all_zero(char const* mem, size_t size)
{
  while (size-- > 0)
    if (*mem++)
      return false;
  return true;
}

If you want to allocate a new block of memory and have it be all zero right away, then use calloc instead of malloc. If you have a block of memory that you want to set to all zero, then use memset or std::fill.

Rob Kennedy
If it is a huge memory. this comparision takes a lot of time
Macroideal
@Macroideal Unless there is special support from the hardware, checking if a buffer contains all zeros requires reading the buffer. There is no way around it. At least in this answer, the buffer is read only once.
Pascal Cuoq
Pascal Cuoq: Have you measured the performance or are you just guessing? If you've measured it, please post results - I would be very interested to see. It doesn't seem obvious to me that the memcpy solution will have to hit the memory twice - the processor has a cache too, and that is much faster than memory. I'd be very interested to see the results, regardless of whice solution is better. Plus I think it's a standard best-practice to measure performance, not guess.
Mark Byers
Pascal Couq: I've thrown together a quick test and it shows that this method is **not** significantly faster on my hardware for 10M allocations of 100 bytes, even when the function is changed to a macro and inlined. I'll post more detailed results when I have time (in about 8 hours from now).
Mark Byers
(And in both cases, the performance impact was negligible - the main performance hit came from the calls to malloc.)
Mark Byers
@Mark Byers: It may not physically touch memory twice. But it *will* cause additional dependencies. Each comparison has to wait for two values to be retrieved, not just one. Even if they both have to be retrieved from cache (which will be the usual case), that is still slower than comparing one object in memory against a known compile-time constant.
jalf
+9  A: 

If you're testing it, and then only going to use it if it's zero, then be aware you have a race-condition, because the method suggested by @Mark Byers doesn't have an atomic test/set operation. It'll be hard to get the logic correct in this case.

If you want to zero it if it's not already zero, then just set it to zero as that will be faster.

Douglas Leeder
+1 for "it's faster to just zero the memory out anyway"
avakar
+7  A: 

C++ solution:

bool all_zeroes = 
  (find_if( pMem, pMem+len, bind2nd(greater<unsigned char>(), 0)) == (pMem+len));
Kirill V. Lyadvinsky
+1, it's good to know what the standard library has to offer.
avakar
+2  A: 

Another C++ solution, slightly simpler than Kirill's. It is somewhat less efficient, though, as it traverses the entire sequence even when that sequence contains a non-zero element.

bool all_zeroes = std::count(pMem, pMem + length, 0) == length;
avakar
not bad, but slightly overkill when the first byte already contains zero.
xtofl
xtofl, you mean non-zero. And yes, it will be asymptotically worse than the optimal algorithm in average case (it has the same worst-case complexity though). I actually noted the efficiency issue in my answer.
avakar
+14  A: 

Since Mark's answer has provoked some controversy:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#ifndef count
    #define count 1000*1000
#endif
#ifndef blocksize
    #define blocksize 1024
#endif

int checkzeros(char *first, char *last) {
    for (; first < last; ++first) {
        if (*first != 0) return 0;
    }
    return 1;
}

int main() {
    int i;
    int zeros = 0;

    #ifdef EMPTY
        /* empty test loop */
        for (i = 0; i < count; ++i) {
            char *p = malloc(blocksize);
            if (*p == 0) ++zeros;
            free(p);
        }
    #endif

    #ifdef LOOP
        /* simple check */
        for (i = 0; i < count; ++i) {
            char *p = malloc(blocksize);
            if (checkzeros(p, p + blocksize)) ++zeros;
            free(p);
        }
    #endif

    #ifdef MEMCMP
        /* memcmp check */
        for (i = 0; i < count; ++i) {
            char *p = malloc(blocksize);
            if (*p == 0 && !memcmp(p, p + 1, blocksize - 1)) ++zeros;
            free(p);
        }
    #endif

    printf("%d\n", zeros);
    return 0;
}

Results (cygwin, Windows XP, Core 2 Duo T7700 at 2.4 GHz):

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DEMPTY && time ./cmploop
1000000

real    0m0.500s
user    0m0.405s
sys     0m0.000s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DLOOP && time ./cmploop
1000000

real    0m1.203s
user    0m1.233s
sys     0m0.000s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DMEMCMP && time ./cmploop
1000000

real    0m2.859s
user    0m2.874s
sys     0m0.015s

So, the memcmp is taking approximately (2.8 - 0.4) / (1.2 - 0.4) = 3 times as long, for me. It'd be interesting to see other people's results - all my malloced memory is zeroed, so I'm getting the worst-case time for each comparison, always.

With smaller blocks (and more of them) the comparison time is less significant, but memcmp is still slower:

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DEMPTY -Dblocksize=20 -Dcount=10000000 && time ./cmploop
10000000

real    0m3.969s
user    0m3.780s
sys     0m0.030s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DLOOP -Dblocksize=20 -Dcount=10000000 && time ./cmploop
10000000

real    0m4.062s
user    0m3.968s
sys     0m0.015s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DMEMCMP -Dblocksize=20 -Dcount=10000000 && time ./cmploop
10000000

real    0m4.391s
user    0m4.296s
sys     0m0.015s

I am slightly surprised by this. I expected memcmp to at least compete, since I expect it to be inlined and to be optimised for small sizes known at compile time. Even changing it so that it tests an int at the start and then 16 bytes of memcmp, to avoid the unaligned worst case, doesn't speed it up much.

Steve Jessop
+1 for trying ;)
peterchen
Nice, +1 for measuring!
Per Ekman
+1 for actually measuring! I'll try to make my own benchmarks later when I have time. PS: what CPU/OS are you using? Maybe this could make a difference too.
Mark Byers
same goes for memcpy, by the way... :(
xtofl
I'm not surprised, as the memcmp may not be optimized for the given platform. I found that one compiler manufacturer didn't use some native processor capabilities, such as the load multiple registers in the ARM processor. If you unroll the loop, you will get better performance, as you divide the overhead over the number of instructions.
Thomas Matthews
Well, I said I was "a bit" surprised. This is gcc-4 on x86, and I've seen `memcpy` outrageously optimised as an intrinsic in other situations. So I was hoping it would do something impressive with memcmp too, I just don't know what.
Steve Jessop
Example of "outrageous": `int i = <something>; int j; memcpy( return j;`. The memcpy is optimised to a no-op, it just uses EAX for i in the first place. OK, there's no chance for register trickery in this problem, and no redundant variables to eliminate, but I was hoping the kind of mind capable of that would also be capable of doing a 16 byte same-alignment memcmp in 4 word comparisons (plus a little bit of work to identify the sign of the difference if it differs). Or something.
Steve Jessop
OK, I used your testbed now and it's close for 10M * 100bytes, but the loop wins. I also get that the gap widens as the length increases. The reason you always get zeros is that you keep getting the exact same pointer. It might be more realistic to ask for differing amounts of memory and/or not free them immediately.
Mark Byers
Yes, and/or write some data to them before freeing. See whether the malloc implementation is clearing them before allocating, or whether it's only zeros because it's fresh new memory for the process. Almost anything should be incredibly fast if the data *isn't* zero, because it can bail out early (although see Per Ekman's answer for one that doesn't, and benefits in the zero case).
Steve Jessop
I just tried it using MS VC++ 2008 compiler: the array returned isn't all zero, so you get almost identical times for both methods.
Mark Byers
Can you try gcc's auto-vectorization? It might be as easy as `-O3 -msse2`.
Adam Goode
While memcmp may be optimized, it's still a fundamentally inefficient way to perform this operation. We're interested in element-wise comparisons of two buffers. We're interested in whether all the elements in one buffer matches a single scalar value. Adding false memory dependencies is rarely the way to get good performance.
jalf
Interesting. On my machine, for a 1Gb memory block filles with zeros, `memcmp` trick is ~4 times faster than a dumb loop comparing individual chars, and ~3 times faster than a loop comparing int-sized chunks. This is VC++2010 x86, compiled with `/O2`.
Pavel Minaev
On a buffer _not_ filled with zeros (random garbage from `new char[]`), `memcmp` is still almost 2x faster than loop over chars, but is exactly the same as loop over ints.
Pavel Minaev
... however, I was using somewhat different call, specifically measuring performance of specific sections of blocks inside the process rather than the execution time of the process from start to finish. I used `GetTickCount`, which, given durations of 700+ milliseconds in best cases (for 1Gb), is accurate enough.
Pavel Minaev
Okay, turns out there was a typo in the test that skewed the result. I've also rewritten it to use `QueryPerformanceCounter` to get more precise value. Now with the fixed test, given the same input and environment, I get: "memcmp: 823ms;charloop: 1303ms;intloop: 814ms" - for random garbage memory block; "memcmp: 491mscharloop: 985ms;intloop: 479ms" - for pre-zeroed memory block.
Pavel Minaev
So at a reasonable approximation, memcmp is keeping pace with the intloop. I'm not hugely surprised - a dumb memcmp only does twice as many memory loads as the dump loop, and because of our parameters, those loads are from adjacent words. So all memcmp should really need is fewer cache misses than the loop (better cache pre-fetching than /O2 achieves), or to vectorise to bigger than a word. I guess either gcc is missing a trick with memcmp, or VC++ is missing a trick with the loop optimisation. Or both.
Steve Jessop
http://stackoverflow.com/questions/1872156/1876630#1876630 I made a more thorough benchmark; on my system, GCC's memcmp is in the same ballpark as all the other byte-by-byte access methods. Disassembly suggests that lack of alignment is preventing any further optimizations.
ephemient
+2  A: 

For large buffers:

typedef int tNativeInt;  // __int64 on 64 bit platforms with 32 bit ints

// test most of the buffer using CPU Word size
tNativeInt * ptr = reinterpret_cast<tNativeInt *>(buffer);
tNativeInt * end = ptr + bufSize / sizeof(tNativeInt);
for(;ptr < end;++ptr)
  if (*ptr != 0)
    return false;

// check remainder
char * ptrc = reinterpret_cast<char *>(ptr);
char * endc = ptrc + bufSize % sizeof(tNativeInt);
for(; ptrc<endc; ++ptrc)
  if (*ptrc != 0)
    return false;

Remarks:
The core optimizations testing full CPU words - reading one is generally as expensive as a single byte.

The code assumes the buffer is well aligned (i.e. the address is a multiple of the CPU Word size). If not, a block similar to "remainder" needs to be put in front of the block test.

The additional code will of course be slower for small buffers - however, in this case one commonly assumes that these short durations don't matter.

If you prefer you can of course replace the loops with std::find_if.


Performance: 1: 3.9

(VS 2008, /Ox /Ot, 2,47 +/- 0,11 vs. 0,63 +/- 0,19, for 10000 repeats over 256000 bytes, statistics over 15 repeats first removed)

Discussion: From my experience analyzing C/C++ to assembly, I wouldn't expect a compiler to do this optimization - because it is a pessimization for small size, and optimization possibilities of that type are few and far between. The factor of roughly 4 confirms the assumpotion - as does looking at the disassembly.

Also, the total time is negligible for most applications, a cache miss will be far worse and affect both versions the same.

[edit] for the fun of it:

Overlapping memcmp clocks in at 1:1.4, which is vastly better than the single byte check (surprised me a little).

Note that the misaligned read makes that strongly platform dependent.

peterchen
I would expect the compiler to do that optimization (not reading onebyte at a time, but reading words). Have you seen this buy you any performance with -O2 for instance?
Per Ekman
This relies on the fact that buffer is a return from malloc. Which is stated in the question, so fair enough, just be aware that you can't use just any old char* for buffer, because it might not be aligned. Also, it's undefined to reinterpret_cast to tNativeInt* and dereference, but we can probably assume a platform which supports that.
Steve Jessop
@Per: See update. ... @Steve: premainder implementation is left as an excercise for the reader ;)
peterchen
Interesting, thanks.
Per Ekman
http://stackoverflow.com/questions/1872156/1876630#1876630 I see a roughly 1:4 or 1:8 improvement depending on 32-bit or 64-bit using raw assembly, and only around a 1:4 improvement in C either way.
ephemient
ephemient: are you using __int64 explicitely? sizeof(int) == 32 bit is a common choice also on 64 bit platforms.
peterchen
+2  A: 

Poking around with Steve Jessops code for fun I found this variant

int checkzeros(char *f, char *l) {
        char a = 0;
        while (f < l) {
                a |= *f++;
        }
        if (a) {
                return 0;
        }
        return 1;
}

to be about 50% faster (no branches in the core loop). All bugs are mine.

[Edit]: As Steve points out, this version has a good worst case and a terrible best case (since they are the same). Only use it if a completely zeroed buffer is the only case that needs to be fast.

Per Ekman
Good point - this version is good if you expect checkzeros to be true, and bad if the buffer contains random data. In that case, my loop will bail out after one byte with probability 255/256, whereas yours always runs to the end, so I'd hope mine is more than 50% faster.
Steve Jessop
A: 

Worst case is when an array is not zero. You have to make two passes: one to check for zero and the other to set the array to zero. To save time, just force it to zeros.

Thomas Matthews
+1  A: 
ephemient
+2  A: 

More benchmarks:

Roughly based on Steve Jessop's sample. I've tested the following:

  • Naive memcmp (allocate a separate block of zeros, and compare against that)
  • "clever" memcmp ( compare the block against itself, shifted once)
  • std::find_if
  • A simple loop checking each byte

None of these make any assumptions about the array, and simply accept and work on an array of chars.

Finally, I made a fifth version, which casts the array to ints, and compares those. (This one obviously assumes that the size of the array is divisible by sizeof(int), so it is less general. But I added it to demonstrate that working with a reasonable chunk size is a much more useful optimization than messing around with memcpy and byte-wise comparisons.

Oh, and note that I just slapped this test together quickly, and I used one of Windows' timers because I'm lazy. :)

#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>

#include <windows.h>

enum {
    count = 1000*1000,
    blocksize = 1024
};

bool test_simple_loop(char* p){
    for (int i = 0; i < blocksize; ++i) {
     if (p[i] != 0) { return false; }
    }
    return true;
}

bool test_memcmp_clever(char* p){
    return *p == 0 && memcmp(p, p + 1, blocksize - 1) == 0;
}
bool test_memcmp_naive(char* p, char* ref){
    return memcmp(p, ref, blocksize) == 0;
}

struct cmp {
    template <typename T>
    bool operator()(T& x) {
     return x != 0;
    }
};
bool test_find_if(char* p){
    return std::find_if(p, p+blocksize, cmp()) == p+blocksize;
}

bool test_find_if_big(int* p){
    return std::find_if(p, p+blocksize, cmp()) == p+blocksize;
}

int main() {

    bool res = true;

    char *p = new char[blocksize];
    char *ref = new char[blocksize];

    std::fill(ref, ref+blocksize, 0);
    std::fill(p, p+blocksize, 0); // ensure the worst-case scenario, that we have to check the entire buffer. This will also load the array into CPU cache so the first run isn't penalized

    DWORD times[5];
    DWORD start;

    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
     res &= test_memcmp_naive(p, ref);
    }
    times[0] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
     res &= test_memcmp_clever(p);
    }
    times[1] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
     res &= test_find_if(p);
    }
    times[2] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
     res &= test_simple_loop(p);
    }
    times[3] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
     res &= test_find_if_big(reinterpret_cast<int*>(p));
    }
    times[4] = GetTickCount() - start;

    delete[] p;
    delete[] ref;

    printf("%d\n", res);
    printf("%d\n%d\n%d\n%d\n%d\n", times[0], times[1], times[2], times[3], times[4]);
}

My results are: (in milliseconds, for a million runs)

Naive memcmp: 546
"Clever" memcmp: 530
`find_if<char>`: 1466
Simple loop: 1358
`find_if<int`>: 343

I think the takeaway point is pretty clear: Anything that does a bytewise comparison is slow. Really slow. Memcmp does more or less ok, but it's far from perfect. It is too general to be optimal.

The most efficient way to solve this problem is to process as much data at a time as possible. char is just silly. int is a good start, but 64- or 128-bit reads would probably perform far better still.

jalf
Would be interesting to know the time of memset to 0 aswell.
Viktor Sehr
I'd expect that to be by far the fastest. You save all the comparisons and dependencies on memory accesses.
jalf
jalf: +1 for taking the time to do this - it's fascinating to me that something so simple as testing for zero can create so much discussion! But I would like to know why do you claim that memcmp is the slower than a simple loop when your own tests show it to be faster? Am I missing something here?
Mark Byers
Sorry if it wasn't clear. I meant that it was slower than a simple loop with a larger word size. `std::find_if` is basically the same algorithm as a simple loop, so I used that as a representative of "simpler loop with larger word size".
jalf