Skip to content

Commit a730659

Browse files
yhuang-intelakpm00
authored andcommitted
acpi, hmat: calculate abstract distance with HMAT
A memory tiering abstract distance calculation algorithm based on ACPI HMAT is implemented. The basic idea is as follows. The performance attributes of system default DRAM nodes are recorded as the base line. Whose abstract distance is MEMTIER_ADISTANCE_DRAM. Then, the ratio of the abstract distance of a memory node (target) to MEMTIER_ADISTANCE_DRAM is scaled based on the ratio of the performance attributes of the node to that of the default DRAM nodes. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: "Huang, Ying" <[email protected]> Cc: Aneesh Kumar K.V <[email protected]> Cc: Wei Xu <[email protected]> Cc: Alistair Popple <[email protected]> Cc: Dan Williams <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Jonathan Cameron <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Yang Shi <[email protected]> Cc: Rafael J Wysocki <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent ee9dcae commit a730659

File tree

3 files changed

+140
-2
lines changed

3 files changed

+140
-2
lines changed

drivers/acpi/numa/hmat.c

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/node.h>
2525
#include <linux/sysfs.h>
2626
#include <linux/dax.h>
27+
#include <linux/memory-tiers.h>
2728

2829
static u8 hmat_revision;
2930
static int hmat_disable __initdata;
@@ -759,6 +760,137 @@ static int hmat_callback(struct notifier_block *self,
759760
return NOTIFY_OK;
760761
}
761762

