Re: RFC: Memory Tiering Kernel Interfaces (v2)

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

 



On Wed, May 25, 2022 at 11:55 PM Ying Huang <ying.huang@xxxxxxxxx> wrote:
>
> On Wed, 2022-05-25 at 20:53 -0700, Wei Xu wrote:
> > On Wed, May 25, 2022 at 6:10 PM Ying Huang <ying.huang@xxxxxxxxx> wrote:
> > >
> > > On Wed, 2022-05-25 at 08:36 -0700, Wei Xu wrote:
> > > > On Wed, May 25, 2022 at 2:03 AM Ying Huang <ying.huang@xxxxxxxxx> wrote:
> > > > >
> > > > > On Tue, 2022-05-24 at 22:32 -0700, Wei Xu wrote:
> > > > > > On Tue, May 24, 2022 at 1:24 AM Ying Huang <ying.huang@xxxxxxxxx> wrote:
> > > > > > >
> > > > > > > On Tue, 2022-05-24 at 00:04 -0700, Wei Xu wrote:
> > > > > > > > On Thu, May 19, 2022 at 8:06 PM Ying Huang <ying.huang@xxxxxxxxx> wrote:
> > > > > > > > >
> > > > > > > > > On Wed, 2022-05-18 at 00:09 -0700, Wei Xu wrote:
> > > > > > > > > > On Thu, May 12, 2022 at 8:00 AM Jonathan Cameron
> > > > > > > > > > <Jonathan.Cameron@xxxxxxxxxx> wrote:
> > > > > > > > > > >
> > > > > > > > > > > On Wed, 11 May 2022 23:22:11 -0700
> > > > > > > > > > > Wei Xu <weixugc@xxxxxxxxxx> wrote:
> > > > > > > > > > > > The current kernel has the basic memory tiering support: Inactive
> > > > > > > > > > > > pages on a higher tier NUMA node can be migrated (demoted) to a lower
> > > > > > > > > > > > tier NUMA node to make room for new allocations on the higher tier
> > > > > > > > > > > > NUMA node.  Frequently accessed pages on a lower tier NUMA node can be
> > > > > > > > > > > > migrated (promoted) to a higher tier NUMA node to improve the
> > > > > > > > > > > > performance.
> > > > > > > > > > > >
> > > > > > > > > > > > In the current kernel, memory tiers are defined implicitly via a
> > > > > > > > > > > > demotion path relationship between NUMA nodes, which is created during
> > > > > > > > > > > > the kernel initialization and updated when a NUMA node is hot-added or
> > > > > > > > > > > > hot-removed.  The current implementation puts all nodes with CPU into
> > > > > > > > > > > > the top tier, and builds the tier hierarchy tier-by-tier by establishing
> > > > > > > > > > > > the per-node demotion targets based on the distances between nodes.
> > > > > > > > > > > >
> > > > > > > > > > > > This current memory tier kernel interface needs to be improved for
> > > > > > > > > > > > several important use cases:
> > > > > > > > > > > >
> > > > > > > > > > > > * The current tier initialization code always initializes
> > > > > > > > > > > >   each memory-only NUMA node into a lower tier.  But a memory-only
> > > > > > > > > > > >   NUMA node may have a high performance memory device (e.g. a DRAM
> > > > > > > > > > > >   device attached via CXL.mem or a DRAM-backed memory-only node on
> > > > > > > > > > > >   a virtual machine) and should be put into a higher tier.
> > > > > > > > > > > >
> > > > > > > > > > > > * The current tier hierarchy always puts CPU nodes into the top
> > > > > > > > > > > >   tier. But on a system with HBM (e.g. GPU memory) devices, these
> > > > > > > > > > > >   memory-only HBM NUMA nodes should be in the top tier, and DRAM nodes
> > > > > > > > > > > >   with CPUs are better to be placed into the next lower tier.
> > > > > > > > > > > >
> > > > > > > > > > > > * Also because the current tier hierarchy always puts CPU nodes
> > > > > > > > > > > >   into the top tier, when a CPU is hot-added (or hot-removed) and
> > > > > > > > > > > >   triggers a memory node from CPU-less into a CPU node (or vice
> > > > > > > > > > > >   versa), the memory tier hierarchy gets changed, even though no
> > > > > > > > > > > >   memory node is added or removed.  This can make the tier
> > > > > > > > > > > >   hierarchy unstable and make it difficult to support tier-based
> > > > > > > > > > > >   memory accounting.
> > > > > > > > > > > >
> > > > > > > > > > > > * A higher tier node can only be demoted to selected nodes on the
> > > > > > > > > > > >   next lower tier as defined by the demotion path, not any other
> > > > > > > > > > > >   node from any lower tier.  This strict, hard-coded demotion order
> > > > > > > > > > > >   does not work in all use cases (e.g. some use cases may want to
> > > > > > > > > > > >   allow cross-socket demotion to another node in the same demotion
> > > > > > > > > > > >   tier as a fallback when the preferred demotion node is out of
> > > > > > > > > > > >   space), and has resulted in the feature request for an interface to
> > > > > > > > > > > >   override the system-wide, per-node demotion order from the
> > > > > > > > > > > >   userspace.  This demotion order is also inconsistent with the page
> > > > > > > > > > > >   allocation fallback order when all the nodes in a higher tier are
> > > > > > > > > > > >   out of space: The page allocation can fall back to any node from
> > > > > > > > > > > >   any lower tier, whereas the demotion order doesn't allow that.
> > > > > > > > > > > >
> > > > > > > > > > > > * There are no interfaces for the userspace to learn about the memory
> > > > > > > > > > > >   tier hierarchy in order to optimize its memory allocations.
> > > > > > > > > > > >
> > > > > > > > > > > > I'd like to propose revised memory tier kernel interfaces based on
> > > > > > > > > > > > the discussions in the threads:
> > > > > > > > > > > >
> > > > > > > > > > > > - https://lore.kernel.org/lkml/20220425201728.5kzm4seu7rep7ndr@offworld/T/
> > > > > > > > > > > > - https://lore.kernel.org/linux-mm/20220426114300.00003ad8@xxxxxxxxxx/t/
> > > > > > > > > > > > - https://lore.kernel.org/linux-mm/867bc216386eb6cbf54648f23e5825830f5b922e.camel@xxxxxxxxx/T/
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > High-level Design Ideas
> > > > > > > > > > > > =======================
> > > > > > > > > > > >
> > > > > > > > > > > > * Define memory tiers explicitly, not implicitly.
> > > > > > > > > > > >
> > > > > > > > > > > > * Memory tiers are defined based on hardware capabilities of memory
> > > > > > > > > > > >   nodes, not their relative node distances between each other.
> > > > > > > > > > > >
> > > > > > > > > > > > * The tier assignment of each node is independent from each other.
> > > > > > > > > > > >   Moving a node from one tier to another tier doesn't affect the tier
> > > > > > > > > > > >   assignment of any other node.
> > > > > > > > > > > >
> > > > > > > > > > > > * The node-tier association is stable. A node can be reassigned to a
> > > > > > > > > > > >   different tier only under the specific conditions that don't block
> > > > > > > > > > > >   future tier-based memory cgroup accounting.
> > > > > > > > > > > >
> > > > > > > > > > > > * A node can demote its pages to any nodes of any lower tiers. The
> > > > > > > > > > > >   demotion target node selection follows the allocation fallback order
> > > > > > > > > > > >   of the source node, which is built based on node distances.  The
> > > > > > > > > > > >   demotion targets are also restricted to only the nodes from the tiers
> > > > > > > > > > > >   lower than the source node.  We no longer need to maintain a separate
> > > > > > > > > > > >   per-node demotion order (node_demotion[]).
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > Hi Wei,
> > > > > > > > > > >
> > > > > > > > > > > This proposal looks good to me, though we'll be having fun
> > > > > > > > > > > white boarding topologies from our roadmaps for the next few days :)
> > > > > > > > > >
> > > > > > > > > > That's good to hear.
> > > > > > > > > >
> > > > > > > > > > > A few comments inline. It also seems likely to me that there is little
> > > > > > > > > > > benefit in starting with 3 tiers as the maximum.  Seems unlikely the
> > > > > > > > > > > code will be substantially simpler for 3 than it would be for 4 or 5.
> > > > > > > > > > > I've drawn out one simple case that needs 4 to do sensible things.
> > > > > > > > > >
> > > > > > > > > > We can make the number of tiers a config option. 3 tiers are just what
> > > > > > > > > > the kernel can reasonably initialize when there isn't enough hardware
> > > > > > > > > > performance information from the firmware.
> > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Sysfs Interfaces
> > > > > > > > > > > > ================
> > > > > > > > > > > >
> > > > > > > > > > > > * /sys/devices/system/memtier/memtierN/nodelist
> > > > > > > > > > > >
> > > > > > > > > > > >   where N = 0, 1, 2 (the kernel supports only 3 tiers for now).
> > > > > > > > > > > >
> > > > > > > > > > > >   Format: node_list
> > > > > > > > > > > >
> > > > > > > > > > > >   Read-only.  When read, list the memory nodes in the specified tier.
> > > > > > > > > > > >
> > > > > > > > > > > >   Tier 0 is the highest tier, while tier 2 is the lowest tier.
> > > > > > > > > > > >
> > > > > > > > > > > >   The absolute value of a tier id number has no specific meaning.
> > > > > > > > > > > >   What matters is the relative order of the tier id numbers.
> > > > > > > > > > > >
> > > > > > > > > > > >   When a memory tier has no nodes, the kernel can hide its memtier
> > > > > > > > > > > >   sysfs files.
> > > > > > > > > > > >
> > > > > > > > > > > > * /sys/devices/system/node/nodeN/memtier
> > > > > > > > > > > >
> > > > > > > > > > > >   where N = 0, 1, ...
> > > > > > > > > > > >
> > > > > > > > > > > >   Format: int or empty
> > > > > > > > > > > >
> > > > > > > > > > > >   When read, list the memory tier that the node belongs to.  Its value
> > > > > > > > > > > >   is empty for a CPU-only NUMA node.
> > > > > > > > > > > >
> > > > > > > > > > > >   When written, the kernel moves the node into the specified memory
> > > > > > > > > > > >   tier if the move is allowed.  The tier assignment of all other nodes
> > > > > > > > > > > >   are not affected.
> > > > > > > > > > > >
> > > > > > > > > > > >   Initially, we can make this interface read-only.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Kernel Representation
> > > > > > > > > > > > =====================
> > > > > > > > > > > >
> > > > > > > > > > > > * All memory tiering code is guarded by CONFIG_TIERED_MEMORY.
> > > > > > > > > > > >
> > > > > > > > > > > > * #define MAX_MEMORY_TIERS 3
> > > > > > > > > > > >
> > > > > > > > > > > >   Support 3 memory tiers for now.
> > > > > > > > > > > >
> > > > > > > > > > > > * #define MEMORY_DEFAULT_TIER 1
> > > > > > > > > > > >
> > > > > > > > > > > >   The default tier that a memory node is assigned to.
> > > > > > > > > > > >
> > > > > > > > > > > > * nodemask_t memory_tiers[MAX_MEMORY_TIERS]
> > > > > > > > > > > >
> > > > > > > > > > > >   Store memory nodes by tiers.
> > > > > > > > > > > >
> > > > > > > > > > > > * int node_tier_map[MAX_NUMNODES]
> > > > > > > > > > > >
> > > > > > > > > > > >   Map a node to its tier.
> > > > > > > > > > > >
> > > > > > > > > > > >   For each CPU-only node c, node_tier_map[c] = -1.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Memory Tier Initialization
> > > > > > > > > > > > ==========================
> > > > > > > > > > > >
> > > > > > > > > > > > By default, all memory nodes are assigned to the default tier
> > > > > > > > > > > > (MEMORY_DEFAULT_TIER).
> > > > > > > > > > >
> > > > > > > > > > > This is tighter than it needs to be.  In many cases we can easily
> > > > > > > > > > > establish if there is any possibility of CPU being hotplugged into
> > > > > > > > > > > a memory node.  If it's CXL attached no way CPUs are going to be
> > > > > > > > > > > turning up their later :)  If CPU HP into a given node can't happen
> > > > > > > > > > > we can be more flexible and I think that often results in better decisions.
> > > > > > > > > > > See example below, though obviously I could just use the userspace
> > > > > > > > > > > interface to fix that up anyway or have a CXL driver move it around
> > > > > > > > > > > if that's relevant.  In some other cases I'm fairly sure we know in
> > > > > > > > > > > advance where CPUs can be added but I'd need to check all the
> > > > > > > > > > > relevant specs to be sure there aren't any corner cases.  I 'think'
> > > > > > > > > > > for ARM for example we know where all possible CPUs can be hotplugged
> > > > > > > > > > > (constraint coming from the interrupt controller + the fact that only
> > > > > > > > > > > virtual CPU HP is defined).
> > > > > > > > > >
> > > > > > > > > > We may not always want to put a CXL-attached memory device into a
> > > > > > > > > > slower tier because even though CXL does add some additional latency,
> > > > > > > > > > both the memory device and CXL can still be very capable in
> > > > > > > > > > performance and may not be much slower (if any) than the on-board DRAM
> > > > > > > > > > (e.g. DRAM from a remote CPU socket).
> > > > > > > > > >
> > > > > > > > > > Also, the default tier here is just the initial tier assignment of
> > > > > > > > > > each node, which behaves as if there were no tiering.  A tiering
> > > > > > > > > > kernel init function can certainly reassign the tier for each node if
> > > > > > > > > > it knows enough about the hardware performance for these nodes from
> > > > > > > > > > the firmware.
> > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > A device driver can move up or down its memory nodes from the default
> > > > > > > > > > > > tier.  For example, PMEM can move down its memory nodes below the
> > > > > > > > > > > > default tier, whereas GPU can move up its memory nodes above the
> > > > > > > > > > > > default tier.
> > > > > > > > > > > >
> > > > > > > > > > > > The kernel initialization code makes the decision on which exact tier
> > > > > > > > > > > > a memory node should be assigned to based on the requests from the
> > > > > > > > > > > > device drivers as well as the memory device hardware information
> > > > > > > > > > > > provided by the firmware.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Memory Tier Reassignment
> > > > > > > > > > > > ========================
> > > > > > > > > > > >
> > > > > > > > > > > > After a memory node is hot-removed, it can be hot-added back to a
> > > > > > > > > > > > different memory tier.  This is useful for supporting dynamically
> > > > > > > > > > > > provisioned CXL.mem NUMA nodes, which may connect to different
> > > > > > > > > > > > memory devices across hot-plug events.  Such tier changes should
> > > > > > > > > > > > be compatible with tier-based memory accounting.
> > > > > > > > > > > >
> > > > > > > > > > > > The userspace may also reassign an existing online memory node to a
> > > > > > > > > > > > different tier.  However, this should only be allowed when no pages
> > > > > > > > > > > > are allocated from the memory node or when there are no non-root
> > > > > > > > > > > > memory cgroups (e.g. during the system boot).  This restriction is
> > > > > > > > > > > > important for keeping memory tier hierarchy stable enough for
> > > > > > > > > > > > tier-based memory cgroup accounting.
> > > > > > > > > > > >
> > > > > > > > > > > > Hot-adding/removing CPUs doesn't affect memory tier hierarchy.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Memory Allocation for Demotion
> > > > > > > > > > > > ==============================
> > > > > > > > > > > >
> > > > > > > > > > > > To allocate a new page as the demotion target for a page, the kernel
> > > > > > > > > > > > calls the allocation function (__alloc_pages_nodemask) with the
> > > > > > > > > > > > source page node as the preferred node and the union of all lower
> > > > > > > > > > > > tier nodes as the allowed nodemask.  The actual target node selection
> > > > > > > > > > > > then follows the allocation fallback order that the kernel has
> > > > > > > > > > > > already defined.
> > > > > > > > > > > >
> > > > > > > > > > > > The pseudo code looks like:
> > > > > > > > > > > >
> > > > > > > > > > > >     targets = NODE_MASK_NONE;
> > > > > > > > > > > >     src_nid = page_to_nid(page);
> > > > > > > > > > > >     src_tier = node_tier_map[src_nid];
> > > > > > > > > > > >     for (i = src_tier + 1; i < MAX_MEMORY_TIERS; i++)
> > > > > > > > > > > >             nodes_or(targets, targets, memory_tiers[i]);
> > > > > > > > > > > >     new_page = __alloc_pages_nodemask(gfp, order, src_nid, targets);
> > > > > > > > > > > >
> > > > > > > > > > > > The memopolicy of cpuset, vma and owner task of the source page can
> > > > > > > > > > > > be set to refine the demotion target nodemask, e.g. to prevent
> > > > > > > > > > > > demotion or select a particular allowed node as the demotion target.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Memory Allocation for Promotion
> > > > > > > > > > > > ===============================
> > > > > > > > > > > >
> > > > > > > > > > > > The page allocation for promotion is similar to demotion, except that (1)
> > > > > > > > > > > > the target nodemask uses the promotion tiers, (2) the preferred node can
> > > > > > > > > > > > be the accessing CPU node, not the source page node.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Examples
> > > > > > > > > > > > ========
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > ...
> > > > > > > > > > >
> > > > > > > > > > > > * Example 3:
> > > > > > > > > > > >
> > > > > > > > > > > > Node 0 & 1 are DRAM nodes, Node 2 is a memory-only DRAM node.
> > > > > > > > > > >
> > > > > > > > > > > Node2 is drawn as pmem.
> > > > > > > > > >
> > > > > > > > > > Typo. Good catch.
> > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > All nodes are in the same tier.
> > > > > > > > > > > >
> > > > > > > > > > > >                   20
> > > > > > > > > > > >   Node 0 (DRAM)  ----  Node 1 (DRAM)
> > > > > > > > > > > >          \                 /
> > > > > > > > > > > >           \ 30            / 30
> > > > > > > > > > > >            \             /
> > > > > > > > > > > >              Node 2 (PMEM)
> > > > > > > > > > > >
> > > > > > > > > > > > node distances:
> > > > > > > > > > > > node   0    1    2
> > > > > > > > > > > >    0  10   20   30
> > > > > > > > > > > >    1  20   10   30
> > > > > > > > > > > >    2  30   30   10
> > > > > > > > > > > >
> > > > > > > > > > > > $ cat /sys/devices/system/memtier/memtier*/nodelist
> > > > > > > > > > > > <empty>
> > > > > > > > > > > > 0-2
> > > > > > > > > > > > <empty>
> > > > > > > > > > > >
> > > > > > > > > > > > $ cat /sys/devices/system/node/node*/memtier
> > > > > > > > > > > > 1
> > > > > > > > > > > > 1
> > > > > > > > > > > > 1
> > > > > > > > > > > >
> > > > > > > > > > > > Demotion fallback order:
> > > > > > > > > > > > node 0: empty
> > > > > > > > > > > > node 1: empty
> > > > > > > > > > > > node 2: empty
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > * Example 4:
> > > > > > > > > > > >
> > > > > > > > > > > > Node 0 is a DRAM node with CPU.
> > > > > > > > > > > > Node 1 is a PMEM node.
> > > > > > > > > > > > Node 2 is a GPU node.
> > > > > > > > > > > >
> > > > > > > > > > > >                   50
> > > > > > > > > > > >   Node 0 (DRAM)  ----  Node 2 (GPU)
> > > > > > > > > > > >          \                 /
> > > > > > > > > > > >           \ 30            / 60
> > > > > > > > > > > >            \             /
> > > > > > > > > > > >              Node 1 (PMEM)
> > > > > > > > > > > >
> > > > > > > > > > > > node distances:
> > > > > > > > > > > > node   0    1    2
> > > > > > > > > > > >    0  10   30   50
> > > > > > > > > > > >    1  30   10   60
> > > > > > > > > > > >    2  50   60   10
> > > > > > > > > > > >
> > > > > > > > > > > > $ cat /sys/devices/system/memtier/memtier*/nodelist
> > > > > > > > > > > > 2
> > > > > > > > > > > > 0
> > > > > > > > > > > > 1
> > > > > > > > > > > >
> > > > > > > > > > > > $ cat /sys/devices/system/node/node*/memtier
> > > > > > > > > > > > 1
> > > > > > > > > > > > 2
> > > > > > > > > > > > 0
> > > > > > > > > > > >
> > > > > > > > > > > > Demotion fallback order:
> > > > > > > > > > > > node 0: 1
> > > > > > > > > > > > node 1: empty
> > > > > > > > > > > > node 2: 0, 1
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > * Example 5:
> > > > > > > > > > > >
> > > > > > > > > > > > Node 0 is a DRAM node with CPU.
> > > > > > > > > > > > Node 1 is a GPU node.
> > > > > > > > > > > > Node 2 is a PMEM node.
> > > > > > > > > > > > Node 3 is a large, slow DRAM node without CPU.
> > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > >      Node 2 (PMEM)  ----
> > > > > > > > > > > >    /      |              \
> > > > > > > > > > > >   /       | 30            \ 120
> > > > > > > > > > > >  |        |         100    \
> > > > > > > > > > > >  |   Node 0 (DRAM)  ----  Node 1 (GPU)
> > > > > > > > > > > >   \         \                 /
> > > > > > > > > > > >     \        \ 40            / 110
> > > > > > > > > > > >   80  \       \             /
> > > > > > > > > > > >         ---  Node 3 (Slow DRAM)
> > > > > > > > > > >
> > > > > > > > > > > This is close but not quite what was intended for Hesham's
> > > > > > > > > > > example... (note we just checked that Hesham's original node0-1
> > > > > > > > > > > timing didn't make any sense.).
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > This was inspired by Hesham's example. But I should have also included
> > > > > > > > > > the version that illustrates the need to skip a tier when demoting
> > > > > > > > > > from certain nodes.
> > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > node distances:
> > > > > > > > > > > > node    0    1    2    3
> > > > > > > > > > > >    0   10  100   30   40
> > > > > > > > > > > >    1  100   10  120  110
> > > > > > > > > > > >    2   30  120   10   80
> > > > > > > > > > > >    3   40  110   80   10
> > > > > > > > > > > >
> > > > > > > > > > > > $ cat /sys/devices/system/memtier/memtier*/nodelist
> > > > > > > > > > > > 1
> > > > > > > > > > > > 0,3
> > > > > > > > > > > > 2
> > > > > > > > > > > >
> > > > > > > > > > > > $ cat /sys/devices/system/node/node*/memtier
> > > > > > > > > > > > 1
> > > > > > > > > > > > 0
> > > > > > > > > > > > 2
> > > > > > > > > > > > 1
> > > > > > > > > > > >
> > > > > > > > > > > > Demotion fallback order:
> > > > > > > > > > > > node 0: 2
> > > > > > > > > > > > node 1: 0, 3, 2
> > > > > > > > > > > > node 2: empty
> > > > > > > > > > > > node 3: 2
> > > > > > > > > > >
> > > > > > > > > > > This is close but not quite the same as the example
> > > > > > > > > > > Hesham gave (note the node timing 1 to 0 on in the table
> > > > > > > > > > > with that example didn't make sense).  I added another
> > > > > > > > > > > level of switching to make the numbers more obviously
> > > > > > > > > > > different and show how critical it might be.
> > > > > > > > > > >
> > > > > > > > > > > * Example 6:
> > > > > > > > > > >
> > > > > > > > > > > Node 0 is a DRAM node with CPU.
> > > > > > > > > > > Node 1 is a GPU node.
> > > > > > > > > > > Node 2 is a PMEM node.
> > > > > > > > > > > Node 3 is an extremely large, DRAM node without CPU.
> > > > > > > > > > >   (Key point here being that it probably never makes sense
> > > > > > > > > > >    to demote to anywhere else from this memory).
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > I've redone the timings wrt to example 5.
> > > > > > > > > > > Basis for this is 0 and 2 are directly connected
> > > > > > > > > > > via controllers in an SoC. 1 and 3 are connected
> > > > > > > > > > > via a a common switch one switch down switch
> > > > > > > > > > > (each hop via this is 100)
> > > > > > > > > > > All drams cost 10 once you've reached correct node
> > > > > > > > > > > and pmem costs 30 from SoC.
> > > > > > > > > > > Numbers get too large as a result but meh, I'm making
> > > > > > > > > > > a point not providing real numbers :)
> > > > > > > > > > >
> > > > > > > > > > >          PMEM Node 2
> > > > > > > > > > >             |(30)
> > > > > > > > > > >         CPU + DRAM Node0
> > > > > > > > > > >             |(100)
> > > > > > > > > > >          Switch 1
> > > > > > > > > > >             |(100)
> > > > > > > > > > >           Switch 2
> > > > > > > > > > >     (100)  |      |(100)
> > > > > > > > > > > Node 1 GPU     Node3 Large memory.
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > With one level of s
> > > > > > > > > > >
> > > > > > > > > > >      Node 2 (PMEM)  ----
> > > > > > > > > > >     /      |              \
> > > > > > > > > > >    /       | 30            \ 330
> > > > > > > > > > >   |        |         310    \
> > > > > > > > > > >   |   Node 0 (DRAM)  ----  Node 1 (GPU)
> > > > > > > > > > >    \         \                 /
> > > > > > > > > > >      \        \ 310           / 210
> > > > > > > > > > >    330 \       \             /
> > > > > > > > > > >          ---  Node 3 (Extremely large DRAM)
> > > > > > > > > > >
> > > > > > > > > > > To my mind, we should potentially also take into account
> > > > > > > > > > > the fact that Node3 can be known to never contain CPUs
> > > > > > > > > > > (in at least some architectures we know where the CPUs
> > > > > > > > > > >  might be added later, they can't just magically turn up
> > > > > > > > > > >  anywhere in the topology).
> > > > > > > > > > >
> > > > > > > > > > > node distances:
> > > > > > > > > > > node    0    1    2    3
> > > > > > > > > > >     0   10   310  30   310
> > > > > > > > > > >     1   310  10   330  210
> > > > > > > > > > >     2   30   330  10   330
> > > > > > > > > > >     3   310  210  330   10
> > > > > > > > > > >
> > > > > > > > > > > So, my ideal would treat node 3 different from other dram nodes
> > > > > > > > > > > as we know it can't have CPUs. Trying to come up with an
> > > > > > > > > > > always correct order for nodes 3 and 2 is tricky as to a certain
> > > > > > > > > > > extent depends on capacity. If node 2 was  big enough to take
> > > > > > > > > > > any demotion from node 0 and still have lots of room then demoting
> > > > > > > > > > > there form node 3 would make sense and visa versa.
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > >  $ cat /sys/devices/system/memtier/memtier*/nodelist
> > > > > > > > > > >  1
> > > > > > > > > > >  0
> > > > > > > > > > >  2
> > > > > > > > > > >  3
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > >  $ cat /sys/devices/system/node/node*/memtier
> > > > > > > > > > >   1
> > > > > > > > > > >   0
> > > > > > > > > > >   2
> > > > > > > > > > >   3
> > > > > > > > > > >
> > > > > > > > > > >  Demotion fallback order:
> > > > > > > > > > >  node 0: 2, 3
> > > > > > > > > > >  node 1: 3, 0, 2 (key being we will almost always have less pressure on node 3)
> > > > > > > > > > >  node 2: 3
> > > > > > > > > > >  node 3: empty
> > > > > > > > > > >
> > > > > > > > > > > or as Hesham just pointed out this can be done with 3 tiers
> > > > > > > > > > > because we can put the GPU and CPU in the same tier because
> > > > > > > > > > > their is little reason to demote from one to the other.
> > > > > > > > > >
> > > > > > > > > > Thank you for the example.  It makes sense to me to have node 3 on its
> > > > > > > > > > own tier.  We can have either 3 tiers or 4 tiers in total (assuming
> > > > > > > > > > that the max number of tiers is a config option).
> > > > > > > > > >
> > > > > > > > > > > We are also a bit worried about ABI backwards compatibility because
> > > > > > > > > > > of potential need to make more space in tiers lower in number than
> > > > > > > > > > > CPU attached DDR. I rather liked the negative proposal with
> > > > > > > > > > > default as 0 that Huang, Ying made.
> > > > > > > > > >
> > > > > > > > > > It is hard to have negative values as the device IDs.
> > > > > > > > > >
> > > > > > > > > > The current proposal equals the tier device ID to the tier hierarchy
> > > > > > > > > > level, which makes the interface simpler, but less flexible.  How
> > > > > > > > > > about the following proposal (which decouples the tier device ID from
> > > > > > > > > > the tier level)?
> > > > > > > > > >
> > > > > > > > > > /sys/devices/system/memtier/memtierN/nodelist
> > > > > > > > > > /sys/devices/system/memtier/memtierN/rank
> > > > > > > > > >
> > > > > > > > > > Each memory tier N has two sysfs files:
> > > > > > > > > > - nodelist: the nodes that are in this tier
> > > > > > > > > > - rank: an opaque value that helps decide the level at which this tier
> > > > > > > > > > is in the tier hierarchy (smaller value means faster tier)
> > > > > > > > > >
> > > > > > > > > > The tier hierarchy is determined by "rank", not by the device id
> > > > > > > > > > number N from "memtierN".
> > > > > > > > > >
> > > > > > > > > > The absolute value of "rank" of a memtier doesn't necessarily carry
> > > > > > > > > > any meaning. Its value relative to other memtiers decides the level of
> > > > > > > > > > this memtier in the tier hierarchy.
> > > > > > > > > >
> > > > > > > > > > The CPU-attached DRAM nodes are always in memtier0 (the device ID),
> > > > > > > > > > but memtier0 may not always be the top-tier, e.g. its level can be 3
> > > > > > > > > > in a 5-tier system.
> > > > > > > > > >
> > > > > > > > > > For the above example (example 6), we can have:
> > > > > > > > > >
> > > > > > > > > > $ ls /sys/devices/system/memtier
> > > > > > > > > > memtier0
> > > > > > > > > > memtier1
> > > > > > > > > > memtier2
> > > > > > > > > > memtier128
> > > > > > > > > >
> > > > > > > > > > $ cat /sys/devices/system/memtier/memtier*/rank
> > > > > > > > > > 50
> > > > > > > > > > 60
> > > > > > > > > > 70
> > > > > > > > > > 10
> > > > > > > > >
> > > > > > > > > I understand that the device ID cannot be negtive.  So we have to use
> > > > > > > > > rank.  Can we make it possible to allow "rank" to be negtive?
> > > > > > > >
> > > > > > > > It is possible to allow "rank" to be negative, though I think all
> > > > > > > > positive values should work equally well.
> > > > > > > >
> > > > > > > > > Another choice is to do some trick on device ID.  For example, the CPU-
> > > > > > > > > attached DRAM node are always memtier100 (the device ID).  Then we can
> > > > > > > > > have memtier99, memtier100, memtier101, memteri102, ....  That's not
> > > > > > > > > perfect too.
> > > > > > > >
> > > > > > > > If we go with the device ID tricks, one approach is to use sub-device IDs:
> > > > > > > >
> > > > > > > > - There are 3 major tiers: tier0 (e.g. GPU), tier1 (e.g.DRAM) and
> > > > > > > > tier2 (e.g. PMEM).
> > > > > > > >
> > > > > > > > - Each major tier can have minor tiers, e.g. tier0.0, tier1.0,
> > > > > > > > tier1.1, tier2.0, tier2.1.
> > > > > > > >
> > > > > > > > The earlier 4-tier example can be represented as:
> > > > > > > >
> > > > > > > > memtier0.0 -> memtier1.0 -> memtier2.0 -> memtier2.1
> > > > > > > >
> > > > > > > > We can also omit .0 so that the tiers are:
> > > > > > > >
> > > > > > > > memtier0 -> memtier1 -> memtier2 -> memtier2.1
> > > > > > > >
> > > > > > > > This should be flexible enough to support multiple tiers while keeping
> > > > > > > > the tier IDs relatively stable.
> > > > > > > >
> > > > > > > > It is not as flexible as the rank approach. For example, to insert a
> > > > > > > > new tier between 2.0 and 2.1, we need to add a tier 2.2 and reassign
> > > > > > > > existing nodes to these 3 tiers.  Using "rank", we can insert a new
> > > > > > > > tier and only move desired nodes into the new tier.
> > > > > > > >
> > > > > > > > What do you think?
> > > > > > >
> > > > > > > The rank approach looks better for.  And if we stick with the device ID
> > > > > > > rule as follows,
> > > > > > >
> > > > > > > ...
> > > > > > > 255     GPU
> > > > > > > 0       DRAM
> > > > > > > 1       PMEM
> > > > > > > 2
> > > > > > > ...
> > > > > > >
> > > > > > > 255 is -1 for "s8".
> > > > > > >
> > > > > > > The device ID should do most tricks at least now.  The rank can provide
> > > > > > > more flexibility in the future.  We can even go without rank in the
> > > > > > > first version, and introduce it when it's necessary.
> > > > > >
> > > > > > Given that the "rank" approach is generally favored, let's go with
> > > > > > that to avoid compatibility issues that may come from the switch of
> > > > > > device ID tricks to ranks.
> > > > >
> > > > > OK.  Just to confirm.  Does this mean that we will have fixed device ID,
> > > > > for example,
> > > > >
> > > > > GPU                     memtier255
> > > > > DRAM (with CPU)         memtier0
> > > > > PMEM                    memtier1
> > > > >
> > > > > When we add a new memtier, it can be memtier254, or memter2?  The rank
> > > > > value will determine the real demotion order.
> > > >
> > > > With the rank approach, the device ID numbering should be flexible and
> > > > not mandated by the proposal.
> > >
> > > If so, the rank number will be fixed?  For example,
> > >
> > > GPU                     100
> > > DRAM (with CPU)         200
> > > PMEM                    300
> > >
> > > When we add a new memtier, its rank can be 50, 150, 250, or 400?
> > >
> > > If so, this makes me think why we don't just make this kind of rank the
> > > device ID?  Or I missed something?
> > >
> > > Or, both device IDs and rank values are not fixed?  Why do we need that
> > > kind of flexibility?  Sorry, I may not undersand all requirements.
> >
> > Even though the proposal doesn't mandate a particular device ID
> > numbering, I expect that the device IDs will be relatively stable once
> > a kernel implementation is chosen. For example, it is likely that DRAM
> > nodes with CPUs will always be on memtier1, no matter how many tiers
> > are higher or lower than these nodes.
> >
> > We don't need to mandate a particular way to assign the rank values,
> > either.  What matters is the relative order and some reasonable gap
> > between these values.
> >
> > The rank approach allows us to keep memtier device IDs relatively
> > stable even though we may change the tier ordering among them.  Its
> > flexibility can have many other uses as well.  For example, we can
> > insert a new memtier into the tier hierarchy for a new set of nodes
> > without affecting the node assignment of any existing memtier,
> > provided that there is enough gap in the rank values for the new
> > memtier.
> >
> > Using the rank value directly as the device ID has some disadvantages:
> > - It is kind of unconventional to number devices in this way.
> > - We cannot assign DRAM nodes with CPUs with a specific memtier device
> > ID (even though this is not mandated by the "rank" proposal, I expect
> > the device will likely always be memtier1 in practice).
> > - It is possible that we may eventually allow the rank value to be
> > modified as a way to adjust the tier ordering.  We cannot do that
> > easily for device IDs.
>
> OK.  I can understand that sometimes it's more natural to change the
> order of a set of nodes with same memory types (and data plane path)
> together instead of change that one by one for each node.
>
> It appears that the memtierX device becomes kind of memory types (with
> data plane path considered for latency/throughput too).  We can assign a
> memory type for a node, and change the order between memory types.  If
> so, we need to allow multiple memtiers have same rank value.

Jonathan mentioned this feature that multiple memtiers share the same
rank as well.  It can be a convenient feature to have.  For
simplicity, it should be fine to leave out this feature initially.

> Best Regards,
> Huang, Ying
>
> > >
> > > > > I think you may need to send v3 to make sure everyone is at the same
> > > > > page.
> > > >
> > > > Will do it shortly.
> > >
> > > Good!  Thanks!
> > >
> > > Best Regards,
> > > Huang, Ying
> > >
> > > > > Best Regards,
> > > > > Huang, Ying
> > > > >
> > > > > > > Best Regards,
> > > > > > > Huang, Ying
> > > > > > >
> > > > > > > > > > The tier order: memtier128 -> memtier0 -> memtier1 -> memtier2
> > > > > > > > > >
> > > > > > > > > > $ cat /sys/devices/system/memtier/memtier*/nodelist
> > > > > > > > > > 0
> > > > > > > > > > 2
> > > > > > > > > > 3
> > > > > > > > > > 1
> > > > > > > > > >
> > > > > > > > > > $ ls -l /sys/devices/system/node/node*/memtier
> > > > > > > > > > /sys/devices/system/node/node0/memtier -> /sys/devices/system/memtier/memtier0
> > > > > > > > > > /sys/devices/system/node/node1/memtier -> /sys/devices/system/memtier/memtier128
> > > > > > > > > > /sys/devices/system/node/node2/memtier -> /sys/devices/system/memtier/memtier1
> > > > > > > > > > /sys/devices/system/node/node3/memtier -> /sys/devices/system/memtier/memtier2
> > > > > > > > > >
> > > > > > > > > > To override the memory tier of a node, we can use a new, write-only,
> > > > > > > > > > per-node interface file:
> > > > > > > > > >
> > > > > > > > > > /sys/devices/system/node/nodeN/set_memtier
> > > > > > > > > >
> > > > > > > > > > e.g.
> > > > > > > > > >
> > > > > > > > > > $ echo "memtier128" > sys/devices/system/node/node1/set_memtier
> > > > > > > > >
> > > > > > > > > I prefer the original proposal to make nodeX/memtier a normal file to
> > > > > > > > > hold memtier devicde ID instead of a link.
> > > > > > > >
> > > > > > > > OK. We don't have to use a symlink.
> > > > > > > >
> > > > > > > > > Best Regards,
> > > > > > > > > Huang, Ying
> > > > > > > > >
> > > > > > > > > > Any comments?
> > > > > > > > > >
> > > > > > > > > > > Jonathan
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > >
> > > > >
> > >
> > >
>
>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux