簡體   English   中英

我如何知道內存段的所有零點

[英]How can I know where the segment of memory is all Zero

我的意思是,我的malloc內存段,也許1K也許20字節..假設指針pMem我怎么能知道內容pMem refered都是Zero\\0 我知道memcmp但第二個參數應該是另一個內存地址... thanx

正如其他人已經建議你可能想要memsetcalloc

但是,如果您確實想要檢查內存區域是否全為零,則可以將其與自身進行比較,但是將其移動一個。

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

其中length是您想要為零的字節數。

由於馬克的回答引起了一些爭議:

#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;
}

結果(cygwin,Windows XP,Core 2 Duo T7700在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

因此,對於我來說,memcmp大約需要(2.8 - 0.4)/(1.2 - 0.4)= 3倍。 看到其他人的結果很有意思 - 我的所有malloced內存都歸零,所以我總是得到每次比較的最壞情況時間。

對於較小的塊(以及更多的塊),比較時間不太重要,但memcmp仍然較慢:

$ 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

我對此感到有些驚訝。 我期望memcmp至少能夠競爭,因為我希望它能夠內聯並針對編譯時已知的小尺寸進行優化。 即使更改它以便它在開始時測試一個int然后再測試16個字節的memcmp,以避免未對齊的最壞情況,也不會加快它的速度。

如果你正在測試它,然后只在它為0時才使用它,那么請注意你有一個競爭條件,因為@Mark Byers建議的方法沒有原子測試/設置操作。 在這種情況下,很難讓邏輯正確。

如果你想將它歸零,如果它還不為零,那么只需將其設置為零,因為它會更快。

C ++解決方案:

bool all_zeroes = 
  (find_if( pMem, pMem+len, bind2nd(greater<unsigned char>(), 0)) == (pMem+len));

正如您所指出的, memcmp將一塊內存與另一塊內存進行比較。 如果您已經知道的另一塊內存全部為零,那么您可以使用該引用塊與候選塊進行比較,看它們是否匹配。

聽起來你沒有另一塊記憶。 你只有一個,你想知道它是否全部為零。 標准庫不提供這樣的功能,但是編寫自己的函數很容易:

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

如果你想分配一個新的內存塊並立即將它全部歸零,那么使用calloc而不是malloc 如果您要將內存塊設置為全零,則使用memsetstd::fill

如果要分配內存中的所有0,可以使用calloc

對於大緩沖區:

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;

備注:
測試完整CPU字的核心優化 - 讀取一個字通常和單個字節一樣昂貴。

代碼假定緩沖區已經很好地對齊(即地址是CPU字大小的倍數)。 如果不是,則需要在塊測試之前放置類似於“余數”的塊。

對於小緩沖區,附加代碼當然會慢一些 - 但是,在這種情況下,通常假設這些短持續時間無關緊要。

如果您願意,您當然可以用std :: find_if替換循環。


表現:1:3.9

(VS 2008,/ Ox / Ot,2,47 +/- 0,11與0,63 +/- 0,19,超過256000字節10000次重復,超過15次重復的統計數據首先被刪除)

討論:從我分析C / C ++到匯編的經驗來看,我希望編譯器進行這種優化 - 因為它對於小size來說是一種悲觀,並且這種類型的優化可能性很少。 大致為4的因素證實了這一點 - 正如看反匯編一樣。

此外,對於大多數應用程序來說,總時間可以忽略不計,緩存未命中將會更糟,並且會影響兩個版本。

[編輯]為了它的樂趣:

以1:1.4重疊的memcmp時鍾 ,這比單字節檢查要好得多(讓我感到有些驚訝)。

請注意,未對齊的讀取使得強烈依賴於平台。

如果你需要內存為零,只需將memset()設置為零; 檢查它是否為零是浪費時間,因為它可能不是,你最終會做更多的工作,檢查然后設置。

但是,如果你真的想要有效地檢查一個內存區域以查看它是否全為零,你可以將memcmp()與其他已知為零的東西進行對比。 例如,您可以分配和歸零一個內存塊,然后保留指向它的指針,以便與其他內存塊進行比較。

另一種C ++解決方案,比Kirill稍微簡單一些。 但是,它的效率稍低,因為即使該序列包含非零元素,它也會遍歷整個序列。

bool all_zeroes = std::count(pMem, pMem + length, 0) == length;

借助Steve Jessops代碼尋找樂趣,我發現了這個變種

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

大約快50%(核心循環中沒有分支)。 所有的錯誤都是我的。

[編輯]:史蒂夫指出,這個版本有一個很好的最壞情況和一個可怕的最佳情況(因為它們是相同的)。 只有在完全歸零的緩沖區是唯一需要快速的情況時才使用它。

更多基准:

大致基於Steve Jessop的樣本。 我測試了以下內容:

  • 天真的mem​​cmp(分配一個單獨的零塊,並與之比較)
  • “聰明”的memcmp(將塊與自身進行比較,移位一次)
  • std::find_if
  • 一個簡單的循環檢查每個字節

這些都沒有對數組作出任何假設,只是接受並處理一組字符。

最后,我制作了第五個版本,它將數組轉換為整數,並對其進行比較。 (這個顯然假設數組的大小可以被sizeof(int)整除,所以它不太通用。但是我添加它來證明使用合理的塊大小比使用memcpy和按字節比較。

哦,請注意我剛剛把這個測試快速打到了一起,我使用了一個Windows定時器因為我很懶。 :)

#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]);
}

我的結果是:(以毫秒為單位,一百萬次運行)

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

我認為要點非常明確:任何進行字節比較的東西都很慢。 真的很慢。 Memcmp或多或少都可以,但它遠非完美。 太籠統而不是最佳。

解決此問題的最有效方法是盡可能多地處理盡可能多的數據。 char很傻。 int是一個很好的開始,但64位或128位讀取可能會更好地執行。

repe.S

.globl repe_scasb
repe_scasb:
#if defined(__i386__)
        push   %edi
        mov    $0x0,%al
        mov    0xc(%esp),%ecx
        mov    0x8(%esp),%edi
        sub    %edi,%ecx
        repe scasb
        pop    %edi
        sete   %al
        ret
#elif defined(__amd64__)
        mov    $0x0,%al
        mov    %rsi,%rcx
        sub    %rdi,%rcx
        repe scasb
        sete   %al
        ret
#else
#  error "repe_scasb not defined for current architecture"
#endif

.globl repe_scas
repe_scas:
#if defined(__i386__)
        push   %edi
        mov    $0x0,%eax
        mov    0xc(%esp),%edx
        mov    0x8(%esp),%edi
        sub    %edi,%edx
repe_scas4:
        test   $0x3,%di
        jnz    repe_scas2
        cmp    $0x4,%edx
        jl     repe_scas2
        mov    %edx,%ecx
        shr    $0x2,%ecx
        repe scasl
        jne    repe_scas0
        and    $0x3,%edx
repe_scas2:
        test   $0x1,%di
        jnz    repe_scas1
        cmp    $0x2,%edx
        jl     repe_scas1
        scasw
        jnz    repe_scas0
        sub    $0x2,%edx
        jmp    repe_scas4
repe_scas1:
        test   %edx,%edx
        jz     repe_scas0
        scasb
        jnz    repe_scas0
        sub    $0x1,%edx
        jmp    repe_scas4
repe_scas0:
        pop    %edi
        sete   %al
        ret
#elif defined(__amd64__)
        mov    $0x0,%eax
        sub    %rdi,%rsi
repe_scas8:
        test   $0x7,%di
        jnz    repe_scas4
        cmp    $0x8,%rsi
        jl     repe_scas4
        mov    %rsi,%rcx
        shr    $0x3,%rcx
        repe scasq
        jne    repe_scas0
        and    $0x7,%rsi
repe_scas4:
        test   $0x3,%di
        jnz    repe_scas2
        cmp    $0x4,%rsi
        jl     repe_scas2
        scasl
        jnz    repe_scas0
        sub    $0x4,%rsi
        jmp    repe_scas8
repe_scas2:
        test   $0x1,%di
        jnz    repe_scas1
        cmp    $0x2,%rsi
        jl     repe_scas1
        scasw
        jnz    repe_scas0
        sub    $0x2,%rsi
        jmp    repe_scas8
repe_scas1:
        test   %rsi,%rsi
        jz     repe_scas0
        scasb
        jnz    repe_scas0
        sub    $0x1,%rsi
        jmp    repe_scas8
