Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 8 May 2015 00:56:57 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r282617 - in head/sys: vm x86/acpica
Message-ID:  <201505080056.t480uvP4091712@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Fri May  8 00:56:56 2015
New Revision: 282617
URL: https://svnweb.freebsd.org/changeset/base/282617

Log:
  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)

Modified:
  head/sys/vm/vm_phys.c
  head/sys/vm/vm_phys.h
  head/sys/x86/acpica/srat.c

Modified: head/sys/vm/vm_phys.c
==============================================================================
--- head/sys/vm/vm_phys.c	Thu May  7 23:49:48 2015	(r282616)
+++ head/sys/vm/vm_phys.c	Fri May  8 00:56:56 2015	(r282617)
@@ -71,6 +71,7 @@ _Static_assert(sizeof(long) * NBBY >= VM
     "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_HA
 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)
 {

Modified: head/sys/vm/vm_phys.h
==============================================================================
--- head/sys/vm/vm_phys.h	Thu May  7 23:49:48 2015	(r282616)
+++ head/sys/vm/vm_phys.h	Fri May  8 00:56:56 2015	(r282617)
@@ -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;

Modified: head/sys/x86/acpica/srat.c
==============================================================================
--- head/sys/x86/acpica/srat.c	Thu May  7 23:49:48 2015	(r282616)
+++ head/sys/x86/acpica/srat.c	Fri May  8 00:56:56 2015	(r282617)
@@ -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)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505080056.t480uvP4091712>