Skip to content

Commit

Permalink
drivers: soc: Implement long irq metrics in metrics driver
Browse files Browse the repository at this point in the history
Bug: 227809911
Signed-off-by: Ziyi Cui <[email protected]>
Change-Id: I6d56f8a2a1d6dae733f7b86600858c7a4b39e58e
  • Loading branch information
Ziyi Cui committed Nov 14, 2022
1 parent 7d476f0 commit 1db8cb2
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 0 deletions.
223 changes: 223 additions & 0 deletions drivers/soc/google/vh/kernel/metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "metrics.h"

static struct resume_latency resume_latency_stats;
static struct long_irq long_irq_stat;
static struct kobject *primary_sysfs_folder;

/*********************************************************************
Expand Down Expand Up @@ -71,7 +72,67 @@ static void vendor_hook_resume_end(void *data, void *unused)
resume_latency_stats.resume_start = resume_latency_stats.resume_end;
}

static void hook_softirq_begin(void *data, unsigned int vec_nr)
{
int cpu_num;
cpu_num = raw_smp_processor_id();
long_irq_stat.softirq_start[cpu_num][vec_nr] = ktime_get();
}

static void hook_softirq_end(void *data, unsigned int vec_nr)
{
s64 irq_usec;
int cpu_num;
s64 curr_max_irq;
if (vec_nr >= NR_SOFTIRQS)
return;
cpu_num = raw_smp_processor_id();
long_irq_stat.softirq_end = ktime_get();
irq_usec = ktime_to_us(ktime_sub(long_irq_stat.softirq_end,
long_irq_stat.softirq_start[cpu_num][vec_nr]));
if (irq_usec >= long_irq_stat.long_softirq_threshold) {
if (long_irq_stat.display_warning)
WARN("%s","Got a long running irq: softirq\n");
atomic64_inc(&(long_irq_stat.long_softirq_count));
}
do {
curr_max_irq = long_irq_stat.long_softirq_arr[vec_nr];
if (irq_usec < curr_max_irq)
return;
} while (cmpxchg64(&long_irq_stat.long_softirq_arr[vec_nr],
curr_max_irq, irq_usec) != curr_max_irq);
}

static void hook_irq_begin(void *data, int irq, struct irqaction *action)
{
int cpu_num;
cpu_num = raw_smp_processor_id();
long_irq_stat.irq_start[cpu_num][irq] = ktime_get();
}

static void hook_irq_end(void *data, int irq, struct irqaction *action, int ret)
{
s64 irq_usec;
int cpu_num;
s64 curr_max_irq;
if (irq >= MAX_IRQ_NUM)
return;
cpu_num = raw_smp_processor_id();
long_irq_stat.irq_end = ktime_get();
irq_usec = ktime_to_us(ktime_sub(long_irq_stat.irq_end,
long_irq_stat.irq_start[cpu_num][irq]));
if (irq_usec >= long_irq_stat.long_irq_threshold) {
if (long_irq_stat.display_warning)
WARN("%s","Got a long running irq: irq_handler\n");
atomic64_inc(&(long_irq_stat.long_irq_count));
}
do {
curr_max_irq = long_irq_stat.long_irq_arr[irq];
if (irq_usec < curr_max_irq)
break;
} while (cmpxchg64(&long_irq_stat.long_irq_arr[irq],
curr_max_irq, irq_usec) != curr_max_irq);
}
/*******************************************************************
* SYSFS *
*******************************************************************/
Expand Down Expand Up @@ -134,12 +195,148 @@ static ssize_t resume_latency_metrics_store(struct kobject *kobj,
spin_unlock(&resume_latency_stats.resume_latency_stat_lock);
return count;
}
static ssize_t long_irq_metrics_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
ssize_t count = 0;
int index;
s64 latency;
int irq_num;
count += sysfs_emit_at(buf, count, "Long running SOFTIRQ count: %lld\n",
atomic64_read(&(long_irq_stat.long_softirq_count)));
for (index = 0; index < NR_SOFTIRQS; index++) {
latency = long_irq_stat.long_softirq_arr[index];
irq_num = index;
count += sysfs_emit_at(buf, count,
"long SOFTIRQ latency: %lld, long SOFTIRQ num: %d\n", latency, irq_num);
}
count += sysfs_emit_at(buf, count, "Long running IRQ count: %lld\n",
atomic64_read(&(long_irq_stat.long_irq_count)));
for (index = 0; index < MAX_IRQ_NUM; index++) {
latency = long_irq_stat.long_irq_arr[index];
irq_num = index;
count += sysfs_emit_at(buf, count,
"long IRQ latency: %lld, long IRQ num: %d\n", latency, irq_num);
}
return count;
}

static ssize_t modify_softirq_threshold_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
ssize_t count = 0;
count += sysfs_emit_at(buf, count,"%lld\n", long_irq_stat.long_softirq_threshold);
return count;
}

static ssize_t modify_softirq_threshold_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf,
size_t count)
{
s64 new_threshold_us;
int err = sscanf (buf, "%lld", &new_threshold_us);
if (!err || new_threshold_us < 0) {
return count;
}
long_irq_stat.long_softirq_threshold = new_threshold_us;
atomic64_set(&(long_irq_stat.long_softirq_count), 0);
return count;
}