repe_scas0:
        sete   %al
        ret
#else
#  error "repe_scas not defined for current architecture"
#endif

test.c

#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static int compar_double(const void *a, const void *b) {
    double diff = *(const double *)a - *(const double *)b;
    if (diff < 0) return -1;
    if (diff > 0) return 1;
    return 0;
}

static bool bit_or(const void *first, const void *last) {
    uint8_t a;
    for (a = 0; first < last; first = (const uint8_t *)first + 1)
        a |= *(const uint8_t *)first;
    return !a;
}

static bool use_memcmp(const void *first, const void *last) {
    return first >= last
        || !(((uint8_t *)first)[0]
        || memcmp(first, (const uint8_t *)first + 1,
            (const uint8_t *)last - (const uint8_t *)first - 1));
}

static bool check_bytes(const void *first, const void *last) {
    while (first < last) {
        if (*(const uint8_t *)first) return false;
        first = (const uint8_t *)first + 1;
    }
    return true;
}

static bool check_aligned(const void *first, const void *last) {
    switch ((uintptr_t)first & 7) while (first < last) {
        case 0:
            if (last - first >= 8) {
                if (*(const uint64_t *)first) return false;
                first = (const uint64_t *)first + 1;
                continue;
            }
        case 4:
            if (last - first >= 4) {
                if (*(const uint32_t *)first) return false;
                first = (const uint32_t *)first + 1;
                continue;
            }
        case 2: case 6:
            if (last - first >= 2) {
                if (*(const uint16_t *)first) return false;
                first = (const uint16_t *)first + 1;
                continue;
            }
        case 1: case 3: case 5: case 7:
            if (*(const uint8_t *)first) return false;
            first = (const uint8_t *)first + 1;
    }
    return true;
}

bool repe_scasb(const void *, const void *);
bool repe_scas(const void *, const void *);

static const struct {
    const char name[16];
    bool (*fn)(const void *, const void *);
} functions[] = {
    { "bit_or", bit_or },
    { "use_memcmp", use_memcmp },
    { "check_bytes", check_bytes },
    { "check_aligned", check_aligned },
    { "repe_scasb", repe_scasb },
    { "repe_scas", repe_scas },
};

#define REPS 999
#define BYTECYCLES 0xFFFF
void time_functions(const char *s, const void *first, const void *last, bool expect) {
    unsigned i, cycles = BYTECYCLES / (last - first) + 1;
    char seps[sizeof(functions) / sizeof(*functions)];
    double times[sizeof(functions) / sizeof(*functions)][REPS];

    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++) {
        unsigned j;

        seps[i] = '/';
        for (j = 0; j < REPS; j++) {
            unsigned k;
            struct timespec start, finish;
            clock_gettime(CLOCK_MONOTONIC, &start);
            for (k = 0; k < cycles; k++)
                if (functions[i].fn(first, last) != expect) seps[i] = '!';
            clock_gettime(CLOCK_MONOTONIC, &finish);
            times[i][j] = ((finish.tv_sec - start.tv_sec) +
                    (finish.tv_nsec - start.tv_nsec) / 100000000.) / cycles;
        }
    }

    fputs(s, stdout);
    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++) {
        qsort(times[i], REPS, sizeof(double), compar_double);
        printf("|%8.2e%c%8.2e", times[i][REPS / 4], seps[i], times[i][3 * REPS / 4]);
    }
    putchar('\n');
}

static size_t sizes[] = {0x7, 0x7, 0x7, 0x7, 0x400, 0x1000, 0x100000};
static uint8_t storage[0x100000];

int main() {
    unsigned i, j, k;

    fputs("      ", stdout);
    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++)
        printf(" |%16.16s", functions[i].name);
    fputs("\n-------", stdout);
    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++)
        fputs("+-----------------", stdout);
    putc('\n', stdout);

    for (j = 0, k = 8; j < sizeof(sizes) / sizeof(*sizes); j++) {
        char test[8];
        if (k /= 2) snprintf(test, sizeof(test), "0x%zX+%u", sizes[j], k);
        else snprintf(test, sizeof(test), "0x%zX", sizes[j]);
        printf("%-7.7s|\n", test);

        memset(storage + k, 0, sizes[j]);
        time_functions("  zero ", storage + k, storage + k + sizes[j], true);

        storage[k + sizes[j] - 1] = 1;
        time_functions("  last ", storage + k, storage + k + sizes[j], false);

        storage[k + sizes[j] / 2] = 1;
        time_functions("  half ", storage + k, storage + k + sizes[j], false);

        memset(storage + k, ~0, sizes[j]);
        time_functions("  first", storage + k, storage + k + sizes[j], false);
    }

    return 0;
}

Makefile

CFLAGS ?= -g -O3 -W -Wall -Wextra
LIBS = -lrt
SRC := test.c repe.S
all: test32 test64
test32: $(SRC)
        $(CC) -m32 $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
test64: $(SRC)
        $(CC) -m64 $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
time: time32 time64
time32: test32
        ./test32
time64: test64
        ./test64
.PHONY: all time time32 time64

這個測試顯示的是第一個四分位數和第三個四分位數的時間,而不僅僅是平均值,但似乎系統相當一致(運行在±2%內變化)。

$ make time
cc -m32 -g -O3 -W -Wall -Wextra  -o test32 test.c repe.S -lrt
./test32
       |          bit_or |      use_memcmp |     check_bytes |   check_aligned |      repe_scasb |       repe_scas
-------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------
0x7+4  |
  zero |1.09e-07/1.09e-07|2.09e-07/2.11e-07|1.66e-07/1.68e-07|1.35e-07/1.74e-07|1.83e-07/1.86e-07|2.00e-07/2.06e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.12e-07|1.00e-07/1.00e-07|1.18e-07/1.18e-07|1.83e-07/1.85e-07|1.83e-07/1.85e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.84e-07|7.42e-08/7.42e-08|6.98e-08/6.98e-08|1.57e-07/1.59e-07|1.39e-07/1.40e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|6.98e-08/6.99e-08|1.22e-07/1.27e-07|1.39e-07/1.42e-07
0x7+2  |
  zero |1.09e-07/1.09e-07|2.09e-07/2.11e-07|1.66e-07/1.71e-07|1.31e-07/1.57e-07|1.83e-07/1.85e-07|2.00e-07/2.06e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.00e-07/1.00e-07|1.22e-07/1.24e-07|1.83e-07/1.88e-07|1.83e-07/1.83e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.80e-07|7.42e-08/7.42e-08|8.72e-08/8.72e-08|1.57e-07/1.59e-07|1.61e-07/1.66e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|6.55e-08/6.55e-08|1.22e-07/1.22e-07|5.82e-08/5.82e-08
0x7+1  |
  zero |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.66e-07/1.66e-07|1.09e-07/1.42e-07|1.83e-07/1.88e-07|2.05e-07/2.07e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.00e-07/1.00e-07|1.00e-07/1.00e-07|1.83e-07/1.87e-07|1.92e-07/1.97e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.81e-07|7.42e-08/7.42e-08|7.85e-08/7.86e-08|1.57e-07/1.61e-07|1.92e-07/1.97e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|5.24e-08/5.24e-08|1.22e-07/1.22e-07|6.55e-08/6.55e-08
0x7    |
  zero |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.66e-07/1.71e-07|1.52e-07/1.79e-07|1.83e-07/1.88e-07|2.00e-07/2.06e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.00e-07/1.00e-07|1.44e-07/1.70e-07|1.83e-07/1.88e-07|1.83e-07/1.85e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.79e-07|7.42e-08/7.42e-08|7.85e-08/7.85e-08|1.57e-07/1.57e-07|1.39e-07/1.39e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|7.85e-08/7.85e-08|1.22e-07/1.22e-07|1.39e-07/1.39e-07
0x400  |
  zero |9.06e-06/9.06e-06|9.97e-06/9.97e-06|1.79e-05/1.81e-05|2.93e-06/2.93e-06|9.06e-06/9.07e-06|2.41e-06/2.41e-06
  last |9.06e-06/9.06e-06|9.97e-06/9.97e-06|1.80e-05/1.80e-05|2.39e-06/2.39e-06|9.06e-06/9.07e-06|2.40e-06/2.40e-06
  half |9.06e-06/9.06e-06|5.08e-06/5.08e-06|9.06e-06/9.06e-06|1.29e-06/1.29e-06|4.62e-06/4.62e-06|1.30e-06/1.30e-06
  first|9.06e-06/9.06e-06|9.25e-08/9.67e-08|8.34e-08/9.67e-08|1.05e-07/1.06e-07|1.58e-07/1.58e-07|1.75e-07/1.75e-07
