diff options
author | adrian <adrian@FreeBSD.org> | 2015-05-08 00:56:56 +0000 |
---|---|---|
committer | adrian <adrian@FreeBSD.org> | 2015-05-08 00:56:56 +0000 |
commit | 2cad336903136efb1928d24e584acc71e5ce5905 (patch) | |
tree | 3dff867c952f9c6dfb76911b755cda68bf3f67d0 | |
parent | 2a9a342fe4ad4a95e3cf3a60682ea2b4a954b8f6 (diff) | |
download | FreeBSD-src-2cad336903136efb1928d24e584acc71e5ce5905.zip FreeBSD-src-2cad336903136efb1928d24e584acc71e5ce5905.tar.gz |
Add initial memory locality cost awareness to the VM, and include
a basic ACPI SLIT table parser.
For now this just exports the map via sysctl; it'll eventually be useful
to userland when there's more useful NUMA support in -HEAD.
* Add an optional mem_locality map;
* add a mapping function taking from/to domain and returning the
relative cost, or -1 if it's not available;
* Add a very basic SLIT parser to x86 ACPI.
Differential Revision: https://reviews.freebsd.org/D2460
Reviewed by: rpaulo, stas, jhb
Sponsored by: Norse Corp, Inc (hardware, coding); Dell (hardware)
-rw-r--r-- | sys/vm/vm_phys.c | 47 | ||||
-rw-r--r-- | sys/vm/vm_phys.h | 1 | ||||
-rw-r--r-- | sys/x86/acpica/srat.c | 126 |
3 files changed, 168 insertions, 6 deletions
diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c index 5c33be4..71fadd7 100644 --- a/sys/vm/vm_phys.c +++ b/sys/vm/vm_phys.c @@ -71,6 +71,7 @@ _Static_assert(sizeof(long) * NBBY >= VM_PHYSSEG_MAX, "Too many physsegs."); struct mem_affinity *mem_affinity; +int *mem_locality; int vm_ndomains = 1; @@ -140,6 +141,10 @@ static int sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS); SYSCTL_OID(_vm, OID_AUTO, phys_segs, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, sysctl_vm_phys_segs, "A", "Phys Seg Info"); +static int sysctl_vm_phys_locality(SYSCTL_HANDLER_ARGS); +SYSCTL_OID(_vm, OID_AUTO, phys_locality, CTLTYPE_STRING | CTLFLAG_RD, + NULL, 0, sysctl_vm_phys_locality, "A", "Phys Locality Info"); + SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD, &vm_ndomains, 0, "Number of physical memory domains available."); @@ -297,6 +302,48 @@ sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS) return (error); } +/* + * Return affinity, or -1 if there's no affinity information. + */ +static int +vm_phys_mem_affinity(int f, int t) +{ + + if (mem_locality == NULL) + return (-1); + if (f >= vm_ndomains || t >= vm_ndomains) + return (-1); + return (mem_locality[f * vm_ndomains + t]); +} + +/* + * Outputs the VM locality table. + */ +static int +sysctl_vm_phys_locality(SYSCTL_HANDLER_ARGS) +{ + struct sbuf sbuf; + int error, i, j; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); + + sbuf_printf(&sbuf, "\n"); + + for (i = 0; i < vm_ndomains; i++) { + sbuf_printf(&sbuf, "%d: ", i); + for (j = 0; j < vm_ndomains; j++) { + sbuf_printf(&sbuf, "%d ", vm_phys_mem_affinity(i, j)); + } + sbuf_printf(&sbuf, "\n"); + } + error = sbuf_finish(&sbuf); + sbuf_delete(&sbuf); + return (error); +} + static void vm_freelist_add(struct vm_freelist *fl, vm_page_t m, int order, int tail) { diff --git a/sys/vm/vm_phys.h b/sys/vm/vm_phys.h index 8f3e847..153ef94 100644 --- a/sys/vm/vm_phys.h +++ b/sys/vm/vm_phys.h @@ -61,6 +61,7 @@ struct vm_phys_seg { }; extern struct mem_affinity *mem_affinity; +int *mem_locality; extern int vm_ndomains; extern struct vm_phys_seg vm_phys_segs[]; extern int vm_phys_nsegs; diff --git a/sys/x86/acpica/srat.c b/sys/x86/acpica/srat.c index 8d2a741..e908279 100644 --- a/sys/x86/acpica/srat.c +++ b/sys/x86/acpica/srat.c @@ -64,9 +64,97 @@ static vm_paddr_t srat_physaddr; static int vm_domains[VM_PHYSSEG_MAX]; +static ACPI_TABLE_SLIT *slit; +static vm_paddr_t slit_physaddr; +static int vm_locality_table[MAXMEMDOM * MAXMEMDOM]; + static void srat_walk_table(acpi_subtable_handler *handler, void *arg); /* + * SLIT parsing. + */ + +static void +slit_parse_table(ACPI_TABLE_SLIT *s) +{ + int i, j; + int i_domain, j_domain; + int offset = 0; + uint8_t e; + + /* + * This maps the SLIT data into the VM-domain centric view. + * There may be sparse entries in the PXM namespace, so + * remap them to a VM-domain ID and if it doesn't exist, + * skip it. + * + * It should result in a packed 2d array of VM-domain + * locality information entries. + */ + + if (bootverbose) + printf("SLIT.Localities: %d\n", (int) s->LocalityCount); + for (i = 0; i < s->LocalityCount; i++) { + i_domain = acpi_map_pxm_to_vm_domainid(i); + if (i_domain < 0) + continue; + + if (bootverbose) + printf("%d: ", i); + for (j = 0; j < s->LocalityCount; j++) { + j_domain = acpi_map_pxm_to_vm_domainid(j); + if (j_domain < 0) + continue; + e = s->Entry[i * s->LocalityCount + j]; + if (bootverbose) + printf("%d ", (int) e); + /* 255 == "no locality information" */ + if (e == 255) + vm_locality_table[offset] = -1; + else + vm_locality_table[offset] = e; + offset++; + } + if (bootverbose) + printf("\n"); + } +} + +/* + * Look for an ACPI System Locality Distance Information Table ("SLIT") + */ +static int +parse_slit(void) +{ + + if (resource_disabled("slit", 0)) { + return (-1); + } + + slit_physaddr = acpi_find_table(ACPI_SIG_SLIT); + if (slit_physaddr == 0) { + return (-1); + } + + /* + * Make a pass over the table to populate the cpus[] and + * mem_info[] tables. + */ + slit = acpi_map_table(slit_physaddr, ACPI_SIG_SLIT); + slit_parse_table(slit); + acpi_unmap_table(slit); + slit = NULL; + + /* Tell the VM about it! */ + mem_locality = vm_locality_table; + return (0); +} + +/* + * SRAT parsing. + */ + +/* * Returns true if a memory range overlaps with at least one range in * phys_avail[]. */ @@ -301,17 +389,17 @@ renumber_domains(void) /* * Look for an ACPI System Resource Affinity Table ("SRAT") */ -static void -parse_srat(void *dummy) +static int +parse_srat(void) { int error; if (resource_disabled("srat", 0)) - return; + return (-1); srat_physaddr = acpi_find_table(ACPI_SIG_SRAT); if (srat_physaddr == 0) - return; + return (-1); /* * Make a pass over the table to populate the cpus[] and @@ -325,13 +413,39 @@ parse_srat(void *dummy) if (error || check_domains() != 0 || check_phys_avail() != 0 || renumber_domains() != 0) { srat_physaddr = 0; - return; + return (-1); } /* Point vm_phys at our memory affinity table. */ mem_affinity = mem_info; + + return (0); +} + +static void +init_mem_locality(void) +{ + int i; + + /* + * For now, assume 255 == "no locality information for + * this pairing. + */ + for (i = 0; i < MAXMEMDOM * MAXMEMDOM; i++) + vm_locality_table[i] = -1; +} + +static void +parse_acpi_tables(void *dummy) +{ + + if (parse_srat() < 0) + return; + init_mem_locality(); + (void) parse_slit(); } -SYSINIT(parse_srat, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_srat, NULL); +SYSINIT(parse_acpi_tables, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_acpi_tables, + NULL); static void srat_walk_table(acpi_subtable_handler *handler, void *arg) |