Skip to content

Instantly share code, notes, and snippets.

@ssvb
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ssvb/56da061451216a37080f to your computer and use it in GitHub Desktop.
Save ssvb/56da061451216a37080f to your computer and use it in GitHub Desktop.
/*
* 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