oop_v1p6.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 653 行 · 第 1/2 页

C
653
字号
    double sum = 0;
    for( int k=0; k<L*L; k++ )
        sum += E[k];
    checksum = sum;
    flops = 2.0*L*L*L*iterations;
}
#endif /* HAVE_MATRIX */

#if HAVE_ITERATOR
//=============================================================================
//
// Iterator benchmark 
//
// Iterators are a common abstraction in object-oriented programming, which
// unfortunately may incur a high cost if compiled inefficiently.
// The iterator benchmark below computes a dot-product using C-style code
// and OOP-style code.  All methods of the iterator are inline, and in 
// principle correspond exactly to the C-style code.
//
// Note that the OOP-style code uses two iterators, but the C-style
// code uses a single index.  Good common-subexpression elimination should,
// in principle, reduce the two iterators to a single index variable, or
// conversely, good strength-reduction should convert the single index into 
// two iterators!  
//
double A[N];
double B[N];
double IteratorResult;

class IteratorBenchmark: public Benchmark {
private:
    const char * name() const {return "Iterator";}
    void init() const;
    void c_style() const; 
    void oop_style() const;
    void check( int iterations, double& flops, double& checksum ) const;
} TheIteratorBenchmark;

void IteratorBenchmark::c_style() const                 // Compute dot-product with C-style code
{
    double sum = 0;
    for( int i=0; i<N; i++ )
        sum += A[i]*B[i];
    IteratorResult = sum;
}

class Iterator {                // Iterator for iterating over array of double
private:
    int index;                  // Index of current element
    const int limit;            // 1 + index of last element
    double * const array;       // Pointer to array
public:
    double look() {return array[index];}        // Get current element
    void next() {index++;}                      // Go to next element
    int done() {return index>=limit;}           // True iff no more elements
    Iterator( double * array1, int limit1 ) : 
        array(array1), 
        limit(limit1), 
        index(0) 
    {}
};

void IteratorBenchmark::oop_style() const               // Compute dot-product with OOP-style code
{
    double sum = 0;
    for( Iterator ai(A,N), bi(B,N); !ai.done(); ai.next(), bi.next() )
        sum += ai.look()*bi.look();
    IteratorResult = sum;
}

void IteratorBenchmark::init() const    
{
    for( int i=0; i<N; i++ ) {
        A[i] = i+1;
        B[i] = 1.0/(i+1);
    }
}

void IteratorBenchmark::check( int iterations, double& flops, double& checksum ) const {
    flops = 2*N*iterations;
    checksum = IteratorResult;
}
#endif /* HAVE_ITERATOR */

#if HAVE_COMPLEX
//=============================================================================
//
// Complex benchmark
//
// Complex numbers are a common abstraction in scientific programming.
// This benchmark measures how fast they are in C++ relative to the same
// calculation done by explicitly writing out the real and imaginary parts.
// The calculation is a complex-valued ``SAXPY'' operation.
//
// The complex arithmetic is all inlined, so in principle the code should
// run as fast as the version using explicit real and imaginary parts.
//
class ComplexBenchmark: public Benchmark {
private:
    const char * name() const {return "Complex";}
    void init() const;
    void c_style() const; 
    void oop_style() const;
    void check( int iterations, double& flops, double& checksum ) const;
} TheComplexBenchmark;

class Complex {
public:
    double re, im;
    Complex( double r, double i ) : re(r), im(i) {}
    Complex() {}
};

inline Complex operator+( Complex a, Complex b )        // Complex add
{
    return Complex( a.re+b.re, a.im+b.im );
}

inline Complex operator*( Complex a, Complex b )        // Complex multiply
{
    return Complex( a.re*b.re-a.im*b.im, a.re*b.im+a.im*b.re );
}

Complex X[N], Y[N];                             // Arrays used by benchmark

void ComplexBenchmark::c_style() const          // C-style complex-valued SAXPY operation
{
    double factor_re = 0.5;
    double factor_im = 0.86602540378443864676;
    for( int k=0; k<N; k++ ) {
        Y[k].re = Y[k].re + factor_re*X[k].re - factor_im*X[k].im;
        Y[k].im = Y[k].im + factor_re*X[k].im + factor_im*X[k].re;
    }
}

void ComplexBenchmark::oop_style() const        // OOP-style complex-valued SAXPY operation 
{
    Complex factor( 0.5, 0.86602540378443864676 );
    for( int k=0; k<N; k++ )
        Y[k] = Y[k] + factor*X[k];
}

void ComplexBenchmark::init() const     
{
    for( int k=0; k<N; k++ ) {
        X[k] = Complex( k+1, 1.0/(k+1) );
        Y[k] = Complex( 0, 0 );
    }
}

void ComplexBenchmark::check( int iterations, double& flops, double& checksum ) const {
    double sum = 0;
    for( int k=0; k<N; k++ )
        sum += Y[k].re + Y[k].im;
    checksum = sum;
    flops = 8*N*iterations;
}
#endif /* HAVE_COMPLEX */

//=============================================================================
// End of benchmark computations.  
//=============================================================================

// All the code below is for running and timing the benchmarks.                                              
#if defined(sun4) && !defined(CLOCKS_PER_SEC)
// Sun/4 include-files seem to be missing CLOCKS_PER_SEC.
#define CLOCKS_PER_SEC 1000000  
#endif

//
// TimeOne
//
// Time a single benchmark computation.
//
// Inputs
//      function = pointer to function to be run and timed.
//      iterations = number of times to call function.
//
// Outputs
//      sec = Total number of seconds for calls of function.
//      Mflop = Megaflop rate of function.
//      checksum = checksum computed by function.
//     
void Benchmark::time_one( void (Benchmark::*function)() const, int iterations, double& sec, double& Mflop, double& checksum ) const
{
    // Initialize and run code once to load caches
    init();
    (this->*function)();

    // Initialize and run code.
    init();
    clock_t t0 = clock();
    for( int k=0; k<iterations; k++ ) 
        (this->*function)();
    clock_t t1 = clock();

    // Update checksum and compute number of floating-point operations.
    double flops;
    check( iterations, flops, checksum );

    sec = (t1-t0) / (double)CLOCKS_PER_SEC;
    Mflop = flops/sec*1e-6;

}

//
// The variable ``C_Seconds'' is the time in seconds in which to run the 
// C-style benchmarks.
//
double C_Seconds = 1;   

//
// The variable ``Tolerance'' is the maximum allowed relative difference 
// between the C and OOP checksums.  Machines with multiply-add 
// instructions may produce different answers when they use those 
// instructions rather than separate instructions.
//
// There is nothing magic about the 32, it's just the result of tweaking.
//
const double Tolerance = 128*DBL_EPSILON;

Benchmark * Benchmark::find( const char * name ) {
    for( int i=0; i<count; i++ )
        if( strcmp( name, list[i]->name() )== 0 )
            return list[i];
    return NULL;        
}

//
// Benchmark::time_both
//
// Runs the C and Oop versions of a benchmark computation, and print the 
// results.
//
// Inputs
//      name = name of the benchmark
//      c_style = benchmark written in C-style code
//      oop_style = benchmark written in OOP-style code
//      check = routine to compute checksum on answer
//
void Benchmark::time_both( int iterations, double limit ) const {
    // Run the C-style code. 
    double c_sec, c_Mflop, c_checksum;
    time_one( &Benchmark::c_style, iterations, c_sec, c_Mflop, c_checksum );
   
    // Run the OOP-style code. 
    double oop_sec, oop_Mflop, oop_checksum;
    time_one( &Benchmark::oop_style, iterations, oop_sec, oop_Mflop, oop_checksum );

    // Compute execution-time ratio of OOP to C.  This is also the 
    // reciprocal of the Megaflop ratios.                                
    double ratio = oop_sec/c_sec;
 
    // Compute the absolute and relative differences between the checksums
    // for the two codes.
    double diff = c_checksum - oop_checksum;
    double min = c_checksum < oop_checksum ? c_checksum : oop_checksum;
    double rel = diff/min;

    // If the relative difference exceeds the tolerance, print an error-message,
    // otherwise print the statistics.
    if( rel > Tolerance || rel < -Tolerance ) {
        printf( "%-10s: warning: relative checksum error of %g between C (%g) and oop (%g)\n",
                name(), rel, c_checksum, oop_checksum );
    } 
    if( ratio > limit ) {
        printf( "%-10s %10d  %5.1f %5.1f  %5.1f %5.1f  %5.1f\n",
                name(), iterations, c_sec, oop_sec, c_Mflop, oop_Mflop, ratio );
    }
}

const char * Version = "Version 1.6"; // The OOPACK version number 

void Usage( int /*argc*/, char * argv[] ) {
    printf( "Usage:\t%s test1=iterations1 test2=iterations2 ...\n", argv[0] ); 
    printf( "E.g.:\ta.out  Max=5000 Matrix=50 Complex=2000  Iterator=5000\n" );
    exit(1);
}

int main( int argc, char * argv[] ) 
{
    // The available benchmarks are automatically put into the list of available benchmarks
    // by the constructor for Benchmark.

    // Check if user does not know command-line format.
    if( argc==1 ) {
        Usage( argc, argv );
    }
    int i;
#if 0
    for( i=1; i<argc; i++ ) {
        if( !isalpha(argv[i][0]) )
            Usage( argc, argv );
    }
#endif

    // Print header.
    printf("%-10s %10s  %11s  %11s  %5s\n", "", "", "Seconds  ", "Mflops  ", "" );
    printf("%-10s %10s  %5s %5s  %5s %5s  %5s\n",
           "Test", "Iterations", " C ", "OOP", " C ", "OOP", "Ratio" );
    printf("%-10s %10s  %11s  %11s  %5s\n", "----", "----------", "-----------", "-----------", "-----" );

    for( i=1; i<argc; i++ ) {
        const char * test_name = strtok( argv[i], "= " );
        const char * rhs =  strtok( NULL, "" );
        const char * limit =  strtok( argv[++i], "" );
        if( rhs==NULL ) {
            printf("missing iteration count for test '%s'\n", test_name );
        } else {
            int test_count = (int)strtol( rhs, 0, 0 );
            double test_limit = (double)strtod( limit, 0 );
            Benchmark * b = Benchmark::find( test_name );
            if( b==NULL ) {
                printf("skipping non-existent test = '%s'\n", test_name );
            } else {
                b->time_both( test_count, test_limit );
            }
        }
    }

    /* Print blank line. */
    printf("\n");

    return 0;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?