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)
This commit is contained in:
parent
8c54dbfb9b
commit
415d7ccab2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=282617
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -64,8 +64,96 @@ 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);
|
||||
}
|
||||
SYSINIT(parse_srat, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_srat, NULL);
|
||||
|
||||
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_acpi_tables, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_acpi_tables,
|
||||
NULL);
|
||||
|
||||
static void
|
||||
srat_walk_table(acpi_subtable_handler *handler, void *arg)
|
||||
|
Loading…
Reference in New Issue
Block a user