Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157048654
D56547.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D56547.diff
View Options
diff --git a/sys/kern/subr_hmp.c b/sys/kern/subr_hmp.c
--- a/sys/kern/subr_hmp.c
+++ b/sys/kern/subr_hmp.c
@@ -23,14 +23,164 @@
/* Per-CPU HMP state */
DPCPU_DEFINE(struct hmp_pcpu, hmp_pcpu);
+/*
+ * Provider interfaces
+ *
+ * Capacity and score providers live on independent lists and are selected
+ * independently at boot. Selection runs in two phases (see hmp_init):
+ * capacity first, then scores.
+ */
+static SLIST_HEAD(, hmp_capacity_provider) hmp_cap_providers =
+ SLIST_HEAD_INITIALIZER(hmp_cap_providers);
+static SLIST_HEAD(, hmp_score_provider) hmp_score_providers =
+ SLIST_HEAD_INITIALIZER(hmp_score_providers);
+
+static struct hmp_capacity_provider *hmp_active_cap_provider;
+static struct hmp_score_provider *hmp_active_score_provider;
+
+void
+hmp_capacity_provider_register(struct hmp_capacity_provider *p)
+{
+ KASSERT(p->name != NULL, ("hmp: capacity provider missing name"));
+ KASSERT(p->probe != NULL && p->init != NULL,
+ ("hmp: capacity provider %s missing probe/init", p->name));
+
+ SLIST_INSERT_HEAD(&hmp_cap_providers, p, link);
+}
+
+void
+hmp_score_provider_register(struct hmp_score_provider *p)
+{
+ KASSERT(p->name != NULL, ("hmp: score provider missing name"));
+ KASSERT(p->probe != NULL && p->init != NULL,
+ ("hmp: score provider %s missing probe/init", p->name));
+
+ SLIST_INSERT_HEAD(&hmp_score_providers, p, link);
+}
+
+/*
+ * Default capacity provider.
+ *
+ * Always wins if nothing else probes: every CPU gets HMP_CAPACITY_DEFAULT,
+ * which collapses HMP decisions down to "any CPU is fine." There is no
+ * default score provider; absence of scores is a valid state.
+ */
+
+static int
+hmp_default_cap_probe(void)
+{
+ return (0);
+}
+
+static int
+hmp_default_cap_init(void)
+{
+ struct hmp_pcpu *hp;
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ hp = DPCPU_ID_PTR(cpu, hmp_pcpu);
+ hp->capacity = HMP_CAPACITY_DEFAULT;
+ }
+
+ return (0);
+}
+
+static struct hmp_capacity_provider hmp_default_cap_provider = {
+ .name = "default",
+ .priority = 0,
+ .probe = hmp_default_cap_probe, /* always true */
+ .init = hmp_default_cap_init,
+};
+HMP_CAPACITY_PROVIDER_DECLARE(default, hmp_default_cap_provider);
+
/*
* Initialization
*/
+static void
+hmp_set_total_capacity(void)
+{
+ struct hmp_pcpu *hp;
+ int cpu;
+
+ hmp_state.total_capacity = 0;
+
+ CPU_FOREACH(cpu) {
+ hp = DPCPU_ID_PTR(cpu, hmp_pcpu);
+ hmp_state.total_capacity += hp->capacity;
+ }
+}
+
+static void
+hmp_init_capacity(void)
+{
+ struct hmp_capacity_provider *p, *best;
+
+ SLIST_FOREACH(p, &hmp_cap_providers, link) {
+ if (p->probe() == 0)
+ p->probed = true;
+ }
+
+ for (;;) {
+ best = NULL;
+ SLIST_FOREACH(p, &hmp_cap_providers, link) {
+ if (!p->probed)
+ continue;
+ if (best == NULL || p->priority > best->priority)
+ best = p;
+ }
+ if (best == NULL)
+ break;
+ if (best->init() == 0)
+ break;
+ best->probed = false;
+ }
+
+ KASSERT(best != NULL,
+ ("hmp: no capacity provider init succeeded, not even default"));
+ best->active = true;
+ hmp_active_cap_provider = best;
+ hmp_set_total_capacity();
+}
+
+static void
+hmp_init_scores(void)
+{
+ struct hmp_score_provider *p, *best;
+
+ SLIST_FOREACH(p, &hmp_score_providers, link) {
+ if (p->probe() == 0)
+ p->probed = true;
+ }
+
+ for (;;) {
+ best = NULL;
+ SLIST_FOREACH(p, &hmp_score_providers, link) {
+ if (!p->probed)
+ continue;
+ if (best == NULL || p->priority > best->priority)
+ best = p;
+ }
+ if (best == NULL) {
+ hmp_state.has_scores = false;
+ return;
+ }
+ if (best->init() == 0)
+ break;
+ best->probed = false;
+ }
+
+ best->active = true;
+ hmp_active_score_provider = best;
+ hmp_state.has_scores = true;
+}
+
static void
hmp_init(void *arg __unused)
{
- /* Choose and call provider */
+ hmp_init_capacity();
+ hmp_init_scores();
}
SYSINIT(hmp, SI_SUB_SMP + 1, SI_ORDER_ANY, hmp_init, NULL);
@@ -175,6 +325,45 @@
return (sysctl_handle_int(oidp, &v, 0, req));
}
+static int
+hmp_sysctl_active_cap_provider(SYSCTL_HANDLER_ARGS)
+{
+ const char *name;
+
+ name = (hmp_active_cap_provider != NULL) ?
+ hmp_active_cap_provider->name : "none";
+ return (sysctl_handle_string(oidp, __DECONST(char *, name), 0, req));
+}
+
+static int
+hmp_sysctl_active_score_provider(SYSCTL_HANDLER_ARGS)
+{
+ const char *name;
+
+ name = (hmp_active_score_provider != NULL) ?
+ hmp_active_score_provider->name : "none";
+ return (sysctl_handle_string(oidp, __DECONST(char *, name), 0, req));
+}
+
+static void
+hmp_sysctl_add_provider(struct sysctl_oid_list *parent, const char *name,
+ int *priority, bool *probed, bool *active)
+{
+ struct sysctl_oid *node;
+
+ node = SYSCTL_ADD_NODE(NULL, parent, OID_AUTO, name,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "HMP provider state");
+ if (node == NULL)
+ return;
+
+ SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(node), OID_AUTO, "priority",
+ CTLFLAG_RD, priority, 0, "Provider priority (higher wins)");
+ SYSCTL_ADD_BOOL(NULL, SYSCTL_CHILDREN(node), OID_AUTO, "probed",
+ CTLFLAG_RD, probed, 0, "probe() returned true on this system");
+ SYSCTL_ADD_BOOL(NULL, SYSCTL_CHILDREN(node), OID_AUTO, "active",
+ CTLFLAG_RD, active, 0, "Selected as the active provider");
+}
+
static SYSCTL_NODE(_kern, OID_AUTO, hmp, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
"Heterogeneous multi-processing state");
@@ -190,8 +379,11 @@
hmp_sysctl_init(void *arg __unused)
{
struct sysctl_oid *cpu_root, *cpu_node, *cpu_score_node;
+ struct sysctl_oid *provider_root, *cap_root, *score_root;
struct sysctl_oid_list *cpu_root_children, *cpu_children;
- struct sysctl_oid_list *cpu_score_children;
+ struct sysctl_oid_list *cpu_score_children, *provider_children;
+ struct hmp_capacity_provider *cp;
+ struct hmp_score_provider *sp;
char name[8];
int cpu;
@@ -245,5 +437,58 @@
"Current efficiency score (dynamic)");
}
}
+
+ /*
+ * Provider tree.
+ *
+ * kern.hmp.provider.active_capacity
+ * - name of the winning capacity provider (always set)
+ * kern.hmp.provider.active_score
+ * - name of the winning score provider, or "" if none
+ * kern.hmp.provider.capacity.<n>.{priority,probed,active}
+ * kern.hmp.provider.score.<n>.{priority,probed,active}
+ *
+ * Every registered provider is listed on each side, not just the
+ * winner, so operators can see which providers were available and
+ * why one was chosen over another.
+ */
+ provider_root = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_kern_hmp),
+ OID_AUTO, "provider", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
+ "Registered HMP providers");
+ if (provider_root == NULL)
+ return;
+ provider_children = SYSCTL_CHILDREN(provider_root);
+
+ SYSCTL_ADD_PROC(NULL, provider_children,
+ OID_AUTO, "active_capacity",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+ hmp_sysctl_active_cap_provider, "A",
+ "Name of the active HMP capacity provider");
+
+ SYSCTL_ADD_PROC(NULL, provider_children,
+ OID_AUTO, "active_score",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+ hmp_sysctl_active_score_provider, "A",
+ "Name of the active HMP score provider (empty if none)");
+
+ cap_root = SYSCTL_ADD_NODE(NULL, provider_children,
+ OID_AUTO, "capacity", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
+ "Registered HMP capacity providers");
+ if (cap_root != NULL) {
+ SLIST_FOREACH(cp, &hmp_cap_providers, link) {
+ hmp_sysctl_add_provider(SYSCTL_CHILDREN(cap_root),
+ cp->name, &cp->priority, &cp->probed, &cp->active);
+ }
+ }
+
+ score_root = SYSCTL_ADD_NODE(NULL, provider_children,
+ OID_AUTO, "score", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
+ "Registered HMP score providers");
+ if (score_root != NULL) {
+ SLIST_FOREACH(sp, &hmp_score_providers, link) {
+ hmp_sysctl_add_provider(SYSCTL_CHILDREN(score_root),
+ sp->name, &sp->priority, &sp->probed, &sp->active);
+ }
+ }
}
SYSINIT(hmp_sysctl, SI_SUB_SMP + 2, SI_ORDER_ANY, hmp_sysctl_init, NULL);
diff --git a/sys/sys/hmp.h b/sys/sys/hmp.h
--- a/sys/sys/hmp.h
+++ b/sys/sys/hmp.h
@@ -15,6 +15,7 @@
#include <sys/types.h>
#include <sys/pcpu.h>
+#include <sys/queue.h>
#include <machine/atomic.h>
@@ -58,6 +59,11 @@
/*
* System-wide CPU capability state - initialized on boot
+ *
+ * total_capacity is populated once the capacity provider finishes init().
+ * has_scores is set to true once a score provider has won selection and
+ * finished init(); when false, the scheduler must fall back to capacity-only
+ * placement decisions.
*/
struct hmp {
hmp_score_t total_capacity; /* Precalculated for scheduler */
@@ -92,6 +98,77 @@
atomic_store_rel_16(&hp->scores[st], score);
}
+/*
+ * Provider interfaces
+ *
+ * HMP is fed by two independent provider paths:
+ *
+ * probe() must not touch hmp_pcpu state.
+ * init() is called once, only on the winning provider of each path.
+ */
+
+/*
+ * Capacity provider
+ *
+ * Populate the static per-CPU capacity field and hmp_state.total_capacity.
+ * Exactly one capacity provider wins at boot (highest priority among
+ * those whose probe() returns true).
+ */
+struct hmp_capacity_provider {
+ const char *name;
+ int priority; /* higher wins */
+ int (*probe)(void);
+ int (*init)(void);
+
+ /* Filled in by registration; do not set manually. */
+ bool probed;
+ bool active;
+
+ SLIST_ENTRY(hmp_capacity_provider) link;
+};
+
+/*
+ * Score provider
+ *
+ * Populate and maintain per-CPU perf/eff scores and flags.
+ * Exactly one score provider wins at boot. Score provider can be absent
+ * (hmp_state.has_scores stays false and the scheduler uses capacity-only
+ * placement).
+ */
+struct hmp_score_provider {
+ const char *name;
+ int priority; /* higher wins */
+ int (*probe)(void);
+ int (*init)(void);
+
+ /* Filled in by registration; do not set manually. */
+ bool probed;
+ bool active;
+
+ SLIST_ENTRY(hmp_score_provider) link;
+};
+
+void hmp_capacity_provider_register(struct hmp_capacity_provider *p);
+void hmp_score_provider_register(struct hmp_score_provider *p);
+
+#define HMP_CAPACITY_PROVIDER_DECLARE(name, provider) \
+ DATA_SET(hmp_capacity_provider_set, provider); \
+ static void hmp_cap_provider_##name##_register(void *arg __unused) \
+ { \
+ hmp_capacity_provider_register(&(provider)); \
+ } \
+ SYSINIT(hmp_cap_provider_##name, SI_SUB_SMP, SI_ORDER_ANY, \
+ hmp_cap_provider_##name##_register, NULL)
+
+#define HMP_SCORE_PROVIDER_DECLARE(name, provider) \
+ DATA_SET(hmp_score_provider_set, provider); \
+ static void hmp_score_provider_##name##_register(void *arg __unused) \
+ { \
+ hmp_score_provider_register(&(provider)); \
+ } \
+ SYSINIT(hmp_score_provider_##name, SI_SUB_SMP, SI_ORDER_ANY, \
+ hmp_score_provider_##name##_register, NULL)
+
/*
* Helper functions for scheduler
*/
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, May 19, 3:21 AM (5 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33289060
Default Alt Text
D56547.diff (10 KB)
Attached To
Mode
D56547: hmp(4): add provider interface
Attached
Detach File
Event Timeline
Log In to Comment