Home | History | Annotate | Download | only in src
      1 // Copyright 2008 Google Inc.
      2 // Authors: Craig Silverstein, Lincoln Smith
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 
     16 #ifndef OPEN_VCDIFF_TESTING_H_
     17 #define OPEN_VCDIFF_TESTING_H_
     18 
     19 #include <config.h>
     20 #include <assert.h>
     21 #include <stdint.h>  // int64_t
     22 #include <stdlib.h>  // rand
     23 #include <time.h>  // gettimeofday
     24 #include "gtest/gtest.h"
     25 
     26 #ifdef HAVE_SYS_TIME_H
     27 #include <sys/time.h>  // struct timeval
     28 #endif  // HAVE_SYS_TIME_H
     29 
     30 #ifdef HAVE_WINDOWS_H
     31 #include <windows.h>  // QueryPerformanceCounter
     32 #endif  // HAVE_WINDOWS_H
     33 
     34 // CHECK is used for assertions that verify the consistency of the test itself,
     35 // rather than correctness of the code that is being tested.
     36 //
     37 // It is better to use a preprocessor macro for CHECK
     38 // than an inline function, because assert() may report
     39 // the source file and line where the failure occurred.
     40 //
     41 // Putting parentheses around the macro arguments
     42 // (e.g. "assert((X) == (Y))") would be good practice
     43 // but would produce error messages that are inconsistent
     44 // with those expected in the unit tests.
     45 
     46 #define CHECK(CONDITION) assert(CONDITION)
     47 #define CHECK_EQ(X, Y) assert(X == Y)
     48 #define CHECK_NE(X, Y) assert(X != Y)
     49 #define CHECK_GE(X, Y) assert(X >= Y)
     50 #define CHECK_GT(X, Y) assert(X > Y)
     51 #define CHECK_LE(X, Y) assert(X <= Y)
     52 #define CHECK_LT(X, Y) assert(X < Y)
     53 
     54 namespace open_vcdiff {
     55 
     56 // Support for timing tests
     57 #if defined(HAVE_GETTIMEOFDAY)
     58 class CycleTimer {
     59  public:
     60   inline CycleTimer() {
     61     Reset();
     62   }
     63 
     64   inline void Reset() {
     65     start_time_.tv_sec = 0;
     66     start_time_.tv_usec = 0;
     67     cumulative_time_in_usec_ = 0;
     68   }
     69 
     70   inline void Start() {
     71     CHECK(!IsStarted());
     72     gettimeofday(&start_time_, NULL);
     73   }
     74 
     75   inline void Restart() {
     76     Reset();
     77     Start();
     78   }
     79 
     80   inline void Stop() {
     81     struct timeval end_time;
     82     gettimeofday(&end_time, NULL);
     83     CHECK(IsStarted());
     84     cumulative_time_in_usec_ +=
     85         (1000000 * (end_time.tv_sec - start_time_.tv_sec))
     86         + end_time.tv_usec - start_time_.tv_usec;
     87     start_time_.tv_sec = 0;
     88     start_time_.tv_usec = 0;
     89   }
     90 
     91   inline int64_t GetInUsec() {
     92     return cumulative_time_in_usec_;
     93   }
     94 
     95  private:
     96   inline bool IsStarted() {
     97     return (start_time_.tv_usec > 0) || (start_time_.tv_sec > 0);
     98   }
     99 
    100   struct timeval start_time_;
    101   int64_t cumulative_time_in_usec_;
    102 };
    103 #elif defined(HAVE_QUERYPERFORMANCECOUNTER)
    104 class CycleTimer {
    105  public:
    106   inline CycleTimer() {
    107     LARGE_INTEGER frequency;
    108     QueryPerformanceFrequency(&frequency);  // counts per second
    109     usecs_per_count_ = 1000000.0 / static_cast<double>(frequency.QuadPart);
    110     Reset();
    111   }
    112 
    113   inline void Reset() {
    114     start_time_.QuadPart = 0;
    115     cumulative_time_in_usec_ = 0;
    116   }
    117 
    118   inline void Start() {
    119     CHECK(!IsStarted());
    120     QueryPerformanceCounter(&start_time_);
    121   }
    122 
    123   inline void Restart() {
    124     Reset();
    125     Start();
    126   }
    127 
    128   inline void Stop() {
    129     LARGE_INTEGER end_time;
    130     QueryPerformanceCounter(&end_time);
    131     CHECK(IsStarted());
    132     double count_diff = static_cast<double>(
    133         end_time.QuadPart - start_time_.QuadPart);
    134     cumulative_time_in_usec_ +=
    135         static_cast<int64_t>(count_diff * usecs_per_count_);
    136     start_time_.QuadPart = 0;
    137   }
    138 
    139   inline int64_t GetInUsec() {
    140     return cumulative_time_in_usec_;
    141   }
    142 
    143  private:
    144   inline bool IsStarted() {
    145     return start_time_.QuadPart > 0;
    146   }
    147 
    148   LARGE_INTEGER start_time_;
    149   int64_t cumulative_time_in_usec_;
    150   double usecs_per_count_;
    151 };
    152 #else
    153 #error CycleTimer needs an implementation that does not use gettimeofday or QueryPerformanceCounter
    154 #endif  // HAVE_GETTIMEOFDAY
    155 
    156 // This function returns a pseudo-random value of type IntType between 0 and
    157 // limit.  It uses the standard rand() function to produce the value, and makes
    158 // as many calls to rand() as needed to ensure that the values returned can fall
    159 // within the full range specified.  It is slow, so don't include calls to this
    160 // function when calculating the execution time of tests.
    161 //
    162 template<typename IntType>
    163 inline IntType PortableRandomInRange(IntType limit) {
    164   uint64_t value = rand();
    165   double rand_limit = RAND_MAX;  // The maximum possible value
    166   while (rand_limit < limit) {
    167     // value is multiplied by (RAND_MAX + 1) each iteration. This factor will be
    168     // canceled out when we divide by rand_limit to get scaled_value, below.
    169     value = (value * (static_cast<uint64_t>(RAND_MAX) + 1)) + rand();
    170     rand_limit = (rand_limit * (RAND_MAX + 1.0)) + RAND_MAX;
    171   }
    172   // Translate the random 64-bit integer into a floating-point value between
    173   // 0.0 (inclusive) and 1.0 (inclusive).
    174   const double scaled_value = value / rand_limit;
    175   return static_cast<IntType>(limit * scaled_value);
    176 }
    177 
    178 }  // namespace open_vcdiff
    179 
    180 #endif  // OPEN_VCDIFF_TESTING_H_
    181