46
46
*/
47
47
48
48
#include <linux/cpumask.h>
49
+ #include <linux/debugfs.h>
49
50
#include <linux/device.h>
50
51
#include <linux/kernel_stat.h>
51
52
#include <linux/kstrtox.h>
52
53
#include <linux/ktime.h>
53
54
#include <linux/sysctl.h>
55
+ #include <linux/types.h>
54
56
#include <linux/workqueue.h>
55
57
#include <asm/hiperdispatch.h>
56
58
#include <asm/setup.h>
@@ -72,6 +74,9 @@ static int hd_entitled_cores; /* Total vertical high and medium CORE count */
72
74
static int hd_online_cores ; /* Current online CORE count */
73
75
74
76
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 */
75
80
76
81
static unsigned int hd_steal_threshold = HD_STEAL_THRESHOLD ;
77
82
static unsigned int hd_delay_factor = HD_DELAY_FACTOR ;
@@ -121,6 +126,33 @@ void hd_add_core(int cpu)
121
126
}
122
127
}
123
128
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
+
124
156
static void hd_update_capacities (void )
125
157
{
126
158
int cpu , upscaling_cores ;
@@ -149,6 +181,9 @@ void hd_disable_hiperdispatch(void)
149
181
150
182
int hd_enable_hiperdispatch (void )
151
183
{
184
+ mutex_lock (& hd_counter_mutex );
185
+ hd_update_times ();
186
+ mutex_unlock (& hd_counter_mutex );
152
187
if (hd_enabled == 0 )
153
188
return 0 ;
154
189
if (hd_entitled_cores == 0 )
@@ -225,6 +260,7 @@ static void hd_capacity_work_fn(struct work_struct *work)
225
260
if (hd_high_capacity_cores != new_cores ) {
226
261
trace_s390_hd_rebuild_domains (hd_high_capacity_cores , new_cores );
227
262
hd_high_capacity_cores = new_cores ;
263
+ atomic64_inc (& hd_adjustments );
228
264
topology_schedule_update ();
229
265
}
230
266
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 = {
327
363
.attrs = hd_attrs ,
328
364
};
329
365
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
+
330
406
static void __init hd_create_attributes (void )
331
407
{
332
408
struct device * dev ;
@@ -347,6 +423,7 @@ static int __init hd_init(void)
347
423
}
348
424
if (!register_sysctl ("s390" , hiperdispatch_ctl_table ))
349
425
pr_warn ("Failed to register s390.hiperdispatch sysctl attribute\n" );
426
+ hd_create_debugfs_counters ();
350
427
hd_create_attributes ();
351
428
return 0 ;
352
429
}
0 commit comments