Last active
August 29, 2015 14:22
-
-
Save ssvb/56da061451216a37080f to your computer and use it in GitHub Desktop.
A test program for http://lists.freedesktop.org/archives/pixman/2015-June/003713.html discussion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright © 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com> | |
* Copyright © 2015 Raspberry Pi Foundation | |
* | |
* Permission to use, copy, modify, distribute, and sell this software and its | |
* documentation for any purpose is hereby granted without fee, provided that | |
* the above copyright notice appear in all copies and that both that | |
* copyright notice and this permission notice appear in supporting | |
* documentation, and that the name of the copyright holders not be used in | |
* advertising or publicity pertaining to distribution of the software without | |
* specific, written prior permission. The copyright holders make no | |
* representations about the suitability of this software for any purpose. It | |
* is provided "as is" without express or implied warranty. | |
* | |
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
* SOFTWARE. | |
* | |
*/ | |
#include <inttypes.h> | |
#include <stdio.h> | |
#include <time.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <sys/time.h> | |
#define MIN_TEST_DURATION 0.1 | |
#define MAX_WORKING_SET_SIZE (512 * 1024 + 8 * 1024) | |
#define NSEC_PER_SEC 1000000000 | |
double test_duration = 0.3; | |
int working_set_size = 300; | |
double | |
gettime(void) | |
{ | |
struct timeval tv; | |
gettimeofday(&tv, NULL); | |
return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.; | |
} | |
static void | |
get_clock_gettime_process(struct timespec *ts) | |
{ | |
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ts); | |
} | |
static int64_t | |
timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b) | |
{ | |
int64_t d; | |
d = a->tv_sec - b->tv_sec; | |
d *= NSEC_PER_SEC; | |
d += a->tv_nsec - b->tv_nsec; | |
return d; | |
} | |
void | |
test(int loop_count) | |
{ | |
static char buf1[MAX_WORKING_SET_SIZE / 2]; | |
static char buf2[MAX_WORKING_SET_SIZE / 2]; | |
memset(buf1, 0, working_set_size / 2); | |
memset(buf2, 0, working_set_size / 2); | |
while (loop_count-- > 0) { | |
memcpy(buf1, buf2, working_set_size / 2); | |
memcpy(buf2, buf1, working_set_size / 2); | |
} | |
} | |
/************************************************************/ | |
void testx(int loop_count, int extra_loops, | |
double *gettime_percentage, | |
double *cputime_percentage) | |
{ | |
int i; | |
double t1, t2, t3; | |
struct timespec a, b, c; | |
int correct_gettime = 0, correct_cputime = 0; | |
int tests_count = 20; | |
test(1); | |
for (i = 0; i < tests_count; i++) { | |
t1 = gettime(); | |
get_clock_gettime_process(&a); | |
test(loop_count); | |
t2 = gettime(); | |
get_clock_gettime_process(&b); | |
test(loop_count + extra_loops); | |
t3 = gettime(); | |
get_clock_gettime_process(&c); | |
if (t3 - t2 > t2 - t1) | |
correct_gettime++; | |
if (timespec_sub_to_nsec(&c, &b) > timespec_sub_to_nsec(&b, &a)) | |
correct_cputime++; | |
} | |
*gettime_percentage = (double)correct_gettime / tests_count * 100; | |
*cputime_percentage = (double)correct_cputime / tests_count * 100; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
int loop_count = 1, extra_loops = 0; | |
double extra_loops_f; | |
double t1, t2; | |
if (argc >= 2) { | |
test_duration = (double)atoi(argv[1]) / 1000; | |
if (test_duration < MIN_TEST_DURATION) | |
test_duration = MIN_TEST_DURATION; | |
} | |
if (argc >= 3) { | |
working_set_size = atoi(argv[2]) & ~1; | |
if (working_set_size < 0) | |
working_set_size = 0; | |
if (working_set_size > MAX_WORKING_SET_SIZE) | |
working_set_size = MAX_WORKING_SET_SIZE; | |
} | |
printf("# This program runs a set of tests, which are repeatedly doing\n"); | |
printf("# memcpy over a %d bytes sized memory buffer. Each individual\n", | |
working_set_size); | |
printf("# test is calibrated to run a sufficient number of iterations\n"); | |
printf("# to make its duration close to %.0f ms.\n", | |
test_duration * 1000); | |
printf("# For each line in the report below, tests are run 20\n"); | |
printf("# times normally and 20 times slightly slower than normal\n"); | |
printf("# (the difference is shown in the first column). The timings\n"); | |
printf("# of these runs are also measured using gettimeofday(...)\n"); | |
printf("# and clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) functions\n"); | |
printf("# to see whether it is possible to reliably distinguish\n"); | |
printf("# between the slower runs and the normal runs. The percentage\n"); | |
printf("# of successful identifications is shown in the second and\n"); | |
printf("# third columns (100%% means that we could perfectly distinguish\n"); | |
printf("# between normal and slower runs in all 20 attempts).\n"); | |
printf("\n"); | |
printf("test_duration = %.0f ms (the first command line argument)\n", | |
test_duration * 1000); | |
printf("working_set_size = %d bytes (the second command line argument)\n", | |
working_set_size); | |
printf("\n"); | |
do { | |
loop_count *= 2; | |
t1 = gettime(); | |
test(loop_count); | |
t2 = gettime(); | |
} while (t2 - t1 < test_duration); | |
loop_count = (double)loop_count * test_duration / (t2 - t1); | |
printf("difference | detected by gettime | detected by cputime\n"); | |
printf("-----------+---------------------+--------------------\n"); | |
for (extra_loops_f = 0.0001 * loop_count; | |
extra_loops_f < loop_count; | |
extra_loops_f *= 1.2) { | |
if ((int)extra_loops_f == extra_loops) | |
continue; | |
extra_loops = extra_loops_f; | |
double gettime_percentage, cputime_percentage; | |
testx(loop_count, extra_loops, &gettime_percentage, &cputime_percentage); | |
printf("%9.3f%% | %18.0f%% | %18.0f%%\n", | |
(double)extra_loops / loop_count * 100, | |
gettime_percentage, cputime_percentage); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment