[Skiboot] [RFC PATCH 4/6] core: Add statistics framework

Cédric Le Goater clg at kaod.org
Fri Sep 18 02:35:41 AEST 2020


This is a set of simple routines to collect statistics on function
calls. It can used to measure low level HW operations and track
possible issues in locking, polling, etc.

Signed-off-by: Cédric Le Goater <clg at kaod.org>
---
 include/stat.h    | 49 ++++++++++++++++++++++++
 core/stat.c       | 98 +++++++++++++++++++++++++++++++++++++++++++++++
 core/Makefile.inc |  2 +-
 3 files changed, 148 insertions(+), 1 deletion(-)
 create mode 100644 include/stat.h
 create mode 100644 core/stat.c

diff --git a/include/stat.h b/include/stat.h
new file mode 100644
index 000000000000..dc020862b199
--- /dev/null
+++ b/include/stat.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Statistics
+ *
+ * Copyright 2020 IBM Corp.
+ */
+
+#ifndef __STAT_H
+#define __STAT_H
+
+#include <lock.h>
+
+#define STAT_NR_RANGES		10
+#define STAT_RANGE_WIDTH	200 /* values */
+#define STAT_MAX_CALL_TIME	10  /* usecs */
+
+struct stat_range {
+	uint64_t count;
+	uint64_t sum;
+	uint64_t min;
+	uint64_t max;
+};
+
+struct stat {
+	const char *name;
+	uint64_t max_call_time;
+	uint64_t nr_ranges;
+	uint64_t count;
+	struct stat_range all;
+	struct stat_range ranges[STAT_NR_RANGES];
+
+	struct lock lock;
+};
+
+
+extern void stat_init(struct stat *s, const char *name, uint64_t max_call_time);
+extern void stat_update(struct stat *s, uint64_t call_time);
+extern int stat_printf(struct stat *s, void *buf, int size);
+
+#define stat_call(expr, s)						\
+({									\
+	uint64_t before = mftb();					\
+	int64_t __rc = (expr);						\
+	uint64_t call_time = tb_to_usecs(mftb() - before);		\
+	stat_update(s, call_time);					\
+	__rc;								\
+})
+
+#endif /* __STAT_H */
diff --git a/core/stat.c b/core/stat.c
new file mode 100644
index 000000000000..6d1ddf2f1a80
--- /dev/null
+++ b/core/stat.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Statistics
+ *
+ * Copyright 2020 IBM Corp.
+ */
+
+#define pr_fmt(fmt) "STAT: " fmt
+
+#include <cpu.h>
+#include <opal.h>
+#include <stat.h>
+#include <stack.h>
+
+static void stat_range_reset(struct stat_range *r)
+{
+	r->count = 0;
+	r->sum = 0;
+	r->max = 0;
+	r->min = 0xFFFFFFFFF;
+}
+
+void stat_init(struct stat *s, const char *name, uint64_t max_call_time)
+{
+	int i;
+
+	s->name = name;
+	s->max_call_time = max_call_time;
+	s->nr_ranges = ARRAY_SIZE(s->ranges);
+	for (i = 0; i < s->nr_ranges; i++)
+		stat_range_reset(&s->ranges[i]);
+	stat_range_reset(&s->all);
+	init_lock(&s->lock);
+}
+
+static void stat_range_update(struct stat_range *r, uint64_t call_time)
+{
+	r->sum += call_time;
+	if (call_time > r->max)
+		r->max = call_time;
+	if (call_time < r->min)
+		r->min = call_time;
+	r->count++;
+}
+
+#define stat_range_index(s) \
+	((((s)->count) / STAT_RANGE_WIDTH) % (s)->nr_ranges)
+
+void stat_update(struct stat *s, uint64_t call_time)
+{
+	int ridx;
+	struct stat_range *r;
+
+	lock(&s->lock);
+
+	ridx = stat_range_index(s);
+	r = &s->ranges[ridx];
+
+	if (!(r->count % STAT_RANGE_WIDTH))
+		stat_range_reset(r);
+
+	stat_range_update(r, call_time);
+	if (s->max_call_time && call_time > s->max_call_time &&
+	    call_time > s->all.max) {
+		/* TODO: simulators need more time */
+		prlog(PR_WARNING, "CPU 0x%04x new %s maximum %lld at #%lld\n",
+		      this_cpu()->pir, s->name, r->max, s->count);
+		backtrace();
+	}
+	stat_range_update(&s->all, call_time);
+	s->count++;
+
+	unlock(&s->lock);
+}
+
+static int stat_range_printf(struct stat_range *r, void *buf, int size)
+{
+	return snprintf(buf, size, "#%lld %lld/%lld/%lld - ",
+			r->count,
+			r->count ? r->min : 0,
+			r->sum / r->count,
+			r->max);
+}
+
+int stat_printf(struct stat *s, void *buf, int size)
+{
+	int n = 0;
+	int i;
+
+	if (s->count) {
+		n += snprintf(buf + n, size - n, "%35s: ", s->name);
+		n += stat_range_printf(&s->all, buf + n, size - n);
+		for (i = 0; i < s->nr_ranges; i++)
+			n += stat_range_printf(&s->ranges[i], buf + n, size - n);
+		n += snprintf(buf + n, size - n,"\n");
+	}
+	return n;
+}
diff --git a/core/Makefile.inc b/core/Makefile.inc
index ed7003ed7a7a..326fc7917631 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -13,7 +13,7 @@ CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
 CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o psr.o
 CORE_OBJS += pci-dt-slot.o direct-controls.o cpufeatures.o
 CORE_OBJS += flash-firmware-versions.o opal-dump.o
-CORE_OBJS += opal-debug.o
+CORE_OBJS += opal-debug.o stat.o
 
 ifeq ($(SKIBOOT_GCOV),1)
 CORE_OBJS += gcov-profiling.o
-- 
2.25.4



More information about the Skiboot mailing list