lkml.org 
[lkml]   [2002]   [Oct]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: Csum and csum copyroutines benchmark
    From
    Date
    >>>>> "Denis" == Denis Vlasenko <vda@port.imtp.ilyichevsk.odessa.ua> writes:

    Denis> [please drop libc from CC:]
    Denis> On 25 October 2002 05:48, Momchil Velikov wrote:
    >>> Short conclusion:
    >>> 1. It is possible to speed up csum routines for AMD processors
    >>> by 30%.
    >>> 2. It is possible to speed up csum_copy routines for both AMD
    >>> andd Intel three times or more.

    >> Additional data point:
    >>
    >> Short summary:
    >> 1. Checksum - kernelpii_csum is ~19% faster
    >> 2. Copy - lernelpii_csum is ~6% faster
    >>
    >> Dual Pentium III, 1266Mhz, 512K cache, 2G SDRAM (133Mhz, ECC)
    >>
    >> The only changes I made were to decrease the buffer size to 1K (as I
    >> think this is more representative to a network packet size, correct
    >> me if I'm wrong) and increase the runs to 1024. Max values are
    >> worthless indeed.

    Denis> Well, that makes it run entirely in L0 cache. This is unrealistic
    Denis> for actual use. movntq is x3 faster when you hit RAM instead of L0.

    Oops ...

    Denis> You need to be more clever than that - generate pseudo-random
    Denis> offsets in large buffer and run on ~1K pieces of that buffer.

    Here it is:

    Csum benchmark program
    buffer size: 1 K
    Each test tried 1024 times, max and min CPU cycles are reported.
    Please disregard max values. They are due to system interference only.
    csum tests:
    kernel_csum - took 8678 max, 808 min cycles per kb. sum=0x400270e8
    kernel_csum - took 941 max, 808 min cycles per kb. sum=0x400270e8
    kernel_csum - took 11604 max, 808 min cycles per kb. sum=0x400270e8
    kernelpii_csum - took 28839 max, 664 min cycles per kb. sum=0x400270e8
    kernelpiipf_csum - took 9163 max, 665 min cycles per kb. sum=0x400270e8
    pfm_csum - took 2788 max, 1470 min cycles per kb. sum=0x400270e8
    pfm2_csum - took 1179 max, 915 min cycles per kb. sum=0x400270e8
    copy tests:
    kernel_copy - took 688 max, 263 min cycles per kb. sum=0x400270e8
    kernel_copy - took 456 max, 263 min cycles per kb. sum=0x400270e8
    kernel_copy - took 11241 max, 263 min cycles per kb. sum=0x400270e8
    kernelpii_copy - took 7635 max, 246 min cycles per kb. sum=0x400270e8
    ntqpf_copy - took 5349 max, 536 min cycles per kb. sum=0x400270e8
    ntqpfm_copy - took 769 max, 425 min cycles per kb. sum=0x400270e8
    ntq_copy - took 672 max, 469 min cycles per kb. sum=0x400270e8
    ntqpf2_copy - took 8000 max, 579 min cycles per kb. sum=0x400270e8
    Done

    Ran on a 512K (my cache size) buffer, choosing each time a 1K
    piece. (making the buffer larger (2M, 4M) does not make any
    difference).

    And the modified 0main.c is attached.

    ~velco
    #include <stdio.h>
    #include <stdlib.h>

    #define NAME(a) \
    unsigned int a##csum(const unsigned char * buff, int len, \
    unsigned int sum); \
    unsigned int a##copy(const char *src, char *dst, \
    int len, int sum, int *src_err_ptr, int *dst_err_ptr)

    /* This makes adding/removing test functions easier */
    /* asm ones... */
    NAME(kernel_);
    NAME(kernelpii_);
    NAME(kernelpiipf_);
    /* and C */
    #include "pfm_csum.c"
    #include "pfm2_csum.c"
    #include "ntq_copy.c"
    #include "ntqpf_copy.c"
    #include "ntqpf2_copy.c"
    #include "ntqpfm_copy.c"

    const int TRY_TIMES = 1024;
    const int NBUFS = 512;
    const int BUFSIZE = 1024;
    const int POISON = 0; // want to check correctness?

    typedef unsigned int csum_func(const unsigned char * buff, int len,
    unsigned int sum);
    typedef unsigned int copy_func(const char *src, char *dst,
    int len, int sum, int *src_err_ptr, int *dst_err_ptr);

    static inline long long rdtsc()
    {
    unsigned int low,high;
    __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
    return low + (((long long)high)<<32);
    }

    int die(const char *msg) {
    puts(msg);
    abort();
    return 1;
    }

    unsigned test_one_csum(csum_func *func, char *name, char *buffer)
    {
    int i;
    unsigned long long before,after,min,max;
    unsigned sum;

    // pick fastest run
    min = ~0ULL;
    max = 0;
    for (i=0;i<TRY_TIMES;i++) {
    before = rdtsc();
    unsigned sum2 = func(buffer + (rand () % NBUFS) * BUFSIZE,
    BUFSIZE, 0);
    after = rdtsc();
    if (before>after) die("timer overflow");
    else {
    after-=before;
    if(min>after) min=after;
    if(max<after) max=after;
    }
    }
    printf("%32s - took %5lli max,%5lli min cycles per kb. sum=0x%08x\n",
    name,
    max / (BUFSIZE/1024),
    min / (BUFSIZE/1024),
    sum
    );
    }

    unsigned test_one_copy(copy_func *func, char *name, char *buffer)
    {
    int i;
    unsigned long long before,after,min,max;
    unsigned sum;
    int err;

    // pick fastest run
    min = ~0ULL;
    max = 0;
    for (i=0; i<TRY_TIMES; i++) {
    if(POISON) memset(buffer, 0x55,BUFSIZE/2);
    if(POISON) memset(buffer+BUFSIZE/2,0xaa,BUFSIZE/2);
    buffer[0] = 0x77;
    buffer[BUFSIZE/2-1] = 0x44;
    before = rdtsc();
    char *buf = buffer + rand () % (NBUFS - 1);
    unsigned sum2 = func(buf,buf+BUFSIZE/2,BUFSIZE/2,0,&err,&err);
    after = rdtsc();
    if(POISON) if(memcmp(buffer,buffer+BUFSIZE/2,BUFSIZE/2)!=0) die("BAD copy!");
    if (before>after) die("timer overflow");
    else {
    after-=before;
    if(min>after) min=after;
    if(max<after) max=after;
    }
    }
    printf("%32s - took %5lli max,%5lli min cycles per kb. sum=0x%08x\n",
    name,
    max / (BUFSIZE/1024) / 2,
    min / (BUFSIZE/1024) / 2,
    sum
    );
    return sum;
    }


    void test_csum(char *buffer)
    {
    unsigned sum;
    puts("csum tests:");

    #define TEST_CSUM(a) test_one_csum(a,#a,buffer)
    TEST_CSUM(kernel_csum );
    TEST_CSUM(kernel_csum );
    TEST_CSUM(kernel_csum );
    TEST_CSUM(kernelpii_csum );
    TEST_CSUM(kernelpiipf_csum);
    TEST_CSUM(pfm_csum );
    TEST_CSUM(pfm2_csum );
    #undef TEST_CSUM
    }

    void test_copy(char *buffer)
    {
    unsigned sum;
    puts("copy tests:");

    #define TEST_COPY(a) test_one_copy(a,#a,buffer)
    sum = TEST_COPY(kernel_copy );
    sum == TEST_COPY(kernel_copy ) || die("Bad sum");
    sum == TEST_COPY(kernel_copy ) || die("Bad sum");
    sum == TEST_COPY(kernelpii_copy ) || die("Bad sum");
    sum == TEST_COPY(ntqpf_copy ) || die("Bad sum");
    sum == TEST_COPY(ntqpfm_copy ) || die("Bad sum");
    sum == TEST_COPY(ntq_copy ) || die("Bad sum");
    sum == TEST_COPY(ntqpf2_copy ) || die("Bad sum");
    #undef TEST_COPY
    }

    int main()
    {
    char *buffer_raw,*buffer;
    printf("Csum benchmark program\n"
    "buffer size: %i K\n"
    "Each test tried %i times, max and min CPU cycles are reported.\n"
    "Please disregard max values. They are due to system interference only.\n",
    BUFSIZE/1024,
    TRY_TIMES
    );

    buffer_raw = malloc(NBUFS * BUFSIZE+16);
    if(!buffer_raw) die("Malloc failed");

    buffer = (char*) ((((int)buffer_raw)+15) & (~0xF));

    test_csum(buffer);
    test_copy(buffer);

    puts("Done");
    free(buffer_raw);
    return 0;
    }
    \
     
     \ /
      Last update: 2005-03-22 13:30    [W:0.036 / U:0.044 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site