[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 3/3] x86/smt: Support for enabling/disabling SMT at runtime



Currently, a user can in combine the output of `xl info -n`, the APCI tables,
and some manual CPUID data to figure out which CPU numbers to feed into
`xen-hptool cpu-offline` to effectively disable SMT at runtime.

A more convenient option is to teach Xen how to perform this action.

First of all, extend XEN_SYSCTL_cpu_hotplug with two new operations.
Introduce new smt_{up,down}_helper() functions which wrap the
cpu_{up,down}_helper() helpers with logic which understands siblings based on
their APIC_ID.

Add libxc stubs, and extend xen-hptool with smt-{enable,disable} options.
These are intended to be shorthands for a loop over cpu-{online,offline}.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Wei Liu <wei.liu2@xxxxxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>

Slightly RFC.  I'm not very happy with the contination situation, but -EBUSY
is the preexisting style and it seems like it is the only option from tasklet
context.

Is it intentional that we can actually online and offline processors beyond
maxcpu?  This is a consequence of the cpu parking logic.
---
 tools/libxc/include/xenctrl.h   |  2 +
 tools/libxc/xc_cpu_hotplug.c    | 26 +++++++++++
 tools/misc/xen-hptool.c         | 56 ++++++++++++++++++++++++
 xen/arch/x86/setup.c            |  2 +-
 xen/arch/x86/sysctl.c           | 96 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/processor.h |  1 +
 xen/include/public/sysctl.h     |  9 ++++
 7 files changed, 191 insertions(+), 1 deletion(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index a3628e5..49a6b2a 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1854,6 +1854,8 @@ int xc_pm_reset_cxstat(xc_interface *xch, int cpuid);
 
 int xc_cpu_online(xc_interface *xch, int cpu);
 int xc_cpu_offline(xc_interface *xch, int cpu);
+int xc_smt_enable(xc_interface *xch);
+int xc_smt_disable(xc_interface *xch);
 
 /* 
  * cpufreq para name of this structure named 
diff --git a/tools/libxc/xc_cpu_hotplug.c b/tools/libxc/xc_cpu_hotplug.c
index 58c2a0f..2ea9825 100644
--- a/tools/libxc/xc_cpu_hotplug.c
+++ b/tools/libxc/xc_cpu_hotplug.c
@@ -46,3 +46,29 @@ int xc_cpu_offline(xc_interface *xch, int cpu)
     return ret;
 }
 
+int xc_smt_enable(xc_interface *xch)
+{
+    DECLARE_SYSCTL;
+    int ret;
+
+    sysctl.cmd = XEN_SYSCTL_cpu_hotplug;
+    sysctl.u.cpu_hotplug.cpu = 0;
+    sysctl.u.cpu_hotplug.op = XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE;
+    ret = xc_sysctl(xch, &sysctl);
+
+    return ret;
+}
+
+int xc_smt_disable(xc_interface *xch)
+{
+    DECLARE_SYSCTL;
+    int ret;
+
+    sysctl.cmd = XEN_SYSCTL_cpu_hotplug;
+    sysctl.u.cpu_hotplug.cpu = 0;
+    sysctl.u.cpu_hotplug.op = XEN_SYSCTL_CPU_HOTPLUG_SMT_DISABLE;
+    ret = xc_sysctl(xch, &sysctl);
+
+    return ret;
+}
+
diff --git a/tools/misc/xen-hptool.c b/tools/misc/xen-hptool.c
index 40cd966..6e27d9c 100644
--- a/tools/misc/xen-hptool.c
+++ b/tools/misc/xen-hptool.c
@@ -19,6 +19,8 @@ void show_help(void)
             "  mem-online    <mfn>      online MEMORY <mfn>\n"
             "  mem-offline   <mfn>      offline MEMORY <mfn>\n"
             "  mem-status    <mfn>      query Memory status<mfn>\n"
+            "  smt-enable               onlines all SMT threads\n"
+            "  smt-disable              offlines all SMT threads\n"
            );
 }
 
@@ -304,6 +306,58 @@ static int hp_cpu_offline_func(int argc, char *argv[])
     return ret;
 }
 
+static int main_smt_enable(int argc, char *argv[])
+{
+    int ret;
+
+    if ( argc )
+    {
+        show_help();
+        return -1;
+    }
+
+    for ( ;; )
+    {
+        ret = xc_smt_enable(xch);
+        if ( (ret >= 0) || (errno != EBUSY) )
+            break;
+    }
+
+    if ( ret < 0 )
+        fprintf(stderr, "Unable to enable SMT: errno %d, %s\n",
+                errno, strerror(errno));
+    else
+        printf("Enabled SMT\n");
+
+    return ret;
+}
+
+static int main_smt_disable(int argc, char *argv[])
+{
+    int ret;
+
+    if ( argc )
+    {
+        show_help();
+        return -1;
+    }
+
+    for ( ;; )
+    {
+        ret = xc_smt_disable(xch);
+        if ( (ret >= 0) || (errno != EBUSY) )
+            break;
+    }
+
+    if ( ret < 0 )
+        fprintf(stderr, "Unable to disable SMT: errno %d, %s\n",
+                errno, strerror(errno));
+    else
+        printf("Disabled SMT\n");
+
+    return ret;
+}
+
 struct {
     const char *name;
     int (*function)(int argc, char *argv[]);
@@ -314,6 +368,8 @@ struct {
     { "mem-status", hp_mem_query_func},
     { "mem-online", hp_mem_online_func},
     { "mem-offline", hp_mem_offline_func},
+    { "smt-enable", main_smt_enable },
+    { "smt-disable", main_smt_disable },
 };
 
 
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 3440794..af245eb 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -60,7 +60,7 @@ static bool __initdata opt_nosmp;
 boolean_param("nosmp", opt_nosmp);
 
 /* maxcpus: maximum number of CPUs to activate. */
-static unsigned int __initdata max_cpus;
+unsigned int max_cpus;
 integer_param("maxcpus", max_cpus);
 
 int8_t __read_mostly opt_smt = -1;
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index b3cc4b5..0e2e409 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -114,6 +114,92 @@ long cpu_down_helper(void *data)
     return ret;
 }
 
