Skip to content

Commit ea31f1c

Browse files
NickJackolsonVasily Gorbik
authored andcommitted
s390/hiperdispatch: Add hiperdispatch debug counters
Add three counters to follow and understand hiperdispatch behavior; * adjustment_count (amount of capacity adjustments triggered) * greedy_time_ms (time spent while all cpus are on high capacity) * conservative_time_ms (time spent while only entitled cpus are on high capacity) These counters can be found under /sys/kernel/debug/s390/hiperdispatch/ Time counters are in <msec> format and only cover the time spent when hiperdispatch is active. Acked-by: Vasily Gorbik <[email protected]> Signed-off-by: Mete Durlu <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent 441cc6f commit ea31f1c

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

arch/s390/kernel/hiperdispatch.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@
4646
*/
4747

4848
#include <linux/cpumask.h>
49+
#include <linux/debugfs.h>
4950
#include <linux/device.h>
5051
#include <linux/kernel_stat.h>
5152
#include <linux/kstrtox.h>
5253
#include <linux/ktime.h>
5354
#include <linux/sysctl.h>
55+
#include <linux/types.h>
5456
#include <linux/workqueue.h>
5557
#include <asm/hiperdispatch.h>
5658
#include <asm/setup.h>
@@ -72,6 +74,9 @@ static int hd_entitled_cores; /* Total vertical high and medium CORE count */
7274
static int hd_online_cores; /* Current online CORE count */
7375

7476
static unsigned long hd_previous_steal; /* Previous iteration's CPU steal timer total */
77+
static unsigned long hd_high_time; /* Total time spent while all cpus have high capacity */
78+
static unsigned long hd_low_time; /* Total time spent while vl cpus have low capacity */
79+
static atomic64_t hd_adjustments; /* Total occurrence count of hiperdispatch adjustments */
7580

7681
static unsigned int hd_steal_threshold = HD_STEAL_THRESHOLD;
7782
static unsigned int hd_delay_factor = HD_DELAY_FACTOR;
@@ -121,6 +126,33 @@ void hd_add_core(int cpu)
121126
}
122127
}
123128

129+
/* Serialize update and read operations of debug counters. */
130+
static DEFINE_MUTEX(hd_counter_mutex);
131+
132+
static void hd_update_times(void)
133+
{
134+
static ktime_t prev;
135+
ktime_t now;
136+
137+
/*
138+
* Check if hiperdispatch is active, if not set the prev to 0.
139+
* This way it is possible to differentiate the first update iteration after
140+
* enabling hiperdispatch.
141+
*/
142+
if (hd_entitled_cores == 0 || hd_enabled == 0) {
143+
prev = ktime_set(0, 0);
144+
return;
145+
}
146+
now = ktime_get();
147+
if (ktime_after(prev, 0)) {
148+
if (hd_high_capacity_cores == hd_online_cores)
149+
hd_high_time += ktime_ms_delta(now, prev);
150+
else
151+
hd_low_time += ktime_ms_delta(now, prev);
152+
}
153+
prev = now;
154+
}
155+
124156
static void hd_update_capacities(void)
125157
{
126158
int cpu, upscaling_cores;
@@ -149,6 +181,9 @@ void hd_disable_hiperdispatch(void)
149181

150182
int hd_enable_hiperdispatch(void)
151183
{
184+
mutex_lock(&hd_counter_mutex);
185+
hd_update_times();
186+
mutex_unlock(&hd_counter_mutex);
152187
if (hd_enabled == 0)
153188
return 0;
154189
if (hd_entitled_cores == 0)
@@ -225,6 +260,7 @@ static void hd_capacity_work_fn(struct work_struct *work)
225260
if (hd_high_capacity_cores != new_cores) {
226261
trace_s390_hd_rebuild_domains(hd_high_capacity_cores, new_cores);
227262
hd_high_capacity_cores = new_cores;
263+
atomic64_inc(&hd_adjustments);
228264
topology_schedule_update();
229265
}
230266
trace_s390_hd_work_fn(steal_percentage, hd_entitled_cores, hd_high_capacity_cores);
@@ -327,6 +363,46 @@ static const struct attribute_group hd_attr_group = {
327363
.attrs = hd_attrs,
328364
};
329365

366+
static int hd_greedy_time_get(void *unused, u64 *val)
367+
{
368+
mutex_lock(&hd_counter_mutex);
369+
hd_update_times();
370+
*val = hd_high_time;
371+
mutex_unlock(&hd_counter_mutex);
372+
return 0;
373+
}
374+
375+
DEFINE_SIMPLE_ATTRIBUTE(hd_greedy_time_fops, hd_greedy_time_get, NULL, "%llu\n");
376+
377+
static int hd_conservative_time_get(void *unused, u64 *val)
378+
{
379+
mutex_lock(&hd_counter_mutex);
380+
hd_update_times();
381+
*val = hd_low_time;
382+
mutex_unlock(&hd_counter_mutex);
383+
return 0;
384+
}
385+
386+
DEFINE_SIMPLE_ATTRIBUTE(hd_conservative_time_fops, hd_conservative_time_get, NULL, "%llu\n");
387+
388+
static int hd_adjustment_count_get(void *unused, u64 *val)
389+
{
390+
*val = atomic64_read(&hd_adjustments);
391+
return 0;
392+
}
393+
394+
DEFINE_SIMPLE_ATTRIBUTE(hd_adjustments_fops, hd_adjustment_count_get, NULL, "%llu\n");
395+
396+
static void __init hd_create_debugfs_counters(void)
397+
{
398+
struct dentry *dir;
399+
400+
dir = debugfs_create_dir("hiperdispatch", arch_debugfs_dir);
401+
debugfs_create_file("conservative_time_ms", 0400, dir, NULL, &hd_conservative_time_fops);
402+
debugfs_create_file("greedy_time_ms", 0400, dir, NULL, &hd_greedy_time_fops);
403+
debugfs_create_file("adjustment_count", 0400, dir, NULL, &hd_adjustments_fops);
404+
}
405+
330406
static void __init hd_create_attributes(void)
331407
{
332408
struct device *dev;
@@ -347,6 +423,7 @@ static int __init hd_init(void)
347423
}
348424
if (!register_sysctl("s390", hiperdispatch_ctl_table))
349425
pr_warn("Failed to register s390.hiperdispatch sysctl attribute\n");
426+
hd_create_debugfs_counters();
350427
hd_create_attributes();
351428
return 0;
352429
}

0 commit comments

Comments
 (0)