|
From: Nathan F. <nf...@li...> - 2015-06-23 13:34:32
|
The pthread handling for checking cpu frequency in the ppc64_cpu
command does not properly handle 'soak' threads exiting from a failed
sched_setaffinity call.
We need to update the number of threads handled to be dynamically set
instead of defining MAX_NR_CPUS, which is out of date. We also need to
check for 'soak' threads that have exited before reading the perf counters
Signed-off-by: Nathan Fontenot <nf...@li...>
---
src/ppc64_cpu.c | 115 +++++++++++++++++++++++++++++++++++--------------------
1 file changed, 73 insertions(+), 42 deletions(-)
diff --git a/src/ppc64_cpu.c b/src/ppc64_cpu.c
index 376c20f..6ecfe7f 100644
--- a/src/ppc64_cpu.c
+++ b/src/ppc64_cpu.c
@@ -50,8 +50,12 @@
#define CPU_OFFLINE -1
#ifdef HAVE_LINUX_PERF_EVENT_H
-static unsigned long long cpu_freq[MAX_NR_CPUS];
-static int counters[MAX_NR_CPUS];
+struct cpu_freq {
+ int offline;
+ int counter;
+ pthread_t tid;
+ unsigned long long freq;
+};
#ifndef __NR_perf_event_open
#define __NR_perf_event_open 319
@@ -762,7 +766,7 @@ static int do_run_mode(char *run_mode)
#ifdef HAVE_LINUX_PERF_EVENT_H
-static int setup_counters(void)
+static int setup_counters(struct cpu_freq *cpu_freqs)
{
int i;
struct perf_event_attr attr;
@@ -774,13 +778,15 @@ static int setup_counters(void)
attr.size = sizeof(attr);
for (i = 0; i < threads_in_system; i++) {
- if (!cpu_online(i))
+ if (!cpu_online(i)) {
+ cpu_freqs[i].offline = 1;
continue;
+ }
- counters[i] = syscall(__NR_perf_event_open, &attr, -1,
- i, -1, 0);
+ cpu_freqs[i].counter = syscall(__NR_perf_event_open, &attr,
+ -1, i, -1, 0);
- if (counters[i] < 0) {
+ if (cpu_freqs[i].counter < 0) {
if (errno == ENOSYS)
fprintf(stderr, "frequency determination "
"not supported with this kernel.\n");
@@ -794,45 +800,68 @@ static int setup_counters(void)
return 0;
}
-static void start_counters(void)
+static void start_counters(struct cpu_freq *cpu_freqs)
{
int i;
for (i = 0; i < threads_in_system; i++) {
- if (cpu_freq[i] == CPU_OFFLINE)
+ if (cpu_freqs[i].offline)
continue;
- ioctl(counters[i], PERF_EVENT_IOC_ENABLE);
+ ioctl(cpu_freqs[i].counter, PERF_EVENT_IOC_ENABLE);
}
}
-static void stop_counters(void)
+static void stop_counters(struct cpu_freq *cpu_freqs)
{
int i;
for (i = 0; i < threads_in_system; i++) {
- if (cpu_freq[i] == CPU_OFFLINE)
+ if (cpu_freqs[i].offline)
continue;
- ioctl(counters[i], PERF_EVENT_IOC_DISABLE);
+ ioctl(cpu_freqs[i].counter, PERF_EVENT_IOC_DISABLE);
}
}
-static void read_counters(void)
+static void read_counters(struct cpu_freq *cpu_freqs)
{
int i;
for (i = 0; i < threads_in_system; i++) {
size_t res;
- if (cpu_freq[i] == CPU_OFFLINE)
+ if (cpu_freqs[i].offline)
continue;
- res = read(counters[i], &cpu_freq[i],
+ res = read(cpu_freqs[i].counter, &cpu_freqs[i].freq,
sizeof(unsigned long long));
assert(res == sizeof(unsigned long long));
- close(counters[i]);
+ close(cpu_freqs[i].counter);
+ }
+}
+
+static void check_threads(struct cpu_freq *cpu_freqs)
+{
+ int i;
+
+ for (i = 0; i < threads_in_system; i++) {
+ if (cpu_freqs[i].offline)
+ continue;
+
+ /* Sending signal 0 with pthread_kill will just check for
+ * the existance of the thread without actually sending a
+ * signal, we use this to see if the thread exited.
+ */
+ if (pthread_kill(cpu_freqs[i].tid, 0)) {
+ /* pthread exited, mark it offline iso we don't use
+ * it in our calculations and close its perf
+ * counter.
+ */
+ cpu_freqs[i].offline = 1;
+ close(cpu_freqs[i].counter);
+ }
}
}
@@ -846,7 +875,7 @@ static void *soak(void *arg)
if (sched_setaffinity(0, sizeof(cpumask), &cpumask)) {
perror("sched_setaffinity");
- exit(1);
+ pthread_exit(NULL);
}
while (1)
@@ -947,27 +976,28 @@ static int do_cpu_frequency(int sleep_time)
unsigned long max_cpu = -1UL;
unsigned long long sum = 0;
unsigned long count = 0;
+ struct cpu_freq *cpu_freqs;
setrlimit_open_files();
- memset(cpu_freq, 0, sizeof(cpu_freq));
- memset(counters, 0, sizeof(counters));
+ cpu_freqs = malloc(sizeof(*cpu_freqs) * threads_in_system);
+ memset(cpu_freqs, 0, sizeof(*cpu_freqs) * threads_in_system);
- rc = setup_counters();
- if (rc)
+ rc = setup_counters(cpu_freqs);
+ if (rc) {
+ free(cpu_freqs);
return rc;
+ }
/* Start a soak thread on each CPU */
for (i = 0; i < threads_in_system; i++) {
- pthread_t tid;
-
- if (!cpu_online(i)) {
- cpu_freq[i] = CPU_OFFLINE;
+ if (cpu_freqs[i].offline)
continue;
- }
- if (pthread_create(&tid, NULL, soak, (void *)(long)i)) {
+ if (pthread_create(&cpu_freqs[i].tid, NULL, soak,
+ (void *)(long)i)) {
perror("pthread_create");
+ free(cpu_freqs);
return -1;
}
}
@@ -975,32 +1005,31 @@ static int do_cpu_frequency(int sleep_time)
/* Wait for soak threads to start */
usleep(1000000);
- start_counters();
+ start_counters(cpu_freqs);
/* Count for specified timeout in seconds */
usleep(sleep_time * 1000000);
- stop_counters();
- read_counters();
+ stop_counters(cpu_freqs);
+ check_threads(cpu_freqs);
+ read_counters(cpu_freqs);
for (i = 0; i < threads_in_system; i++) {
- if (cpu_freq[i] == CPU_OFFLINE)
- continue;
+ unsigned long long frequency;
- /* No result - Couldn't schedule on that cpu */
- if (cpu_freq[i] == 0) {
- printf("WARNING: couldn't run on cpu %d\n", i);
+ if (cpu_freqs[i].offline)
continue;
- }
- if (cpu_freq[i] < min) {
- min = cpu_freq[i];
+ frequency = cpu_freqs[i].freq;
+
+ if (frequency < min) {
+ min = frequency;
min_cpu = i;
}
- if (cpu_freq[i] > max) {
- max = cpu_freq[i];
+ if (frequency > max) {
+ max = frequency;
max_cpu = i;
}
- sum += cpu_freq[i];
+ sum += frequency;
count++;
}
@@ -1010,6 +1039,8 @@ static int do_cpu_frequency(int sleep_time)
printf("max:\t%.3f GHz (cpu %ld)\n", freq_calc(max, sleep_time),
max_cpu);
printf("avg:\t%.3f GHz\n\n", freq_calc((sum / count), sleep_time));
+
+ free(cpu_freqs);
return 0;
}
|