763+
static int hmat_adistance_disabled;
764+
static struct node_hmem_attrs default_dram_attrs;
765+
766+
static void dump_hmem_attrs(struct node_hmem_attrs *attrs)
767+
{
768+
pr_cont("read_latency: %u, write_latency: %u, read_bandwidth: %u, write_bandwidth: %u\n",
769+
attrs->read_latency, attrs->write_latency,
770+
attrs->read_bandwidth, attrs->write_bandwidth);
771+
}
772+
773+
static void disable_hmat_adistance_algorithm(void)
774+
{
775+
hmat_adistance_disabled = true;
776+
}
777+
778+
static int hmat_init_default_dram_attrs(void)
779+
{
780+
struct memory_target *target;
781+
struct node_hmem_attrs *attrs;
782+
int nid, pxm;
783+
int nid_dram = NUMA_NO_NODE;
784+
785+
if (default_dram_attrs.read_latency +
786+
default_dram_attrs.write_latency != 0)
787+
return 0;
788+
789+
if (!default_dram_type)
790+
return -EIO;
791+
792+
for_each_node_mask(nid, default_dram_type->nodes) {
793+
pxm = node_to_pxm(nid);
794+
target = find_mem_target(pxm);
795+
if (!target)
796+
continue;
797+
attrs = &target->hmem_attrs[1];
798+
if (nid_dram == NUMA_NO_NODE) {
799+
if (attrs->read_latency + attrs->write_latency == 0 ||
800+
attrs->read_bandwidth + attrs->write_bandwidth == 0) {
801+
pr_info("hmat: invalid hmem attrs for default DRAM node: %d,\n",
802+
nid);
803+
pr_info(" ");
804+
dump_hmem_attrs(attrs);
805+
pr_info(" disable hmat based abstract distance algorithm.\n");
806+
disable_hmat_adistance_algorithm();
807+
return -EIO;
808+
}
809+
nid_dram = nid;
810+
default_dram_attrs = *attrs;
811+
continue;
812+
}
813+
814+
/*
815+
* The performance of all default DRAM nodes is expected
816+
* to be same (that is, the variation is less than 10%).
817+
* And it will be used as base to calculate the abstract
818+
* distance of other memory nodes.
819+
*/
820+
if (abs(attrs->read_latency - default_dram_attrs.read_latency) * 10 >
821+
default_dram_attrs.read_latency ||
822+
abs(attrs->write_latency - default_dram_attrs.write_latency) * 10 >
823+
default_dram_attrs.write_latency ||
824+
abs(attrs->read_bandwidth - default_dram_attrs.read_bandwidth) * 10 >
825+
default_dram_attrs.read_bandwidth) {
826+
pr_info("hmat: hmem attrs for DRAM nodes mismatch.\n");
827+
pr_info(" node %d:", nid_dram);
828+
dump_hmem_attrs(&default_dram_attrs);
829+
pr_info(" node %d:", nid);
830+
dump_hmem_attrs(attrs);
831+
pr_info(" disable hmat based abstract distance algorithm.\n");
832+
disable_hmat_adistance_algorithm();
833+
return -EIO;
834+
}
835+
}
836+
837+
return 0;
838+
}
839+
840+
static int hmat_calculate_adistance(struct notifier_block *self,
841+
unsigned long nid, void *data)
842+
{
843+
static DECLARE_BITMAP(p_nodes, MAX_NUMNODES);
844+
struct memory_target *target;
845+
struct node_hmem_attrs *attrs;
846+
int *adist = data;
847+
int pxm;
848+
849+
if (hmat_adistance_disabled)
850+
return NOTIFY_OK;
851+
852+
pxm = node_to_pxm(nid);
853+
target = find_mem_target(pxm);
854+
if (!target)
855+
return NOTIFY_OK;
856+
857+
if (hmat_init_default_dram_attrs())
858+
return NOTIFY_OK;
859+
860+
mutex_lock(&target_lock);
861+
hmat_update_target_attrs(target, p_nodes, 1);
862+
mutex_unlock(&target_lock);
863+
864+
attrs = &target->hmem_attrs[1];
865+
866+
if (attrs->read_latency + attrs->write_latency == 0 ||
867+
attrs->read_bandwidth + attrs->write_bandwidth == 0)
868+
return NOTIFY_OK;
869+
870+
/*
871+
* The abstract distance of a memory node is in direct
872+
* proportion to its memory latency (read + write) and
873+
* inversely proportional to its memory bandwidth (read +
874+
* write). The abstract distance, memory latency, and memory
875+
* bandwidth of the default DRAM nodes are used as the base.
876+
*/
877+
*adist = MEMTIER_ADISTANCE_DRAM *
878+
(attrs->read_latency + attrs->write_latency) /
879+
(default_dram_attrs.read_latency +
880+
default_dram_attrs.write_latency) *
881+
(default_dram_attrs.read_bandwidth +
882+
default_dram_attrs.write_bandwidth) /
883+
(attrs->read_bandwidth + attrs->write_bandwidth);
884+
885+
return NOTIFY_STOP;
886+
}
887+
888+
static __meminitdata struct notifier_block hmat_adist_nb =
889+
{
890+
.notifier_call = hmat_calculate_adistance,
891+
.priority = 100,
892+
};
893+
762894
static __init void hmat_free_structures(void)
763895
{
764896
struct memory_target *target, *tnext;
@@ -801,6 +933,7 @@ static __init int hmat_init(void)
801933
struct acpi_table_header *tbl;
802934
enum acpi_hmat_type i;
803935
acpi_status status;
936+
int usage;
804937

805938
if (srat_disabled() || hmat_disable)
806939
return 0;
@@ -841,8 +974,11 @@ static __init int hmat_init(void)
841974
hmat_register_targets();
842975

843976
/* Keep the table and structures if the notifier may use them */
844-
if (!hotplug_memory_notifier(hmat_callback, HMAT_CALLBACK_PRI))
977+
usage = !hotplug_memory_notifier(hmat_callback, HMAT_CALLBACK_PRI);
978+
usage += !register_mt_adistance_algorithm(&hmat_adist_nb);
979+
if (usage)
845980
return 0;
981+
846982
out_put:
847983
hmat_free_structures();
848984
acpi_put_table(tbl);

include/linux/memory-tiers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct memory_dev_type {
3333

3434
#ifdef CONFIG_NUMA
3535
extern bool numa_demotion_enabled;
36+
extern struct memory_dev_type *default_dram_type;
3637
struct memory_dev_type *alloc_memory_type(int adistance);
3738
void put_memory_type(struct memory_dev_type *memtype);
3839
void init_node_memory_type(int node, struct memory_dev_type *default_type);
@@ -64,6 +65,7 @@ static inline bool node_is_toptier(int node)
6465
#else
6566

6667
#define numa_demotion_enabled false
68+
#define default_dram_type NULL
6769
/*
6870
* CONFIG_NUMA implementation returns non NULL error.
6971
*/

mm/memory-tiers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct node_memory_type_map {
3737
static DEFINE_MUTEX(memory_tier_lock);
3838
static LIST_HEAD(memory_tiers);
3939
static struct node_memory_type_map node_memory_types[MAX_NUMNODES];
40-
static struct memory_dev_type *default_dram_type;
40+
struct memory_dev_type *default_dram_type;
4141

4242
static struct bus_type memory_tier_subsys = {
4343
.name = "memory_tiering",

0 commit comments

Comments
 (0)