/****************************************************
    AddUnrollCPE.hpp

    This program adds an array of numbers and compares the
    performance with manual loop unrolling with an unrolled loop.

****************************************************/


#ifndef ADDUNROLLCPE_HEADER
#define ADDUNROLLCPE_HEADER

#include <iostream>
#include "CPE.hpp"

//everything stuck in header for convenience, NOT considered 'good practice'!
const int NNUMS = 1024;
const int NRUNS = 10;

class AddUnrollCPE : CCPE{
    //    function to run the tests on MUST ALWAYS RETURN A VOID *
    //    AND MUST ALWAYS TAKE A VOID * AS AN ARG
    static void * foo1(void *da_args) {
        int i, sum=0, *nums = (int *)da_args;

    //unroll loop by 6
        for(i=0; i<NNUMS-5; i+=6)
            sum += nums[i] + nums[i+1] + nums[i+2] + nums[i+3] + nums[i+4] + nums[i+5];

    //cleanup slackers
        while(i<NNUMS) sum += nums[i++];

        return (void *)sum;
    };

    //and now with no unrolling
    static void * foo2(void *da_args) {
        int i, sum=0, *nums = (int *)da_args;

        for(i=0; i<NNUMS; i++) sum += nums[i];

        return (void *)sum;
    };

public:
    AddUnrollCPE(){
        int i, sum, nums[NNUMS];

    //fill up array with some data
        for(i=0; i<NNUMS; i++) nums[i] = i;

    //do the testing
        sum = (int)test_it(foo2, nums, NRUNS);
        std::cout << "Addition sum without unrolling: " << sum << std::endl;
        std::cout << "Minimum overhead is: " << GetMinOverhead() << std::endl;
        std::cout << "CPE for function without unrolling: " << GetMinExecution();

        sum = (int)test_it(foo1, nums, NRUNS);
        std::cout << "\n\nAddition sum unrolled (by 6): " << sum << std::endl;
        std::cout << "Minimum overhead unrolled is: " << GetMinOverhead() << std::endl;
        std::cout << "CPE for unrolled function: " << GetMinExecution();
    };

};

#endif //ADDUNROLLCPE_HEADER
