|
|
|
@ -86,6 +86,18 @@ struct other_thread { |
|
|
|
struct stats stats; // temp storage, owned by output thread |
|
|
|
}; |
|
|
|
|
|
|
|
struct freq_stats { |
|
|
|
long min; |
|
|
|
long max; |
|
|
|
long sum; |
|
|
|
long samples; |
|
|
|
}; |
|
|
|
|
|
|
|
struct thread_freq_stats { |
|
|
|
mutex_t lock; |
|
|
|
struct freq_stats stats; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
typedef void render_fn(const struct stats *stats, int line, int x, int breadth, int width, |
|
|
|
int color, |
|
|
|
@ -141,6 +153,11 @@ static int init_threads = 0; |
|
|
|
static bool bidirectional = false; |
|
|
|
static int max_cpu = 0; |
|
|
|
static bool system_cpu; |
|
|
|
static int break_in = 200; |
|
|
|
static int measure_time = 500; |
|
|
|
static int repeats = 1; |
|
|
|
static bool cpu_freq; |
|
|
|
static int freq_granularity = 50; |
|
|
|
|
|
|
|
|
|
|
|
#define BLOCKED_COLOR 1 |
|
|
|
@ -1512,6 +1529,36 @@ static void options(int *argc, char ***argv) { |
|
|
|
.arg_data = &system_cpu, |
|
|
|
.description = "Consider system CPU usage for automated tests", |
|
|
|
}, |
|
|
|
{ |
|
|
|
.long_name = "break-in", |
|
|
|
.arg = G_OPTION_ARG_INT, |
|
|
|
.arg_data = &break_in, |
|
|
|
.description = "Break-in time in ms before measuring for automated tests", |
|
|
|
}, |
|
|
|
{ |
|
|
|
.long_name = "measure-time", |
|
|
|
.arg = G_OPTION_ARG_INT, |
|
|
|
.arg_data = &measure_time, |
|
|
|
.description = "Duration of automated tests in ms", |
|
|
|
}, |
|
|
|
{ |
|
|
|
.long_name = "repeats", |
|
|
|
.arg = G_OPTION_ARG_INT, |
|
|
|
.arg_data = &repeats, |
|
|
|
.description = "Number of times to repeat automated test", |
|
|
|
}, |
|
|
|
{ |
|
|
|
.long_name = "cpu-freq", |
|
|
|
.arg = G_OPTION_ARG_NONE, |
|
|
|
.arg_data = &cpu_freq, |
|
|
|
.description = "Monitor CPU frequencies during automated test", |
|
|
|
}, |
|
|
|
{ |
|
|
|
.long_name = "freq-granularity", |
|
|
|
.arg = G_OPTION_ARG_INT, |
|
|
|
.arg_data = &freq_granularity, |
|
|
|
.description = "Granularity in ms for measuring CPU frequencies", |
|
|
|
}, |
|
|
|
{ NULL, } |
|
|
|
}; |
|
|
|
|
|
|
|
@ -1525,6 +1572,8 @@ static void options(int *argc, char ***argv) { |
|
|
|
|
|
|
|
if (max_cpu > 100 || max_cpu < 0) |
|
|
|
die("Invalid `max-cpu` number given"); |
|
|
|
if (freq_granularity <= 0) |
|
|
|
die("Invalid `freq-granularity` number given"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1582,6 +1631,63 @@ static void delay_measure_workers(uint milliseconds, struct stats *totals) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void *cpu_freq_monitor(void *p) { |
|
|
|
struct thread_freq_stats *freq_stats = p; |
|
|
|
|
|
|
|
while (true) { |
|
|
|
struct freq_stats iter_stats = {0}; |
|
|
|
|
|
|
|
{ |
|
|
|
AUTO_CLEANUP(DIR *dp, closedir_p) = opendir("/sys/devices/system/cpu/cpufreq"); |
|
|
|
if (!dp) |
|
|
|
break; // bail out |
|
|
|
|
|
|
|
|
|
|
|
struct dirent *ent; |
|
|
|
while ((ent = readdir(dp))) { |
|
|
|
if (strncmp(ent->d_name, "policy", 6) != 0) |
|
|
|
continue; // skip |
|
|
|
|
|
|
|
AUTO_CLEANUP(char *fn, free_gbuf) |
|
|
|
= g_strdup_printf("/sys/devices/system/cpu/cpufreq/%s/scaling_cur_freq", |
|
|
|
ent->d_name); |
|
|
|
AUTO_CLEANUP(FILE *fp, fclose_p) = fopen(fn, "r"); |
|
|
|
if (!fp) |
|
|
|
continue; // ignore |
|
|
|
|
|
|
|
long long freq; |
|
|
|
int rets = fscanf(fp, "%lld", &freq); |
|
|
|
if (rets != 1) |
|
|
|
continue; // ignore |
|
|
|
|
|
|
|
iter_stats.max = iter_stats.max ? MAX(iter_stats.max, freq) : freq; |
|
|
|
iter_stats.min = iter_stats.min ? MIN(iter_stats.min, freq) : freq; |
|
|
|
iter_stats.sum += freq; |
|
|
|
iter_stats.samples++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// done collecting, add to shared struct |
|
|
|
|
|
|
|
{ |
|
|
|
LOCK(&freq_stats->lock); |
|
|
|
freq_stats->stats.max = freq_stats->stats.max |
|
|
|
? MAX(freq_stats->stats.max, iter_stats.max) : iter_stats.max; |
|
|
|
freq_stats->stats.min = freq_stats->stats.min |
|
|
|
? MIN(freq_stats->stats.min, iter_stats.min) : iter_stats.min; |
|
|
|
freq_stats->stats.sum += iter_stats.sum; |
|
|
|
freq_stats->stats.samples += iter_stats.samples; |
|
|
|
} |
|
|
|
|
|
|
|
thread_cancel_enable(); |
|
|
|
usleep(freq_granularity * 1000); |
|
|
|
thread_cancel_disable(); |
|
|
|
} |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void max_cpu_test(void) { |
|
|
|
int max_cpu_scaled = max_cpu * 100000; |
|
|
|
|
|
|
|
@ -1590,17 +1696,24 @@ static void max_cpu_test(void) { |
|
|
|
uint test_num = 1; |
|
|
|
set_streams(test_num); |
|
|
|
|
|
|
|
while (true) { |
|
|
|
pthread_t cpu_thread = 0; |
|
|
|
struct thread_freq_stats freq_stats = {.lock = MUTEX_STATIC_INIT}; |
|
|
|
if (cpu_freq) |
|
|
|
cpu_thread = thread_new("CPU freq", cpu_freq_monitor, &freq_stats); |
|
|
|
|
|
|
|
int count = repeats; |
|
|
|
|
|
|
|
while (count > 0) { |
|
|
|
// initial break-in |
|
|
|
delay_measure_workers(200, NULL); |
|
|
|
delay_measure_workers(break_in, NULL); |
|
|
|
cpu_collect(NULL, NULL); |
|
|
|
|
|
|
|
// measure |
|
|
|
struct stats totals = {0}; |
|
|
|
if (!system_cpu) |
|
|
|
delay_measure_workers(500, &totals); |
|
|
|
delay_measure_workers(measure_time, &totals); |
|
|
|
else { |
|
|
|
delay_measure_workers(500, NULL); |
|
|
|
delay_measure_workers(measure_time, NULL); |
|
|
|
cpu_collect(NULL, &totals); |
|
|
|
} |
|
|
|
|
|
|
|
@ -1632,7 +1745,28 @@ static void max_cpu_test(void) { |
|
|
|
? "bidirectional calls" |
|
|
|
: "unidirectional streams", |
|
|
|
workers.length); |
|
|
|
break; |
|
|
|
|
|
|
|
if (cpu_freq) { |
|
|
|
// retrieve stats and reset |
|
|
|
struct freq_stats stats; |
|
|
|
{ |
|
|
|
LOCK(&freq_stats.lock); |
|
|
|
stats = freq_stats.stats; |
|
|
|
freq_stats.stats = (__typeof__(freq_stats.stats)) {0}; |
|
|
|
} |
|
|
|
if (!stats.samples) |
|
|
|
printf(" (no CPU frequency stats collected)\n"); |
|
|
|
else { |
|
|
|
printf(" CPU frequencies: " |
|
|
|
"%.2f <> %.2f GHz, avg %.2f GHz\n", |
|
|
|
(float) stats.min / 1000000., |
|
|
|
(float) stats.max / 1000000., |
|
|
|
(float) stats.sum / (float) stats.samples |
|
|
|
/ 1000000.); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
count--; |
|
|
|
} |
|
|
|
|
|
|
|
// scale to 50..100 |
|
|
|
@ -1643,6 +1777,11 @@ static void max_cpu_test(void) { |
|
|
|
|
|
|
|
set_streams(test_num); |
|
|
|
} |
|
|
|
|
|
|
|
if (cpu_thread) { |
|
|
|
pthread_cancel(cpu_thread); |
|
|
|
pthread_join(cpu_thread, NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|