+static long smt_up_helper(void *data)
+{
+    unsigned int cpu, sibling_mask =
+        (1u << (boot_cpu_data.x86_num_siblings - 1)) - 1;
+    int ret = 0;
+
+    if ( !cpu_has_htt || !sibling_mask )
+        return -EOPNOTSUPP;
+
+    opt_smt = true;
+
+    for_each_present_cpu ( cpu )
+    {
+        if ( cpu == 0 )
+            continue;
+        if ( cpu >= max_cpus )
+            break;
+
+        if ( x86_cpu_to_apicid[cpu] & sibling_mask )
+            ret = cpu_up_helper(_p(cpu));
+
+        /* Tolerate already-online siblings. */
+        if ( ret == -EEXIST )
+            ret = 0;
+
+        if ( ret )
+            break;
+
+        if ( general_preempt_check() )
+        {
+            /* In tasklet context - can't create a contination. */
+            ret = -EBUSY;
+            break;
+        }
+    }
+
+    if ( !ret )
+        printk(XENLOG_INFO "SMT enabled - online CPUs {%*pbl}\n",
+               nr_cpu_ids, cpumask_bits(&cpu_online_map));
+
+    return ret;
+}
+
+static long smt_down_helper(void *data)
+{
+    unsigned int cpu, sibling_mask =
+        (1u << (boot_cpu_data.x86_num_siblings - 1)) - 1;
+    int ret = 0;
+
+    if ( !cpu_has_htt || !sibling_mask )
+        return -EOPNOTSUPP;
+
+    opt_smt = false;
+
+    for_each_present_cpu ( cpu )
+    {
+        if ( cpu == 0 )
+            continue;
+        if ( cpu >= max_cpus )
+            break;
+
+        if ( x86_cpu_to_apicid[cpu] & sibling_mask )
+            ret = cpu_down_helper(_p(cpu));
+
+        /* Tolerate already-offline siblings. */
+        if ( ret == -EEXIST )
+            ret = 0;
+
+        if ( ret )
+            break;
+
+        if ( general_preempt_check() )
+        {
+            /* In tasklet context - can't create a contination. */
+            ret = -EBUSY;
+            break;
+        }
+    }
+
+    if ( !ret )
+        printk(XENLOG_INFO "SMT disabled - online CPUs {%*pbl}\n",
+               nr_cpu_ids, cpumask_bits(&cpu_online_map));
+
+    return ret;
+}
+
 void arch_do_physinfo(struct xen_sysctl_physinfo *pi)
 {
     memcpy(pi->hw_cap, boot_cpu_data.x86_capability,
@@ -155,6 +241,16 @@ long arch_do_sysctl(
             hcpu = (void *)(unsigned long)cpu;
             break;
 
+        case XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE:
+            plug = true;
+            fn = smt_up_helper;
+            break;
+
+        case XEN_SYSCTL_CPU_HOTPLUG_SMT_DISABLE:
+            plug = false;
+            fn = smt_down_helper;
+            break;
+
         default:
             ret = -EOPNOTSUPP;
             break;
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index cef3ffb..8ffcffe 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -154,6 +154,7 @@ extern void (*ctxt_switch_masking)(const struct vcpu *next);
 extern bool_t opt_cpu_info;
 extern u32 cpuid_ext_features;
 extern u64 trampoline_misc_enable_off;
+extern unsigned int max_cpus;
 
 /* Maximum width of physical addresses supported by the hardware. */
 extern unsigned int paddr_bits;
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index c49b4dc..5c43aed 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -246,8 +246,17 @@ struct xen_sysctl_get_pmstat {
 struct xen_sysctl_cpu_hotplug {
     /* IN variables */
     uint32_t cpu;   /* Physical cpu. */
+
+    /* Single CPU enable/disable. */
 #define XEN_SYSCTL_CPU_HOTPLUG_ONLINE  0
 #define XEN_SYSCTL_CPU_HOTPLUG_OFFLINE 1
+
+    /*
+     * SMT enable/disable. Caller must zero the 'cpu' field to begin, and
+     * ignore it on completion.
+     */
+#define XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE  2
+#define XEN_SYSCTL_CPU_HOTPLUG_SMT_DISABLE 3
     uint32_t op;    /* hotplug opcode */
 };
 
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.