static ssize_t modify_irq_threshold_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
ssize_t count = 0;
count += sysfs_emit_at(buf, count,"%lld\n", long_irq_stat.long_irq_threshold);
return count;
}

static ssize_t modify_irq_threshold_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf,
size_t count)
{
s64 new_threshold_us;
int err = sscanf (buf, "%lld", &new_threshold_us);
if (!err || new_threshold_us < 0) {
return count;
}
long_irq_stat.long_irq_threshold = new_threshold_us;
atomic64_set(&(long_irq_stat.long_irq_count), 0);
return count;
}

static ssize_t display_warning_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
ssize_t count = 0;
if (long_irq_stat.display_warning) {
count += sysfs_emit_at(buf, count,"%s",
"WARN is turned on\n");
} else {
count += sysfs_emit_at(buf, count,"%s",
"WARN is turned off\n");
}
return count;
}

static ssize_t display_warning_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf,
size_t count)
{
int display_warn;
int err = sscanf (buf, "%d", &display_warn);
if (!err) {
return count;
}
if (display_warn == 0) {
long_irq_stat.display_warning = false;
}
if (display_warn == 1) {
long_irq_stat.display_warning = true;
}
return count;
}

static struct kobj_attribute resume_latency_metrics_attr = __ATTR(resume_latency_metrics,
0664,
resume_latency_metrics_show,
resume_latency_metrics_store);
static struct kobj_attribute long_irq_metrics_attr = __ATTR(long_irq_metrics,
0444,
long_irq_metrics_show,
NULL);
static struct kobj_attribute modify_softirq_threshold_attr = __ATTR(modify_softirq_threshold,
0664,
modify_softirq_threshold_show,
modify_softirq_threshold_store);
static struct kobj_attribute modify_irq_threshold_attr = __ATTR(modify_irq_threshold,
0664,
modify_irq_threshold_show,
modify_irq_threshold_store);
static struct kobj_attribute display_warning_attr = __ATTR(display_warning,
0664,
display_warning_show,
display_warning_store);

static struct attribute *irq_attrs[] = {
&long_irq_metrics_attr.attr,
&modify_softirq_threshold_attr.attr,
&modify_irq_threshold_attr.attr,
&display_warning_attr.attr,
NULL
};

static const struct attribute_group irq_attr_group = {
.attrs = irq_attrs,
.name = "irq"
};

static struct attribute *resume_latency_attrs[] = {
&resume_latency_metrics_attr.attr,
Expand Down Expand Up @@ -167,6 +364,10 @@ static int __init perf_metrics_init(void)
pr_err("failed to create resume_latency folder\n");
return ret;
}
if (sysfs_create_group(primary_sysfs_folder, &irq_attr_group)) {
pr_err("failed to create irq folder\n");
return ret;
}
spin_lock_init(&resume_latency_stats.resume_latency_stat_lock);
ret = register_trace_android_vh_early_resume_begin(
vendor_hook_resume_begin, NULL);
Expand All @@ -180,6 +381,28 @@ static int __init perf_metrics_init(void)
pr_err("Register resume end vendor hook fail %d\n", ret);
return ret;
}
long_irq_stat.long_softirq_threshold = 10000;
long_irq_stat.long_irq_threshold = 500;
ret = register_trace_softirq_entry(hook_softirq_begin, NULL);
if (ret) {
pr_err("Register soft irq handler hook fail %d\n", ret);
return ret;
}
ret = register_trace_softirq_exit(hook_softirq_end, NULL);
if (ret) {
pr_err("Register soft irq exit hook fail %d\n", ret);
return ret;
}
ret = register_trace_irq_handler_entry(hook_irq_begin, NULL);
if (ret) {
pr_err("Register irq handler hook fail %d\n", ret);
return ret;
}
ret = register_trace_irq_handler_exit(hook_irq_end, NULL);
if (ret) {
pr_err("Register irq exit hook fail %d\n", ret);
return ret;
}
pr_info("perf_metrics driver initialized! :D\n");
return ret;
}
Expand Down
16 changes: 16 additions & 0 deletions drivers/soc/google/vh/kernel/metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define RESUME_LATENCY_BOUND_MID 500
#define RESUME_LATENCY_BOUND_MAX 1000

#define MAX_IRQ_NUM 1024

#define LATENCY_CNT_SMALL (RESUME_LATENCY_BOUND_SMALL / RESUME_LATENCY_STEP_SMALL)
#define LATENCY_CNT_MID ((RESUME_LATENCY_BOUND_MID - RESUME_LATENCY_BOUND_SMALL) / \
RESUME_LATENCY_STEP_MID)
Expand All @@ -30,3 +32,17 @@ struct resume_latency {
s64 resume_latency_max_ms;
u64 resume_latency_sum_ms;
};

struct long_irq {
ktime_t softirq_start[CONFIG_VH_SCHED_CPU_NR][NR_SOFTIRQS];
ktime_t softirq_end;
ktime_t irq_start[CONFIG_VH_SCHED_CPU_NR][MAX_IRQ_NUM];
ktime_t irq_end;
atomic64_t long_softirq_count;
atomic64_t long_irq_count;
s64 long_softirq_arr[NR_SOFTIRQS];
s64 long_irq_arr[MAX_IRQ_NUM];
s64 long_softirq_threshold;
s64 long_irq_threshold;
bool display_warning;
};

0 comments on commit 1db8cb2

Please sign in to comment.