cmemcmp

memcmp but need to compare block with fixed value


I need to compare a block of memory to a fixed value in C. Can I do this with memcmp? Something like:

memcmp (starting_address , fixed_value , num_byte)

I need fixed_value to be a fixed value not the starting address of a block.

  1. Writing the fixed value to an entire temporary memory block is not an option because I have limited space.
  2. Using a loop to write and check memory one by one is not an option because it's very slow.

If it's not possible can anyone tell me a solution that is as fast (or faster) than memcmp?

Thanks,

EDIT: Let's say I have 5GB of memory that holds 0's. And I'm trying to make sure they're all 0's. Is it safe to check the first byte of the block then do this:

memcmp (starting_address , starting_address + ONE_BYTE , FIVE_GB); ?

EDIT: This is why I need to use memcmp and not a user defined loop:

This code took 546 clock ticks to run:

memset(0x80000000 , 0x1 , 0x10000000);
memset(0x90000000 , 0x1 , 0x10000000);
memcmp(0x80000000 , 0x90000000 , 0x10000000);

vs this one that took 7669 clock ticks:

unsigned int i;
int flag = 0;
int *p = 0x80000000;
int *q = 0x90000000;
while(p < 0x90000000)
{
    if(*p++ != *q++)
    {
        flag = 1;
    }
}

Solution

  • I just tested this loop on my Mac, and it beats memcmp:

    uint64_t *p = (uint64_t *)buffer1;
    uint64_t compare;
    memset(&compare, 1, sizeof compare);
    for (i = 0; i < length/sizeof compare; i++)
    {
        if (p[i] != compare)
            break;
    }
    

    Complete example code:

    #include <stdio.h>
    #include <string.h>
    #include <sys/resource.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    // from: http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
    void timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
    {
        /* Perform the carry for the later subtraction by updating y. */
        if (x->tv_usec < y->tv_usec)
        {
            int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
            y->tv_usec -= 1000000 * nsec;
            y->tv_sec += nsec;
        }
    
        if (x->tv_usec - y->tv_usec > 1000000)
        {
            int nsec = (x->tv_usec - y->tv_usec) / 1000000;
            y->tv_usec += 1000000 * nsec;
            y->tv_sec -= nsec;
        }
    
        /* Compute the time remaining to wait. tv_usec is certainly positive. */
        result->tv_sec = x->tv_sec - y->tv_sec;
        result->tv_usec = x->tv_usec - y->tv_usec;
    }
    
    int main(int argc, char **argv)
    {
        struct rusage before;
        struct rusage after;
        struct timeval diff;
        size_t i;
    
        size_t length = strtoull(argv[1], NULL, 0);
    
        char *buffer1 = malloc(length);
        char *buffer2 = malloc(length);
    
        printf("filling...");
        fflush(stdout);
        memset(buffer1, 1, length);
        memset(buffer2, 1, length);
        printf(" done\n");
    
        getrusage(RUSAGE_SELF, &before);
        uint64_t *p = (uint64_t *)buffer1;
        uint64_t compare;
        memset(&compare, 1, sizeof compare);
        for (i = 0; i < length/sizeof compare; i++)
        {
            if (p[i] != compare)
                break;
        }
        if (i == length/sizeof compare)
            i = 0;
        getrusage(RUSAGE_SELF, &after);
    
        printf("\nloop (returned %zu):\n", i);
        timeval_subtract(&diff, &after.ru_utime, &before.ru_utime);
        printf("User:   %ld.%06d s\n", diff.tv_sec, diff.tv_usec);
    
        timeval_subtract(&diff, &after.ru_stime, &before.ru_stime);
        printf("System: %ld.%06d s\n", diff.tv_sec, diff.tv_usec);
    
        getrusage(RUSAGE_SELF, &before);
        i = memcmp(buffer1, buffer2, length);
        getrusage(RUSAGE_SELF, &after);
    
        printf("\nmemcmp (returned %zu):\n", i);
        timeval_subtract(&diff, &after.ru_utime, &before.ru_utime);
        printf("User:   %ld.%06d s\n", diff.tv_sec, diff.tv_usec);
    
        timeval_subtract(&diff, &after.ru_stime, &before.ru_stime);
        printf("System: %ld.%06d s\n", diff.tv_sec, diff.tv_usec);
    
        return 0;
    }
    

    And run results:

    $ make
    clang -Wall -Wextra -Werror -O3 -g -o example example.c
    ./example 0x10000000
    filling... done
    
    loop (returned 0):
    User:   0.024078 s
    System: 0.000011 s
    
    memcmp (returned 0):
    User:   0.036752 s
    System: 0.000017 s
    

    Maybe you can do something similar?

    Note: For those concerned about cache warming, I also tried with the memcmp before the loop and got the same results.