How to check whether all bytes in a memory block are zero

后端 未结 10 706
渐次进展
渐次进展 2021-02-03 21:05

I have a block of memory with elements of fixed size, say 100 bytes, put into it one after another, all with the same fixed length, so memory looks like this

&l         


        
10条回答
  •  死守一世寂寞
    2021-02-03 21:48

    I have tested some solutions proposed here and checked memcmp source code which is not optimized for the OP needs since it has an additional requirement to perform sorting, leading it to compare unsigned char one by one.

    In the following, I propose an optimized function check_memory_zeroed which performs most of the check on the biggest aligned int available, making it portable, and I compare it with the other solutions proposed in this thread. Time measurement is performed and results printed.

    It shows that the proposed solution is near twice better than wallyk's obvious portable high efficiency method and does not need to create an additional array, and six times better than char by char comparison or mihaif's shifted array which saves RAM compared to wallyk's one.

    I have also tested my solution without aligning the words check_memory_zeroed_bigestint_not_aligned and surprisingly, it performs even better. If someone has an explanation, he is welcome.

    Here is the code with functional and performance tests on a 1Gb table (the proposed optimized function is the fisrt one : check_memory_zeroed):

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define BIG_TAB_SIZE 1000000000
    
    typedef intmax_t biggestint;
    
    int check_memory_zeroed (void* ptr, size_t size)
    {
        if (ptr == NULL) return -1;
        int bis = sizeof(biggestint);
        char* pc = (char*) ptr;
        biggestint* pbi0 = (biggestint*) pc;
        if ((size_t) pc % bis) /* is aligned ? */
            pbi0 = (biggestint*) (pc + (bis - ((size_t) pc % bis))); /* minimal pointer larger than ptr but aligned */
        assert ((size_t) pbi0 % bis == 0); /* check that pbi0 is aligned */
        for (char* p = pc; p < (char*) pbi0; p++)
            if(*p) return 0; /* check beginning of non aligned array */
        biggestint* pbi = pbi0;
        biggestint* pbiUpper = ((biggestint*) (pc + size)) - 1;
        for (;pbi <= pbiUpper; pbi++)
            if(*pbi) return 0; /* check with the biggest int available most of the array : its aligned part */
        for (char* p = (char*) pbi; p < pc + size; p++)
            if(*p) return 0; /* check end of non aligned array */
        return 1;
    }
    
    int check_memory_zeroed_bigestint_not_aligned (void* ptr, size_t size)
    {
        if (ptr == NULL) return -1;
        biggestint* pbi = (biggestint*) ptr;
        biggestint* pbiUpper = ((biggestint*) (((char*) ptr) + size)) - 1;
        for (;pbi <= pbiUpper; pbi++)
            if(*pbi) return 0; /* check with the biggest int available most of the array, but without aligning it */
        for (char* p = (char*) pbi; p < ((char*) ptr) + size; p++)
            if(*p) return 0; /* check end of non aligned array */
        return 1;
    }
    
    int check_memory_zeroed_by_char (void* ptr, size_t size)
    {
        if (ptr == NULL) return -1;
        for (char* p = (char*) ptr; p < ((char*) ptr) + size; p++)
            if(*p) return 0;
        return 1;
    }
    
    /* variant of wallyk solution */
    int check_memory_zeroed_by_memcmp_and_testblock (void* ptr, size_t size)
    {
        void* testblock = malloc(size);
        if (ptr == NULL || testblock == NULL) return -1;
        memset (testblock, 0, sizeof(testblock));
        int res = ! memcmp (testblock, ptr, size);
        free (testblock);
        return res;
    }
    
    /* variant of mihaif solution */
    int check_memory_zeroed_by_memcmp_with_shifted_array (void* ptr, size_t size)
    {
        if (ptr == NULL) return -1;
        char* pc = (char*) ptr;
        return (*pc) || memcmp(pc, pc + 1, size - 1);
    }
    
    int test() {
        /* check_memory_zeroed (void* ptr, size_t size) */
        char tab[16];
        for (int i = 0; i < 8; i++)
            for (int j = 0; j < 8; j++) {
                for (int k = 0; k < 16; k++) tab[k] = (k >= i && k < 16 - j) ? 0 : 100 + k;
                assert(check_memory_zeroed(tab + i, 16 - j - i));
                if (i > 0) assert(tab[i-1] == 100 + i - 1);
                if (j > 0) assert(tab[16 - j] == 100 + 16 - j);
                for (int k = i; k < 16 - j; k++) {
                    tab[k] = 200+k;
                    assert(check_memory_zeroed(tab + i, 16 - j - i) == 0);
                    tab[k] = 0;
                }
            }
        char* bigtab = malloc(BIG_TAB_SIZE);
        clock_t t = clock();
        printf ("Comparison of different solutions execution time for checking an array has all its values null\n");
        assert(check_memory_zeroed(bigtab, BIG_TAB_SIZE) != -1);
        t = clock() - t;
        printf ("check_memory_zeroed optimized : %f seconds\n",((float)t)/CLOCKS_PER_SEC);
        assert(check_memory_zeroed_bigestint_not_aligned(bigtab, BIG_TAB_SIZE) != -1);
        t = clock() - t;
        printf ("check_memory_zeroed_bigestint_not_aligned : %f seconds\n",((float)t)/CLOCKS_PER_SEC);
        assert(check_memory_zeroed_by_char(bigtab, BIG_TAB_SIZE) != -1);
        t = clock() - t;
        printf ("check_memory_zeroed_by_char : %f seconds\n",((float)t)/CLOCKS_PER_SEC);
        assert(check_memory_zeroed_by_memcmp_and_testblock(bigtab, BIG_TAB_SIZE) != -1);
        t = clock() - t;
        printf ("check_memory_zeroed_by_memcmp_and_testblock by wallyk : %f seconds\n",((float)t)/CLOCKS_PER_SEC);
        assert(check_memory_zeroed_by_memcmp_with_shifted_array(bigtab, BIG_TAB_SIZE) != -1);
        t = clock() - t;
        printf ("check_memory_zeroed_by_memcmp_with_shifted_array by mihaif : %f seconds\n",((float)t)/CLOCKS_PER_SEC);
        free (bigtab);
    
        return 0;
    }
    
    int main(void) {
        printf("Size of intmax_t = %lu\n", sizeof(intmax_t));
        test();
        return 0;
    }
    

    And the results for comparison of different solutions execution time for checking an array has all its values null:

    • Size of intmax_t = 8
    • check_memory_zeroed optimized : 0.331238 seconds
    • check_memory_zeroed_bigestint_not_aligned : 0.260504 seconds
    • check_memory_zeroed_by_char : 1.958392 seconds
    • check_memory_zeroed_by_memcmp_and_testblock by wallyk : 0.503189 seconds
    • check_memory_zeroed_by_memcmp_with_shifted_array by mihaif : 2.012257 seconds

提交回复
热议问题