0x1000 |
  zero |3.59e-05/3.59e-05|3.95e-05/3.95e-05|7.15e-05/7.15e-05|1.14e-05/1.14e-05|3.59e-05/3.59e-05|9.20e-06/9.20e-06
  last |3.59e-05/3.59e-05|3.95e-05/3.95e-05|3.59e-05/3.59e-05|9.18e-06/9.18e-06|3.59e-05/3.59e-05|9.19e-06/9.19e-06
  half |3.59e-05/3.59e-05|1.99e-05/1.99e-05|1.81e-05/1.81e-05|4.74e-06/4.74e-06|1.81e-05/1.81e-05|4.74e-06/4.75e-06
  first|3.59e-05/3.59e-05|2.04e-07/2.04e-07|2.04e-07/2.04e-07|2.13e-07/2.13e-07|2.65e-07/2.66e-07|2.82e-07/2.82e-07
0x10000|
  zero |9.52e-03/1.07e-02|1.14e-02/1.17e-02|1.94e-02/2.04e-02|3.43e-03/3.52e-03|9.59e-03/1.07e-02|3.10e-03/3.17e-03
  last |9.57e-03/1.07e-02|1.14e-02/1.17e-02|9.73e-03/1.08e-02|3.04e-03/3.13e-03|9.57e-03/1.05e-02|3.11e-03/3.22e-03
  half |9.54e-03/1.06e-02|5.06e-03/5.13e-03|4.69e-03/4.76e-03|1.17e-03/1.17e-03|4.60e-03/4.65e-03|1.18e-03/1.18e-03
  first|9.55e-03/1.07e-02|2.28e-06/2.29e-06|2.26e-06/2.27e-06|2.28e-06/2.29e-06|2.34e-06/2.35e-06|2.36e-06/2.36e-06
cc -m64 -g -O3 -W -Wall -Wextra  -o test64 test.c repe.S -lrt
./test64
       |          bit_or |      use_memcmp |     check_bytes |   check_aligned |      repe_scasb |       repe_scas
-------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------
0x7+4  |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.26e-07/1.26e-07|1.52e-07/1.52e-07|2.57e-07/2.67e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.17e-07|1.09e-07/1.09e-07|1.52e-07/1.52e-07|1.70e-07/1.70e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|5.66e-08/5.66e-08|1.26e-07/1.26e-07|7.83e-08/7.83e-08
  first|9.14e-08/9.14e-08|4.79e-08/4.79e-08|5.23e-08/5.23e-08|5.66e-08/5.66e-08|1.00e-07/1.00e-07|7.83e-08/7.83e-08
0x7+2  |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.26e-07/1.26e-07|1.52e-07/1.52e-07|2.30e-07/2.57e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.04e-07|1.09e-07/1.09e-07|1.52e-07/1.52e-07|2.22e-07/2.22e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|7.83e-08/7.83e-08|1.26e-07/1.26e-07|1.09e-07/1.09e-07
  first|9.14e-08/9.14e-08|4.79e-08/4.79e-08|5.23e-08/5.23e-08|5.66e-08/5.66e-08|1.00e-07/1.00e-07|7.40e-08/7.40e-08
0x7+1  |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.17e-07/1.17e-07|1.52e-07/1.52e-07|2.30e-07/2.32e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.04e-07|1.04e-07/1.13e-07|1.52e-07/1.52e-07|1.52e-07/1.52e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|7.40e-08/7.40e-08|1.26e-07/1.26e-07|1.52e-07/1.52e-07
  first|9.14e-08/9.14e-08|3.92e-08/3.92e-08|4.36e-08/4.36e-08|4.79e-08/4.79e-08|1.00e-07/1.00e-07|7.83e-08/7.83e-08
