/********************************************* CPE.cpp Cost Per Execution A class designed for extending. Used for testing the actuall number of instructions executed for a given sample of code. This class makes use of self-modifying code to access x86 instructions in a compiler independant manner (i.e., does not have any embedded assembler). This technique is based on parts of the book "Computer Systems: A Programmer's Perspective" by Randal E. Bryant and David R. O'Hallaron, information on which can be found at http://csapp.cs.cmu.edu/. Sean Larsson originally adapted the examples in the book and Keith Oxenrider took Sean's code, rewrote it to use self-modifying code and adapted it into a class. This program should run fine on any x86 instruction based computer (Intel, AMD, Cyrix), but has only been tested on Intel. If you get results for other machines (good or bad) we would very much appreciate knowing about them, particularlly if you had to modify the program to get it to run properly. This code is placed in the public domain for use by anyone for anything. We ask that if you make use of this code that you acknowledge us as authors. Sean wrote his version 12/25/2003, Keith adapted it on 06/22/2004. The most recent version of this program can be found via: sol-biotech.com/code/ Keith can be contacted at koxenrider[at]sol[dash]biotech[dot]com Sean can be contacted at infamous41md[at]sol[dash]biotech[dot]com *********************************************/ #ifndef CPE_HEADER #define CPE_HEADER #include class CCPE { std::vector < unsigned char > m_vctInstructions; unsigned long m_ulMinOverhead, m_ulMinExecution; //typedefs here because I (Keith) never got the right syntax //to use it directly typedef void (* FunctionUIntPtrInt)(unsigned int *, int); FunctionUIntPtrInt GetOverhead; typedef void (* FunctionUIntPtr)(unsigned int *); FunctionUIntPtr ReadStamp; void writeGetOverhead(); void writeReadStamp(); public: CCPE(); //Should be run at least 3 times to get code/data into L1 cache //if you want to strictly test the performance of the function. //Something else to keep in mind... if your test function takes more than 1 //timeslice you will not get accurate results as the CPE will reflect the //time spent in kernel as well as anything else that executed while your process //was in the context switch. Also, if your test function makes any OS API calls //(reads from file, allocates memory, talks on a pipe/socket, etc.) then the CPE //will also be (potentially) grossly distorted. void *test_it(void * (*your_func)(void *), void *your_arg, unsigned int NRUNS); //NOTE: If your test takes longer than ULONG_MAX cycles you will get wrapping //of the return value! inline unsigned long GetMinOverhead(){return m_ulMinOverhead;}; inline unsigned long GetMinExecution(){return m_ulMinExecution;}; }; #endif //CPE_HEADER