summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2018-11-01 12:47:21 -0500
committerJason King <jason.king@joyent.com>2020-12-08 19:13:03 +0000
commitb56d7ba70c13eb53c9a274b4d47e3317fe87a716 (patch)
tree9623ce551f5fb6d91494ed0fb958030a67dd7435
parent88880f2384ccc4a2382a0fd56138ff5a6862866f (diff)
downloadillumos-joyent-b56d7ba70c13eb53c9a274b4d47e3317fe87a716.tar.gz
More load calculations
-rw-r--r--usr/src/cmd/intrd/intrd.c48
-rw-r--r--usr/src/cmd/intrd/intrd.h18
2 files changed, 59 insertions, 7 deletions
diff --git a/usr/src/cmd/intrd/intrd.c b/usr/src/cmd/intrd/intrd.c
index fa0ef14e45..4eb84461b3 100644
--- a/usr/src/cmd/intrd/intrd.c
+++ b/usr/src/cmd/intrd/intrd.c
@@ -218,18 +218,19 @@ setup(kstat_ctl_t **restrict kcpp, config_t *restrict cfg)
// XXX: Initialize cfg
}
+/*
+ * Temporary functions to output data during development. Maybe turn into
+ * debug output later.
+ */
static void
format_load(lgrp_id_t id, load_t *l, int indent)
{
char buf[NN_NUMBUF_SZ];
- double pct = 0.0;
nanonicenum(l->ld_intrtotal, buf, sizeof (buf));
- if (l->ld_total > 0)
- pct = (double)(l->ld_intrtotal * 100) / l->ld_total;
(void) printf("%*sLGRP %2d %zu CPUs intr %6ss (%3.1f%%)",
- indent * 2, "", id, l->ld_ncpu, buf, pct);
+ indent * 2, "", id, l->ld_ncpu, buf, l->ld_avgload * 100.0);
ivec_t *iv = l->ld_bigint;
@@ -350,12 +351,39 @@ delta_save(stats_t **deltas, size_t n, stats_t *newdelta, uint_t statslen)
}
static void
+calc_avgs(load_t *ld)
+{
+ double intr = (double)ld->ld_intrtotal;
+
+ if (ld->ld_ncpu == 0) {
+ ld->ld_avgnsec = 0.0;
+ ld->ld_avgload = 0.0;
+ return;
+ }
+
+ ld->ld_avgnsec = intr;
+ ld->ld_avgload = intr / ld->ld_total;
+
+ if (ld->ld_ncpu > 1) {
+ ld->ld_avgnsec /= ld->ld_ncpu;
+ ld->ld_avgload /= ld->ld_ncpu;
+ }
+}
+
+static void
calc_lgrp_load(cpugrp_t *grp, load_t *ld, lgrp_id_t id)
{
cpugrp_t *cg = grp + id;
load_t *lgrp = LOAD_LGRP(ld, id);
for (size_t i = 0; i < cg->cg_nchildren; i++) {
+ /*
+ * The values of an lgrp load_t entry are the sums of all
+ * the children lgrps (for ld_bigint, it is the interrupt
+ * consuming the most time in any of the child lgrps) of
+ * this lgrp. Recursively calculate any children first so
+ * their values are calculated before we calculate ours.
+ */
calc_lgrp_load(grp, ld, cg->cg_children[i]);
load_t *lchild = LOAD_LGRP(ld, cg->cg_children[i]);
@@ -365,6 +393,7 @@ calc_lgrp_load(cpugrp_t *grp, load_t *ld, lgrp_id_t id)
lgrp->ld_bigint = LOAD_MAXINT(lgrp, lchild);
lgrp->ld_ncpu += lchild->ld_ncpu;
}
+ calc_avgs(lgrp);
}
static intrd_walk_ret_t
@@ -385,6 +414,7 @@ calc_load_cb(stats_t *stp, cpustat_t *cs, void *arg)
if (LOAD_BIGINT_LOAD(lcpu) < iv->ivec_time)
lcpu->ld_bigint = iv;
}
+ calc_avgs(lcpu);
load_t *lgrp = LOAD_LGRP(load, cs->cs_lgrp);
@@ -395,11 +425,21 @@ calc_load_cb(stats_t *stp, cpustat_t *cs, void *arg)
return (INTRD_WALK_NEXT);
}
+
static load_t *
calc_load(stats_t *stp)
{
load_t *ld = xcalloc(max_cpu + stp->sts_nlgrp, sizeof (load_t));
+ /*
+ * Calculate the load_t values for all the CPU entries first. If one
+ * thinks of the locality topology as a tree, the leaf lgrps (ones
+ * without any child lgrps) are the ones that will directly contain
+ * CPUs (these are also the lgrp_id_t values stored in
+ * cpustat_t->cs_lgrp). We also calculate those lgrp leaves at the same
+ * time we are calculating the per-CPU values in calc_load_cb().
+ * We can then calculate any parent lgrps in calc_lgrp_load().
+ */
VERIFY3S(cpu_iter(stp, calc_load_cb, ld), ==, INTRD_WALK_DONE);
calc_lgrp_load(stp->sts_lgrp, ld, 0);
return (ld);
diff --git a/usr/src/cmd/intrd/intrd.h b/usr/src/cmd/intrd/intrd.h
index 3bc00d2ec3..8f57acb6cb 100644
--- a/usr/src/cmd/intrd/intrd.h
+++ b/usr/src/cmd/intrd/intrd.h
@@ -42,6 +42,8 @@ typedef struct config {
/*
* An interrupt vector, corresponding to the data from a pci_intrs kstat.
+ * For shared interrupts, this may also represent a consolidated picture of
+ * all of those shared interrupts.
*/
typedef struct ivec {
list_node_t ivec_node;
@@ -78,7 +80,9 @@ typedef struct cpustat {
} cpustat_t;
/*
- * The locality group data.
+ * The locality group data. Since NLGRPS_MAX is only available in the kernel
+ * and not userland, the array holding the IDs of the children of any lgrp
+ * is dynamically allocated.
*/
typedef struct cpugrp {
lgrp_id_t cg_id;
@@ -93,9 +97,13 @@ typedef struct cpugrp {
* sts_{min,max}time represent the smallest and largest values of
* kstat_t.ks_crtime of all the individual kstats used to create this snapshot.
*
- * cpustat_t's are indexed by CPU id. That is, the cpustat_t for CPU 5 is
+ * cpustat_t's are indexed by CPU id. For example, the cpustat_t for CPU 5 is
* sts_cpu[5] -- i.e. there may be gaps in this. It is sized to hold
* max_cpu (i.e. _SC_N_PROCESSORS_MAX) cpustat_t *'s.
+ *
+ * It also includes a snapshot of the locality groups near in time to when
+ * the kstats for this stats_t were read (i.e. we read the kstats, then grab
+ * the lgrp info).
*/
typedef struct stats {
kid_t sts_kid;
@@ -117,11 +125,15 @@ typedef struct stats {
* total time, as well as the average interrupt time per cpu. In addition,
* we keep a reference to ivec consuming the most time. A load_t is created
* per cpu, as well as per locality group. The load_t's for lgrps are
- * aggregated over all the cpus in a given lgrp.
+ * aggregated over all the cpus in a given lgrp. The results are stored in
+ * an array of load_t's where the first max_cpu entries represent the load of
+ * the corresponding CPU, followed by the locality groups.
*/
typedef struct load {
uint64_t ld_total;
uint64_t ld_intrtotal;
+ double ld_avgnsec;
+ double ld_avgload;
ivec_t *ld_bigint;
size_t ld_ncpu;
} load_t;