0x7    |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.52e-07/1.52e-07|1.52e-07/1.52e-07|2.39e-07/2.65e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.04e-07|1.26e-07/1.26e-07|1.52e-07/1.52e-07|1.70e-07/1.70e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|6.53e-08/6.53e-08|1.26e-07/1.26e-07|8.70e-08/8.70e-08
  first|9.14e-08/9.14e-08|4.79e-08/4.79e-08|5.23e-08/5.23e-08|6.53e-08/6.53e-08|1.00e-07/1.00e-07|8.70e-08/8.70e-08
0x400  |
  zero |9.04e-06/9.04e-06|9.90e-06/9.90e-06|9.03e-06/9.05e-06|2.36e-06/2.36e-06|9.01e-06/9.01e-06|1.25e-06/1.25e-06
  last |9.04e-06/9.04e-06|9.90e-06/9.90e-06|9.03e-06/9.03e-06|2.35e-06/2.35e-06|9.01e-06/9.01e-06|1.23e-06/1.23e-06
  half |9.04e-06/9.04e-06|5.02e-06/5.02e-06|4.59e-06/4.59e-06|1.25e-06/1.25e-06|4.57e-06/4.57e-06|6.84e-07/6.84e-07
  first|9.04e-06/9.04e-06|6.19e-08/7.47e-08|7.91e-08/7.92e-08|7.03e-08/7.05e-08|1.14e-07/1.15e-07|1.27e-07/1.28e-07
0x1000 |
  zero |3.61e-05/3.61e-05|3.93e-05/3.93e-05|3.58e-05/3.58e-05|9.08e-06/9.08e-06|3.58e-05/3.58e-05|4.64e-06/4.64e-06
  last |3.61e-05/3.61e-05|3.93e-05/3.93e-05|3.58e-05/3.58e-05|9.07e-06/9.07e-06|3.58e-05/3.58e-05|4.61e-06/4.61e-06
  half |3.61e-05/3.61e-05|1.97e-05/1.97e-05|1.80e-05/1.80e-05|4.63e-06/4.63e-06|1.80e-05/1.80e-05|2.40e-06/2.40e-06
  first|3.61e-05/3.61e-05|1.04e-07/1.17e-07|1.21e-07/1.21e-07|1.26e-07/1.26e-07|1.58e-07/1.58e-07|1.71e-07/1.71e-07
0x10000|
  zero |1.08e-02/1.09e-02|1.03e-02/1.04e-02|9.38e-03/9.50e-03|2.41e-03/2.49e-03|9.33e-03/9.50e-03|1.67e-03/1.73e-03
  last |1.08e-02/1.09e-02|1.03e-02/1.04e-02|9.38e-03/9.49e-03|2.44e-03/2.55e-03|9.33e-03/9.47e-03|1.62e-03/1.67e-03
  half |1.08e-02/1.10e-02|5.05e-03/5.12e-03|4.61e-03/4.69e-03|1.16e-03/1.16e-03|4.59e-03/4.66e-03|6.63e-04/6.65e-04
  first|1.08e-02/1.09e-02|8.70e-07/8.80e-07|8.70e-07/8.80e-07|8.90e-07/9.00e-07|9.60e-07/9.60e-07|9.70e-07/9.80e-07
$ uname -srvmp
Linux 2.6.32-gentoo #1 SMP Sun Dec 6 16:24:50 EST 2009 x86_64 AMD Phenom(tm) 9600 Quad-Core Processor

如你看到的,

  • 對於簡短的數據,簡單就更好了
  • memcmp實際上非常擅長爬行內存(至少GCC 4.4.2適用的優化)
  • x86的字符串內在函數有點幫助
  • 長數據的最大收益來自於更大的進步 - 盡可能避免逐字節訪問。

另一種C ++解決方案:

bool all_zero( const char * buf, size_t len )
{
    return (buf == std::search_n( buf, buf+len, len, 0 ) );
}

search_n返回第一次出現的值“len”連續出現的值(此處為0)或返回“end”。 在這個特定的應用程序中,它顯然要么返回序列的開頭還是結束。

這樣做的好處是我也可以將它應用於一個int,double等數組,這些數組能夠逐字檢查。 (顯然,使all_zero成為一個模板)。

您想要的功能稱為memset

像這樣稱呼它:

memset(pMem, '\0', iMemSize);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM