<chapter id="lgroups-1"><title>Locality Group APIs</title><highlights><para>This chapter describes the APIs that applications use to interact with
locality groups.</para><para>This chapter discusses the following topics:</para><itemizedlist><listitem><para><olink targetptr="lgroups-2" remap="internal">Locality Groups Overview</olink> describes
the locality group abstraction.</para>
</listitem><listitem><para><olink targetptr="lgroups-27" remap="internal">Verifying the Interface Version</olink> describes
the functions that give information about the interface.</para>
</listitem><listitem><para><olink targetptr="lgroups-4" remap="internal">Initializing the Locality Group
Interface</olink> describes function calls that initialize and shut down the
portion of the interface that is used to traverse the locality group hierarchy
and to discover the contents of a locality group.</para>
</listitem><listitem><para><olink targetptr="lgroups-29" remap="internal">Locality Group Hierarchy</olink> describes
function calls that navigate the locality group hierarchy and functions that
get characteristics of the locality group hierarchy.</para>
</listitem><listitem><para><olink targetptr="lgroups-30" remap="internal">Locality Group Contents</olink> describes
function calls that retrieve information about a locality group's contents.</para>
</listitem><listitem><para><olink targetptr="lgroups-31" remap="internal">Locality Group Characteristics</olink> describes
function calls that retrieve information about a locality group's characteristics.</para>
</listitem><listitem><para><olink targetptr="lgroups-32" remap="internal">Locality Groups and Thread and
Memory Placement</olink> describes how to affect the locality group placement
of a thread and its memory.</para>
</listitem><listitem><para><olink targetptr="lgroups-33" remap="internal">Examples of API Usage</olink> contains
code that performs example tasks by using the APIs that are described in this
chapter.</para>
</listitem>
</itemizedlist>
</highlights><sect1 id="lgroups-2"><title>Locality Groups Overview</title><para>Shared memory multiprocessor computers contain multiple CPUs. Each CPU
can access all of the memory in the machine. In some shared memory multiprocessors,
the memory architecture enables each CPU to access some areas of memory more
quickly than other areas.</para><para>When a machine with such a memory architecture runs the Solaris software,
providing information to the kernel about the shortest access times between
a given CPU and a given area of memory can improve the system's performance.
The locality group (lgroup) abstraction has been introduced to handle this
information. The lgroup abstraction is part of the Memory Placement Optimization
(MPO) feature.</para><para>An lgroup is a set of CPU&ndash;like and memory&ndash;like devices in
which each CPU in the set can access any memory in that set within a bounded
latency interval. The value of the latency interval represents the least common
latency between all the CPUs and all the memory in that lgroup. The latency
bound that defines an lgroup does not restrict the maximum latency between
members of that lgroup. The value of the latency bound is the shortest latency
that is common to all possible CPU-memory pairs in the group.</para><para>Lgroups are hierarchical. The lgroup hierarchy is a Directed Acyclic
Graph (DAG) and is similar to a tree, except that an lgroup might have more
than one parent. The root lgroup contains all the resources in the system
and can include child lgroups. Furthermore, the root lgroup can be characterized
as having the highest latency value of all the lgroups in the system. All
of its child lgroups will have lower latency values. The lgroups closer to
the root have a higher latency while lgroups closer to leaves have lower latency.</para><para>A computer in which all the CPUs can access all the memory in the same
amount of time can be represented with a single lgroup (see <olink targetptr="lgroups-fig-52" remap="internal">Figure 1&ndash;1</olink>). A computer in which
some of the CPUs can access some areas of memory in a shorter time than other
areas can be represented by using multiple lgroups (see <olink targetptr="lgroups-fig-53" remap="internal">Figure 1&ndash;2</olink>).</para><figure id="lgroups-fig-52"><title>Single Locality Group Schematic</title><mediaobject><imageobject><imagedata entityref="uma"/>
</imageobject><textobject><simpara>All CPUs in the machine can access the memory in a comparable
time frame.</simpara>
</textobject>
</mediaobject>
</figure><figure id="lgroups-fig-53"><title>Multiple Locality Groups Schematic</title><mediaobject><imageobject><imagedata entityref="numa"/>
</imageobject><textobject><simpara>The machine's CPU and memory resources are grouped by
bounded latency intervals.</simpara>
</textobject>
</mediaobject>
</figure><para>The organization of the lgroup hierarchy simplifies the task of finding
the nearest resources in the system. Each thread is assigned a home lgroup
upon creation. The operating system attempts to allocate resources for the
thread from the thread's home lgroup by default. For example, the Solaris
kernel attempts to schedule a thread to run on the CPUs in the thread's home
lgroup and allocate the thread's memory in the thread's home lgroup by default.
If the desired resources are not available from the thread's home lgroup,
the kernel can traverse the lgroup hierarchy to find the next nearest resources
from parents of the home lgroup. If the desired resources are not available
in the home lgroup's parents, the kernel continues to traverse the lgroup
hierarchy to the successive ancestor lgroups of the home lgroup. The root
lgroup is the ultimate ancestor of all other lgroups in a machine and contains
all of the machine's resources.</para><para>The lgroup APIs export the lgroup abstraction for applications to use
for observability and performance tuning. A new library, called <literal>liblgrp</literal>,
contains the new APIs. Applications can use the APIs to perform the following
tasks:</para><itemizedlist><listitem><para>Traverse the group hierarchy</para>
</listitem><listitem><para>Discover the contents and characteristics of a given lgroup</para>
</listitem><listitem><para>Affect the thread and memory placement on lgroups</para>
</listitem>
</itemizedlist>
</sect1><sect1 id="lgroups-27"><title>Verifying the Interface Version</title><para>The <olink targetdoc="refman3e" targetptr="lgrp-version-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_version</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function must be used to verify the presence of a
supported lgroup interface before using the lgroup API. The <function>lgrp_version</function> function has the following syntax:</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_version(const int version);</programlisting><para>The <function>lgrp_version</function> function takes a version number
for the lgroup interface as an argument and returns the lgroup interface version
that the system supports. When the current implementation of the lgroup API
supports the version number in the <literal>version</literal> argument, the <function>lgrp_version</function> function returns that version number. Otherwise, the <function>lgrp_version</function> function returns <literal>LGRP_VER_NONE</literal>.</para><example id="lgroups-ex-26"><title>Example of <function>lgrp_version</function> Use</title><programlisting>#include &lt;sys/lgrp_user.h>
if (lgrp_version(LGRP_VER_CURRENT) != LGRP_VER_CURRENT) {
    fprintf(stderr, "Built with unsupported lgroup interface %d\n",
        LGRP_VER_CURRENT);
    exit (1);
    }</programlisting>
</example>
</sect1><sect1 id="lgroups-4"><title>Initializing the Locality Group Interface</title><para>Applications must call <olink targetdoc="refman3e" targetptr="lgrp-init-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_init</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> in order to use the APIs
for traversing the lgroup hierarchy and to discover the contents of the lgroup
hierarchy. The call to <function>lgrp_init</function> gives the application
a consistent snapshot of the lgroup hierarchy. The application developer can
specify whether the snapshot contains only the resources that are available
to the calling thread specifically or the resources that are available to
the operating system in general. The <function>lgrp_init</function> function
returns a cookie that is used for the following tasks:</para><itemizedlist><listitem><para>Navigating the lgroup hierarchy</para>
</listitem><listitem><para>Determining the contents of an lgroup</para>
</listitem><listitem><para>Determining whether the snapshot is current</para>
</listitem>
</itemizedlist><sect2 id="lgroups-5"><title>Using <function>lgrp_init</function></title><para>The <function>lgrp_init</function> function initializes the lgroup interface
and takes a snapshot of the lgroup hierarchy.</para><programlisting>#include &lt;sys/lgrp_user.h>
lgrp_cookie_t lgrp_init(lgrp_view_t view);</programlisting><para>When the <function>lgrp_init</function> function is called with <literal>LGRP_VIEW_CALLER</literal> as the view, the function returns a snapshot that contains only
the resources that are available to the calling thread. When the <function>lgrp_init</function> function is called with <literal>LGRP_VIEW_OS</literal> as the
view, the function returns a snapshot that contains the resources that are
available to the operating system. When a thread successfully calls the <function>lgrp_init</function> function, the function returns a cookie that is used
by any function that interacts with the lgroup hierarchy. When a thread no
longer needs the cookie, call the <function>lgrp_fini</function> function
with the cookie as the argument.</para><para>The lgroup hierarchy consists of a root lgroup that contains all of
the machine's CPU and memory resources. The root lgroup might contain other
locality groups bounded by smaller latencies.</para><para>The <function>lgrp_init</function> function can return two errors. When
a view is invalid, the function returns <errorname>EINVAL</errorname>. When
there is insufficient memory to allocate the snapshot of the lgroup hierarchy,
the function returns <errorname>ENOMEM</errorname>.</para>
</sect2><sect2 id="lgroups-6"><title>Using <function>lgrp_fini</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-fini-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_fini</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function ends the usage of a given cookie and frees
the corresponding lgroup hierarchy snapshot.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_fini(lgrp_cookie_t cookie);</programlisting><para>The <function>lgrp_fini</function> function takes a cookie that represents
an lgroup hierarchy snapshot created by a previous call to <function>lgrp_init</function>.
The <function>lgrp_fini</function> function frees the memory that is allocated
to that snapshot. After the call to <function>lgrp_fini</function>, the cookie
is invalid. Do not use that cookie again.</para><para>When the cookie passed to the <function>lgrp_fini</function> function
is invalid, <function>lgrp_fini</function> returns <errorname>EINVAL</errorname>.</para>
</sect2>
</sect1><sect1 id="lgroups-29"><title>Locality Group Hierarchy</title><para>The APIs that are described in this section enable the calling thread
to navigate the lgroup hierarchy. The lgroup hierarchy is a directed acyclic
graph that is similar to a tree, except that a node might have more than one
parent. The root lgroup represents the whole machine and contains all of that
machine's resources. The root lgroup is the lgroup with the highest latency
value in the system. Each of the child lgroups contains a subset of the hardware
that is in the root lgroup. Each child lgroup is bounded by a lower latency
value. Locality groups that are closer to the root have more resources and
a higher latency. Locality groups that are closer to the leaves have fewer
resources and a lower latency. An lgroup can contain resources directly within
its latency boundary. An lgroup can also contain leaf lgroups that contain
their own sets of resources. The resources of leaf lgroups are available to
the lgroup that encapsulates those leaf lgroups.</para><sect2 id="lgroups-8"><title>Using <function>lgrp_cookie_stale</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-cookie-stale-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_cookie_stale</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function determines whether the snapshot of the lgroup
hierarchy represented by the given cookie is current.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_cookie_stale(lgrp_cookie_t cookie);</programlisting><para>The cookie returned by the <function>lgrp_init</function> function can
become stale due to several reasons that depend on the view that the snapshot
represents. A cookie that is returned by calling the <function>lgrp_init</function> function
with the view set to <literal>LGRP_VIEW_OS</literal> can become stale due
to changes in the lgroup hierarchy such as dynamic reconfiguration or a change
in a CPU's online status. A cookie that is returned by calling the <function>lgrp_init</function> function with the view set to <literal>LGRP_VIEW_CALLER</literal> can
become stale due to changes in the calling thread's processor set or changes
in the lgroup hierarchy. A stale cookie is refreshed by calling the <function>lgrp_fini</function> function with the old cookie, followed by calling <function>lgrp_init</function> to generate a new cookie.</para><para>The <function>lgrp_cookie_stale</function> function returns <errorname>EINVAL</errorname> when the given cookie is invalid.</para>
</sect2><sect2 id="lgroups-9"><title>Using <function>lgrp_view</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-view-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_view</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function determines the view with which a given lgroup
hierarchy snapshot was taken.</para><programlisting>#include &lt;sys/lgrp_user.h>
lgrp_view_t lgrp_view(lgrp_cookie_t cookie);</programlisting><para>The <function>lgrp_view</function> function takes a cookie that represents
a snapshot of the lgroup hierarchy and returns the snapshot's view of the
lgroup hierarchy. Snapshots that are taken with the view <literal>LGRP_VIEW_CALLER</literal> contain only the resources that are available to the calling thread.
Snapshots that are taken with the view <literal>LGRP_VIEW_OS</literal> contain
all the resources that are available to the operating system.</para><para>The <function>lgrp_view</function> function returns <errorname>EINVAL</errorname> when
the given cookie is invalid.</para>
</sect2><sect2 id="lgroups-10"><title>Using <function>lgrp_nlgrps</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-nlgrps-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_nlgrps</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function returns the number of locality groups in
the system. If a system has only one locality group, memory placement optimizations
have no effect.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_nlgrps(lgrp_cookie_t cookie);</programlisting><para>The <function>lgrp_nlgrps</function> function takes a cookie that represents
a snapshot of the lgroup hierarchy and returns the number of lgroups available
in the hierarchy.</para><para>The <function>lgrp_nlgrps</function> function returns <errorname>EINVAL</errorname> when
the cookie is invalid.</para>
</sect2><sect2 id="lgroups-35"><title>Using <function>lgrp_root</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-root-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_root</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function returns the root lgroup ID.</para><programlisting>#include &lt;sys/lgrp_user.h>
lgrp_id_t lgrp_root(lgrp_cookie_t cookie);</programlisting><para>The <function>lgrp_root</function> function takes a cookie that represents
a snapshot of the lgroup hierarchy and returns the root lgroup ID.</para>
</sect2><sect2 id="lgroups-36"><title>Using <function>lgrp_parents</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-parents-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_parents</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function takes a cookie that represents a snapshot
of the lgroup hierarchy and returns the number of parent lgroups for the specified
lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_parents(lgrp_cookie_t cookie, lgrp_id_t child,
                 lgrp_id_t *lgrp_array, uint_t lgrp_array_size);</programlisting><para>If <literal>lgrp_array</literal> is not <literal>NULL</literal> and
the value of <literal>lgrp_array_size</literal> is not zero, the <function>lgrp_parents</function> function fills the array with parent lgroup IDs until the array
is full or all parent lgroup IDs are in the array. The root lgroup has zero
parents. When the <function>lgrp_parents</function> function is called for
the root lgroup, <literal>lgrp_array</literal> is not filled in.</para><para>The <function>lgrp_parents</function> function returns <errorname>EINVAL</errorname> when
the cookie is invalid. The <function>lgrp_parents</function> function returns <errorname>ESRCH</errorname> when the specified lgroup ID is not found.</para>
</sect2><sect2 id="lgroups-37"><title>Using <function>lgrp_children</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-children-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_children</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function takes a cookie that represents the calling
thread's snapshot of the lgroup hierarchy and returns the number of child
lgroups for the specified lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_children(lgrp_cookie_t cookie, lgrp_id_t parent,
                  lgrp_id_t *lgrp_array, uint_t lgrp_array_size);</programlisting><para>If <literal>lgrp_array</literal> is not <literal>NULL</literal> and
the value of <literal>lgrp_array_size</literal> is not zero, the <function>lgrp_children</function> function fills the array with child lgroup IDs until the array
is full or all child lgroup IDs are in the array.</para><para>The <function>lgrp_children</function> function returns <errorname>EINVAL</errorname> when
the cookie is invalid. The <function>lgrp_children</function> function returns <errorname>ESRCH</errorname> when the specified lgroup ID is not found.</para>
</sect2>
</sect1><sect1 id="lgroups-30"><title>Locality Group Contents</title><para>The following APIs retrieve information about the contents of a given
lgroup.</para><para>The lgroup hierarchy organizes the domain's resources to simplify the
process of locating the nearest resource. Leaf lgroups are defined with resources
that have the least latency. Each of the successive ancestor lgroups of a
given leaf lgroup contains the next nearest resources to its child lgroup.
The root lgroup contains all of the resources that are in the domain.</para><para>The resources of a given lgroup are contained directly within that lgroup
or indirectly within the leaf lgroups that the given lgroup encapsulates.
Leaf lgroups directly contain their resources and do not encapsulate any other
lgroups.</para><sect2 id="lgroups-940"><title>Using <function>lgrp_resources</function></title><para>The <function>lgrp_resources</function> function returns the number
of resources contained in a specified lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *lgrpids,
                   uint_t count, lgrp_rsrc_t type);</programlisting><para>The <function>lgrp_resources</function> function takes a cookie that
represents a snapshot of the lgroup hierarchy. That cookie is obtained from
the <function>lgrp_init</function> function. The <function>lgrp_resources</function> function
returns the number of resources that are in the lgroup with the ID that is
specified by the value of the <literal>lgrp</literal> argument. The <function>lgrp_resources</function> function represents the resources with a set of lgroups that directly
contain CPU or memory resources. The <literal>lgrp_rsrc_t</literal> argument
can have the following two values:</para><variablelist><varlistentry><term><literal>LGRP_RSRC_CPU</literal></term><listitem><para>The <function>lgrp_resources</function> function returns the
number of CPU resources.</para>
</listitem>
</varlistentry><varlistentry><term><literal>LGRP_RSRC_MEM</literal></term><listitem><para>The <function>lgrp_resources</function> function returns the
number of memory resources.</para>
</listitem>
</varlistentry>
</variablelist><para>When the value passed in the <literal>lgrpids[]</literal> argument is
not null and the <literal>count</literal> argument is not zero, the <function>lgrp_resources</function> function stores lgroup IDs in the <literal>lgrpids[]</literal> array.
The number of lgroup IDs stored in the array can be up to the value of the <literal>count</literal> argument.</para><para>The <function>lgrp_resources</function> function returns <errorname>EINVAL</errorname> when
the specified cookie, lgroup ID, or type are not valid. The <function>lgrp_resources</function> function returns <errorname>ESRCH</errorname> when the function
does not find the specified lgroup ID.</para>
</sect2><sect2 id="lgroups-38"><title>Using <function>lgrp_cpus</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-cpus-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_cpus</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function takes a cookie that represents a snapshot
of the lgroup hierarchy and returns the number of CPUs in a given lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_cpus(lgrp_cookie_t cookie, lgrp_id_t lgrp, processorid_t *cpuids,
              uint_t count, int content);</programlisting><para>If the <parameter>cpuid[]</parameter> argument is not <literal>NULL</literal> and
the CPU count is not zero, the <function>lgrp_cpus</function> function fills
the array with CPU IDs until the array is full or all the CPU IDs are in the
array.</para><para>The <parameter>content</parameter> argument can have the following two
values:</para><variablelist><varlistentry><term><literal>LGRP_CONTENT_ALL</literal></term><listitem><para>The <function>lgrp_cpus</function> function returns IDs for
the CPUs in this lgroup and this lgroup's descendants.</para>
</listitem>
</varlistentry><varlistentry><term><literal>LGRP_CONTENT_DIRECT</literal></term><listitem><para>The <function>lgrp_cpus</function> function returns IDs for
the CPUs in this lgroup only.</para>
</listitem>
</varlistentry>
</variablelist><para>The <function>lgrp_cpus</function> function returns <errorname>EINVAL</errorname> when
the cookie, lgroup ID, or one of the flags is not valid. The <function>lgrp_cpus</function> function
returns <errorname>ESRCH</errorname> when the specified lgroup ID is not found.</para>
</sect2><sect2 id="lgroups-39"><title>Using <function>lgrp_mem_size</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-mem-size-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_mem_size</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function takes a cookie that represents a snapshot
of the lgroup hierarchy and returns the size of installed or free memory in
the given lgroup. The <function>lgrp_mem_size</function> function reports
memory sizes in bytes.</para><programlisting>#include &lt;sys/lgrp_user.h>
lgrp_mem_size_t lgrp_mem_size(lgrp_cookie_t cookie, lgrp_id_t lgrp,
                              int type, int content)</programlisting><para>The <parameter>type</parameter> argument can have the following two
values:</para><variablelist><varlistentry><term><literal>LGRP_MEM_SZ_FREE</literal></term><listitem><para>The <function>lgrp_mem_size</function> function returns the
amount of free memory in bytes.</para>
</listitem>
</varlistentry><varlistentry><term><literal>LGRP_MEM_SZ_INSTALLED</literal></term><listitem><para>The <function>lgrp_mem_size</function> function returns the
amount of installed memory in bytes.</para>
</listitem>
</varlistentry>
</variablelist><para>The <parameter>content</parameter> argument can have the following two
values:</para><variablelist><varlistentry><term><literal>LGRP_CONTENT_ALL</literal></term><listitem><para>The <function>lgrp_mem_size</function> function returns the
amount of memory in this lgroup and this lgroup's descendants.</para>
</listitem>
</varlistentry><varlistentry><term><literal>LGRP_CONTENT_DIRECT</literal></term><listitem><para>The <function>lgrp_mem_size</function> function returns the
amount of memory in this lgroup only.</para>
</listitem>
</varlistentry>
</variablelist><para>The <function>lgrp_mem_size</function> function returns <errorname>EINVAL</errorname> when
the cookie, lgroup ID, or one of the flags is not valid. The <function>lgrp_mem_size</function> function returns <errorname>ESRCH</errorname> when the specified
lgroup ID is not found.</para>
</sect2>
</sect1><sect1 id="lgroups-31"><title>Locality Group Characteristics</title><para>The following API retrieves information about the characteristics of
a given lgroup.</para><sect2 id="lgroups-40"><title>Using <function>lgrp_latency_cookie</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-latency-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_latency</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function returns the latency between a CPU in one
lgroup to the memory in another lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_latency_cookie(lgrp_cookie_t cookie, lgrp_id_t from, lgrp_id_t to.
                        lat_between_t between);</programlisting><para>The <function>lgrp_latency_cookie</function> function takes a cookie
that represents a snapshot of the lgroup hierarchy. The <function>lgrp_init</function> function
creates this cookie. The <function>lgrp_latency_cookie</function> function
returns a value that represents the latency between a hardware resource in
the lgroup given by the value of the <parameter>from</parameter> argument
and a hardware resource in the lgroup given by the value of the <parameter>to</parameter> argument.
If both arguments point to the same lgroup, the <function>lgrp_latency_cookie</function> function
returns the latency value within that lgroup.</para><note><para>The latency value returned by the <function>lgrp_latency_cookie</function> function
is defined by the operating system and is platform-specific. This value does
not necessarily represent the actual latency between hardware devices. Use this value only for comparison within one domain.</para>
</note><para>When the value of the <parameter>between</parameter> argument is <literal>LGRP_LAT_CPU_TO_MEM</literal>, the <function>lgrp_latency_cookie</function> function measures
the latency from a CPU resource to a memory resource.</para><para>The <function>lgrp_latency_cookie</function> function returns <errorname>EINVAL</errorname> when the lgroup ID is not valid. When the <function>lgrp_latency_cookie</function> function does not find the specified lgroup ID, the &ldquo;from&rdquo;
lgroup does not contain any CPUs, or the &ldquo;to&rdquo; lgroup does not
have any memory, the <function>lgrp_latency_cookie</function> function returns <errorname>ESRCH</errorname>.</para>
</sect2>
</sect1><sect1 id="lgroups-32"><title>Locality Groups and Thread and Memory Placement</title><para>This section discusses the APIs used to discover and affect thread and
memory placement with respect to lgroups.</para><itemizedlist><listitem><para>The <olink targetdoc="refman3e" targetptr="lgrp-home-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_home</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function is used to discover thread placement.</para>
</listitem><listitem><para>The <olink targetdoc="refman2" targetptr="meminfo-2" remap="external"><citerefentry><refentrytitle>meminfo</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink> system
call is used to discover memory placement.</para>
</listitem><listitem><para>The <literal>MADV_ACCESS</literal> flags to the <olink targetdoc="refman3a" targetptr="madvise-3c" remap="external"><citerefentry><refentrytitle>madvise</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink> function are used to affect
memory allocation among lgroups.</para>
</listitem><listitem><para>The <olink targetdoc="refman3e" targetptr="lgrp-affinity-set-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_affinity_set</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function
can affect thread and memory placement by setting a thread's affinity for
a given lgroup.</para>
</listitem><listitem><para>The affinities of an lgroup may specify an order of preference
for lgroups from which to allocate resources.</para>
</listitem><listitem><para>The kernel needs information about the likely pattern of an
application's memory use in order to allocate memory resources efficiently.</para>
</listitem><listitem><para>The <function>madvise</function> function and its shared object
analogue <literal>madv.so.1</literal> provide this information to the kernel.</para>
</listitem><listitem><para>A running process can gather memory usage information about
itself by using the <function>meminfo</function> system call.</para>
</listitem>
</itemizedlist><sect2 id="lgroups-19"><title>Using <function>lgrp_home</function></title><para>The <function>lgrp_home</function> function returns the home lgroup
for the specified process or thread.</para><programlisting>#include &lt;sys/lgrp_user.h>
lgrp_id_t lgrp_home(idtype_t idtype, id_t id);</programlisting><para>The <function>lgrp_home</function> function returns <errorname>EINVAL</errorname> when
the ID type is not valid. The <function>lgrp_home</function> function returns <errorname>EPERM</errorname> when the effective user of the calling process is not the
superuser and the real or effective user ID of the calling process does not
match the real or effective user ID of one of the threads. The <function>lgrp_home</function> function returns <errorname>ESRCH</errorname> when the specified
process or thread is not found.</para>
</sect2><sect2 id="lgroups-23"><title>Using <function>madvise</function></title><para>The <function>madvise</function> function advises the kernel that a
region of user virtual memory in the range starting at the address specified
in <parameter>addr</parameter> and with length equal to the value of the <parameter>len</parameter> parameter is expected to follow a particular pattern of use.
The kernel uses this information to optimize the procedure for manipulating
and maintaining the resources associated with the specified range. Use of
the <function>madvise</function> function can increase system performance
when used by programs that have specific knowledge of their access patterns
over memory.</para><programlisting>#include &lt;sys/types.h>
#include &lt;sys/mman.h>
int madvise(caddr_t addr, size_t len, int advice);</programlisting><para>The <function>madvise</function> function provides the following flags
to affect how a thread's memory is allocated among lgroups:</para><variablelist><varlistentry><term><literal>MADV_ACCESS_DEFAULT</literal></term><listitem><para>This flag resets the kernel's expected access pattern for
the specified range to the default.</para>
</listitem>
</varlistentry><varlistentry><term><literal>MADV_ACCESS_LWP</literal></term><listitem><para>This flag advises the kernel that the next LWP to touch the
specified address range is the LWP that will access that range the most. The
kernel allocates the memory and other resources for this range and the LWP
accordingly.</para>
</listitem>
</varlistentry><varlistentry><term><literal>MADV_ACCESS_MANY</literal></term><listitem><para>This flag advises the kernel that many processes or LWPs will
access the specified address range randomly across the system. The kernel
allocates the memory and other resources for this range accordingly.</para>
</listitem>
</varlistentry>
</variablelist><para>The <function>madvise</function> function can return the following values:</para><variablelist><varlistentry><term><errorname>EAGAIN</errorname></term><listitem><para>Some or all of the mappings in the specified address range,
from <parameter>addr</parameter> to <parameter>addr</parameter>+<parameter>len</parameter>,
are locked for I/O.</para>
</listitem>
</varlistentry><varlistentry><term><errorname>EINVAL</errorname></term><listitem><para>The value of the <parameter>addr</parameter> parameter is
not a multiple of the page size as returned by <olink targetdoc="refman3a" targetptr="sysconf-3c" remap="external"><citerefentry><refentrytitle>sysconf</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink>, the length of the specified
address range is less than or equal to zero, or the advice is invalid.</para>
</listitem>
</varlistentry><varlistentry><term><errorname>EIO</errorname></term><listitem><para>An I/O error occurs while reading from or writing to the file
system.</para>
</listitem>
</varlistentry><varlistentry><term><errorname>ENOMEM</errorname></term><listitem><para>Addresses in the specified address range are outside the valid
range for the address space of a process or the addresses in the specified
address range specify one or more pages that are not mapped.</para>
</listitem>
</varlistentry><varlistentry><term><errorname>ESTALE</errorname></term><listitem><para>The NFS file handle is stale.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2><sect2 id="lgroups-24"><title>Using <literal>madv.so.1</literal></title><para>The <literal>madv.so.1</literal> shared object enables the selective
configuration of virtual memory advice for launched processes and their descendants.
To use the shared object, the following string must be present in the environment:</para><programlisting>LD_PRELOAD=$LD_PRELOAD:madv.so.1</programlisting><para>The <literal>madv.so.1</literal> shared object applies memory advice
as specified by the value of the <envar>MADV</envar> environment variable.
The <envar>MADV</envar> environment variable specifies the virtual memory
advice to use for all heap, shared memory, and mmap regions in the process
address space. This advice is applied to all created processes. The following
values of the <envar>MADV</envar> environment variable affect resource allocation
among lgroups:</para><variablelist><varlistentry><term><literal>access_default</literal></term><listitem><para>This value resets the kernel's expected access pattern to
the default.</para>
</listitem>
</varlistentry><varlistentry><term><literal>access_lwp</literal></term><listitem><para>This value advises the kernel that the next LWP to touch an
address range is the LWP that will access that range the most. The kernel
allocates the memory and other resources for this range and the LWP accordingly.</para>
</listitem>
</varlistentry><varlistentry><term><literal>access_many</literal></term><listitem><para>This value advises the kernel that many processes or LWPs
will access memory randomly across the system. The kernel allocates the memory
and other resources accordingly.</para>
</listitem>
</varlistentry>
</variablelist><para>The value of the <envar>MADVCFGFILE</envar> environment variable is
the name of a text file that contains one or more memory advice configuration
entries in the form <replaceable>exec-name</replaceable>:<replaceable>advice-opts</replaceable>.</para><para>The value of <replaceable>exec-name</replaceable> is the name of an
application or executable. The value of <replaceable>exec-name</replaceable> can
be a full pathname, a base name, or a pattern string.</para><para>The value of <replaceable>advice-opts</replaceable> is of the form <replaceable>region</replaceable>=<replaceable>advice</replaceable>. The values of <replaceable>advice</replaceable> are the same as the values for the <envar>MADV</envar> environment
variable. Replace <replaceable>region</replaceable> with any of the following
legal values:</para><variablelist><varlistentry><term><literal>madv</literal></term><listitem><para>Advice applies to all heap, shared memory, and <olink targetdoc="refman2" targetptr="mmap-2" remap="external"><citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink> regions in the process address
space.</para>
</listitem>
</varlistentry><varlistentry><term><literal>heap</literal></term><listitem><para>The heap is defined to be the <olink targetdoc="refman2" targetptr="brk-2" remap="external"><citerefentry><refentrytitle>brk</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink> area. Advice applies to the existing heap and to any
additional heap memory allocated in the future.</para>
</listitem>
</varlistentry><varlistentry><term><literal>shm</literal></term><listitem><para>Advice applies to shared memory segments. See <olink targetdoc="refman2" targetptr="shmat-2" remap="external"><citerefentry><refentrytitle>shmat</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink> for more information on shared
memory operations.</para>
</listitem>
</varlistentry><varlistentry><term><literal>ism</literal></term><listitem><para>Advice applies to shared memory segments that are using the <literal>SHM_SHARE_MMU</literal> flag. The <literal>ism</literal> option takes precedence
over <literal>shm</literal>.</para>
</listitem>
</varlistentry><varlistentry><term><literal>dsm</literal></term><listitem><para>Advice applies to shared memory segments that are using the <literal>SHM_PAGEABLE</literal> flag. The <literal>dsm</literal> option takes precedence
over <literal>shm</literal>.</para>
</listitem>
</varlistentry><varlistentry><term><literal>mapshared</literal></term><listitem><para>Advice applies to mappings established by the <function>mmap</function> system
call using the <literal>MAP_SHARED</literal> flag.</para>
</listitem>
</varlistentry><varlistentry><term><literal>mapprivate</literal></term><listitem><para>Advice applies to mappings established by the <function>mmap</function> system
call using the <literal>MAP_PRIVATE</literal> flag.</para>
</listitem>
</varlistentry><varlistentry><term><literal>mapanon</literal></term><listitem><para>Advice applies to mappings established by the <function>mmap</function> system
call using the <literal>MAP_ANON</literal> flag. The <literal>mapanon</literal> option
takes precedence when multiple options apply.</para>
</listitem>
</varlistentry>
</variablelist><para>The value of the <envar>MADVERRFILE</envar> environment variable is
the name of the path where error messages are logged. In the absence of a <envar>MADVERRFILE</envar> location, the <literal>madv.so.1</literal> shared object
logs errors by using <olink targetdoc="refman3a" targetptr="syslog-3c" remap="external"><citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink> with
a <literal>LOG_ERR</literal> as the severity level and <literal>LOG_USER</literal> as
the facility descriptor.</para><para>Memory advice is inherited. A child process has the same advice as its
parent. The advice is set back to the system default advice after a call to <olink targetdoc="refman2" targetptr="exec-2" remap="external"><citerefentry><refentrytitle>exec</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink> unless a different level of
advice is configured using the <literal>madv.so.1</literal> shared object.
Advice is only applied to <function>mmap</function> regions explicitly created
by the user program. Regions established by the run-time linker or by system
libraries that make direct system calls are not affected.</para><sect3 id="lgroups-42"><title><literal>madv.so.1</literal> Usage Examples</title><para>The following examples illustrate specific aspects of the <literal>madv.so.1</literal> shared object.</para><example id="lgroups-ex-43"><title>Setting Advice for a Set of Applications</title><para>This configuration applies advice to all ISM segments for applications
with exec names that begin with <literal>foo</literal>.</para><programlisting>$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADVCFGFILE
$ cat $MADVCFGFILE
        foo*:ism=access_lwp</programlisting>
</example><example id="lgroups-ex-44"><title>Excluding a Set of Applications From Advice</title><para>This configuration sets advice for all applications with the exception
of <command>ls</command>.</para><programlisting>$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADV=access_many
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADV MADVCFGFILE
$ cat $MADVCFGFILE
        ls:</programlisting>
</example><example id="lgroups-ex-45"><title>Pattern Matching in a Configuration File</title><para>Because the configuration specified in <envar>MADVCFGFILE</envar> takes
precedence over the value set in <envar>MADV</envar>, specifying <literal>*</literal> as
the <replaceable>exec-name</replaceable> of the last configuration entry is
equivalent to setting <envar>MADV</envar>. This example is equivalent to the
previous example.</para><programlisting>$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADVCFGFILE
$ cat $MADVCFGFILE
        ls:
        *:madv=access_many</programlisting>
</example><example id="lgroups-ex-46"><title>Advice for Multiple Regions</title><para>This configuration applies one type of advice for <function>mmap</function> regions
and different advice for heap and shared memory regions for applications whose <function>exec</function> names begin with <literal>foo</literal>.</para><programlisting>$ LD_PRELOAD=$LD_PRELOAD:madv.so.1
$ MADVCFGFILE=madvcfg
$ export LD_PRELOAD MADVCFGFILE
$ cat $MADVCFGFILE
        foo*:madv=access_many,heap=sequential,shm=access_lwp</programlisting>
</example>
</sect3>
</sect2><sect2 id="lgroups-25"><title>Using <function>meminfo</function></title><para>The <function>meminfo</function> function gives the calling process
information about the virtual memory and physical memory that the system has
allocated to that process.</para><programlisting>#include &lt;sys/types.h>
#include &lt;sys/mman.h>
int meminfo(const uint64_t inaddr[], int addr_count,
    const uint_t info_req[], int info_count, uint64_t outdata[],
    uint_t validity[]);</programlisting><para>The <function>meminfo</function> function can return the following types
of information:</para><variablelist><varlistentry><term><literal>MEMINFO_VPHYSICAL</literal></term><listitem><para>The physical memory address corresponding to the given virtual
address</para>
</listitem>
</varlistentry><varlistentry><term><literal>MEMINFO_VLGRP</literal></term><listitem><para>The lgroup to which the physical page corresponding to the
given virtual address belongs</para>
</listitem>
</varlistentry><varlistentry><term><literal>MEMINFO_VPAGESIZE</literal></term><listitem><para>The size of the physical page corresponding to the given virtual
address</para>
</listitem>
</varlistentry><varlistentry><term><literal>MEMINFO_VREPLCNT</literal></term><listitem><para>The number of replicated physical pages that correspond to
the given virtual address</para>
</listitem>
</varlistentry><varlistentry><term><literal>MEMINFO_VREPL|n</literal></term><listitem><para>The <emphasis>n</emphasis>th physical replica of the given
virtual address</para>
</listitem>
</varlistentry><varlistentry><term><literal>MEMINFO_VREPL_LGRP|n</literal></term><listitem><para>The lgroup to which the <emphasis>n</emphasis>th physical
replica of the given virtual address belongs</para>
</listitem>
</varlistentry><varlistentry><term><literal>MEMINFO_PLGRP</literal></term><listitem><para>The lgroup to which the given physical address belongs</para>
</listitem>
</varlistentry>
</variablelist><para>The <function>meminfo</function> function takes the following parameters:</para><variablelist><varlistentry><term><parameter>inaddr</parameter></term><listitem><para>An array of input addresses.</para>
</listitem>
</varlistentry><varlistentry><term><parameter>addr_count</parameter></term><listitem><para>The number of addresses that are passed to <function>meminfo</function>.</para>
</listitem>
</varlistentry><varlistentry><term><parameter>info_req</parameter></term><listitem><para>An array that lists the types of information that are being
requested.</para>
</listitem>
</varlistentry><varlistentry><term><parameter>info_count</parameter></term><listitem><para>The number of pieces of information that are requested for
each address in the <parameter>inaddr</parameter> array.</para>
</listitem>
</varlistentry><varlistentry><term><parameter>outdata</parameter></term><listitem><para>An array where the <function>meminfo</function> function places
the results. The array's size is equal to the product of the values of the <parameter>info_req</parameter> and <parameter>addr_count</parameter> parameters.</para>
</listitem>
</varlistentry><varlistentry><term><parameter>validity</parameter></term><listitem><para>An array of size equal to the value of the <parameter>addr_count</parameter> parameter.
The <parameter>validity</parameter> array contains bitwise result codes. The <emphasis>0</emphasis>th bit of the result code evaluates the validity of the corresponding
input address. Each successive bit in the result code evaluates the validity
of the response to the members of the <parameter>info_req</parameter> array
in turn.</para>
</listitem>
</varlistentry>
</variablelist><para>The <function>meminfo</function> function returns <errorname>EFAULT</errorname> when
the area of memory to which the <parameter>outdata</parameter> or <parameter>validity</parameter> arrays point cannot be written to. The <function>meminfo</function> function
returns <errorname>EFAULT</errorname> when the area of memory to which the <parameter>info_req</parameter> or <parameter>inaddr</parameter> arrays point cannot
be read from. The <function>meminfo</function> function returns <errorname>EINVAL</errorname> when the value of <parameter>info_count</parameter> exceeds 31
or is less than 1. The <function>meminfo</function> function returns <errorname>EINVAL</errorname> when the value of <parameter>addr_count</parameter> is less than
zero.</para><example id="lgroups-ex-41"><title>Use of <function>meminfo</function> to
Print Out Physical Pages and Page Sizes Corresponding to a Set of Virtual
Addresses</title><programlisting>void
print_info(void **addrvec, int how_many)
{
        static const int info[] = {
                MEMINFO_VPHYSICAL,
                MEMINFO_VPAGESIZE};
        uint64_t * inaddr = alloca(sizeof(uint64_t) * how_many);
        uint64_t * outdata = alloca(sizeof(uint64_t) * how_many * 2;
        uint_t * validity = alloca(sizeof(uint_t) * how_many);

        int i;

        for (i = 0; i &lt; how_many; i++)
                inaddr[i] = (uint64_t *)addr[i];

        if (meminfo(inaddr, how_many,  info,
                    sizeof (info)/ sizeof(info[0]),
                    outdata, validity) &lt; 0)
                ...

        for (i = 0; i &lt; how_many; i++) {
                if (validity[i] &amp; 1 == 0)
                        printf("address 0x%llx not part of address
                                        space\n",
                                inaddr[i]);

                else if (validity[i] &amp; 2 == 0)
                        printf("address 0x%llx has no physical page
                                        associated with it\n",
                                inaddr[i]);

                else {
                        char buff[80];
                        if (validity[i] &amp; 4 == 0)
                                strcpy(buff, "&lt;Unknown>");
                        else
                                sprintf(buff, "%lld", outdata[i * 2 +
                                                1]);
                        printf("address 0x%llx is backed by physical
                                        page 0x%llx of size %s\n",
                                        inaddr[i], outdata[i * 2], buff);
                }
        }
}</programlisting>
</example>
</sect2><sect2 id="lgroups-20"><title>Locality Group Affinity</title><para>The kernel assigns a thread to a locality group when the lightweight
process (LWP) for that thread is created. That lgroup is called the thread's <emphasis>home lgroup</emphasis>. The kernel runs the thread on the CPUs in the thread's
home lgroup and allocates memory from that lgroup whenever possible. If resources
from the home lgroup are unavailable, the kernel allocates resources from
other lgroups. When a thread has affinity for more than one lgroup, the operating
system allocates resources from lgroups chosen in order of affinity strength.
Lgroups can have one of three distinct affinity levels:</para><orderedlist><listitem><para><literal>LGRP_AFF_STRONG</literal> indicates strong affinity.
If this lgroup is the thread's home lgroup, the operating system avoids rehoming
the thread to another lgroup if possible. Events such as dynamic reconfiguration,
processor, offlining, processor binding, and processor set binding and manipulation
might still result in thread rehoming.</para>
</listitem><listitem><para><literal>LGRP_AFF_WEAK</literal> indicates weak affinity.
If this lgroup is the thread's home lgroup, the operating system rehomes the
thread if necessary for load balancing purposes.</para>
</listitem><listitem><para><literal>LGRP_AFF_NONE</literal> indicates no affinity. If
a thread has no affinity to any lgroup, the operating system assigns a home
lgroup to the thread .</para>
</listitem>
</orderedlist><para>The operating system uses lgroup affinities as advice when allocating
resources for a given thread. The advice is factored in with the other system
constraints. Processor binding and processor sets do not change lgroup affinities,
but might restrict the lgroups on which a thread can run.</para><sect3 id="lgroups-192"><title>Using <function>lgrp_affinity_get</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-affinity-get-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_affinity_get</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function returns the affinity that a LWP has for a
given lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
lgrp_affinity_t lgrp_affinity_get(idtype_t idtype, id_t id, lgrp_id_t lgrp);</programlisting><para>The <parameter>idtype</parameter> and <parameter>id</parameter> arguments
specify the LWP that the <function>lgrp_affinity_get</function> function examines.
If the value of <parameter>idtype</parameter> is <literal>P_PID</literal>,
the <function>lgrp_affinity_get</function> function gets the lgroup affinity
for one of the LWPs in the process whose process ID matches the value of the <parameter>id</parameter> argument. If the value of <parameter>idtype</parameter> is <literal>P_LWPID</literal>, the <function>lgrp_affinity_get</function> function gets
the lgroup affinity for the LWP of the current process whose LWP ID matches
the value of the <parameter>id</parameter> argument. If the value of <parameter>idtype</parameter> is <literal>P_MYID</literal>, the <function>lgrp_affinity_get</function> function
gets the lgroup affinity for the current LWP.</para><para>The <function>lgrp_affinity_get</function> function returns <errorname>EINVAL</errorname> when the given lgroup or ID type is not valid. The <function>lgrp_affinity_get</function> function returns <errorname>EPERM</errorname> when the effective
user of the calling process is not the superuser and the ID of the calling
process does not match the real or effective user ID of one of the LWPs. The <function>lgrp_affinity_get</function> function returns <errorname>ESRCH</errorname> when
a given lgroup or LWP is not found.</para>
</sect3><sect3 id="lgroups-193"><title>Using <function>lgrp_affinity_set</function></title><para>The <olink targetdoc="refman3e" targetptr="lgrp-affinity-set-3lgrp" remap="external"><citerefentry><refentrytitle>lgrp_affinity_set</refentrytitle><manvolnum>3LGRP</manvolnum></citerefentry></olink> function sets the affinity that a LWP or set of LWPs
have for a given lgroup.</para><programlisting>#include &lt;sys/lgrp_user.h>
int lgrp_affinity_set(idtype_t idtype, id_t id, lgrp_id_t lgrp,
                      lgrp_affinity_t affinity);</programlisting><para>The <parameter>idtype</parameter> and <parameter>id</parameter> arguments
specify the LWP or set of LWPs the <function>lgrp_affinity_set</function> function
examines. If the value of <parameter>idtype</parameter> is <literal>P_PID</literal>,
the <function>lgrp_affinity_set</function> function sets the lgroup affinity
for all of the LWPs in the process whose process ID matches the value of the <parameter>id</parameter> argument to the affinity level specified in the <parameter>affinity</parameter> argument. If the value of <parameter>idtype</parameter> is <literal>P_LWPID</literal>, the <function>lgrp_affinity_set</function> function sets
the lgroup affinity for the LWP of the current process whose LWP ID matches
the value of the <parameter>id</parameter> argument to the affinity level
specified in the <parameter>affinity</parameter> argument. If the value of <parameter>idtype</parameter> is <literal>P_MYID</literal>, the <function>lgrp_affinity_set</function> function
sets the lgroup affinity for the current LWP or process to the affinity level
specified in the <parameter>affinity</parameter> argument.</para><para>The <function>lgrp_affinity_set</function> function returns <errorname>EINVAL</errorname> when the given lgroup, affinity, or ID type is not valid. The <function>lgrp_affinity_set</function> function returns <errorname>EPERM</errorname> when
the effective user of the calling process is not the superuser and the ID
of the calling process does not match the real or effective user ID of one
of the LWPs. The <function>lgrp_affinity_set</function> function returns <errorname>ESRCH</errorname> when a given lgroup or LWP is not found.</para>
</sect3>
</sect2>
</sect1><sect1 id="lgroups-33"><title>Examples of API Usage</title><para>This section contains code for example tasks that use the APIs that
are described in this chapter.</para><example id="lgroups-ex-47"><title>Move Memory to a Thread</title><para>The following code sample moves the memory in the address range between <parameter>addr</parameter> and <parameter>addr</parameter>+<parameter>len</parameter> near
the next thread to touch that range.</para><programlisting>#include &lt;stdio.h>
#include &lt;sys/mman.h>
#include &lt;sys/types.h>



/*
 * Move memory to thread
 */
void
mem_to_thread(caddr_t addr, size_t len)
{
	if (madvise(addr, len, MADV_ACCESS_LWP) &lt; 0)
		perror("madvise");
}</programlisting>
</example><example id="lgroups-ex-48"><title>Move a Thread to Memory</title><para>This sample code uses the <function>meminfo</function> function to determine
the lgroup of the physical memory backing the virtual page at the given address.
The sample code then sets a strong affinity for that lgroup in an attempt
to move the current thread near that memory.</para><programlisting>#include &lt;stdio.h>
#include &lt;sys/lgrp_user.h>
#include &lt;sys/mman.h>
#include &lt;sys/types.h>


/*
 * Move a thread to memory
 */
int
thread_to_memory(caddr_t va)
{
	uint64_t    addr;
	ulong_t     count;
	lgrp_id_t   home;
	uint64_t    lgrp;
	uint_t      request;
	uint_t      valid;

	addr = (uint64_t)va;
	count = 1;
	request = MEMINFO_VLGRP;
	if (meminfo(&amp;addr, 1, &amp;request, 1, &amp;lgrp, &amp;valid) != 0) {
		perror("meminfo");
		return (1);
	}

	if (lgrp_affinity_set(P_LWPID, P_MYID, lgrp, LGRP_AFF_STRONG) != 0) {
		perror("lgrp_affinity_set");
		return (2);
	}

	home = lgrp_home(P_LWPID, P_MYID);
	if (home == -1) {
		perror ("lgrp_home");
		return (3);
	}

	if (home != lgrp)
		return (-1);

	return (0);
}</programlisting>
</example><example id="lgroups-ex-49"><title>Walk the lgroup Hierarchy</title><para>The following sample code walks through and prints out the lgroup hierarchy.</para><programlisting>#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;sys/lgrp_user.h>
#include &lt;sys/types.h>


/*
 * Walk and print lgroup hierarchy from given lgroup
 * through all its descendants
 */
int
lgrp_walk(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_content_t content)
{
	lgrp_affinity_t    aff;
	lgrp_id_t          *children;
	processorid_t      *cpuids;
	int                i;
	int                ncpus;
	int                nchildren;
	int                nparents;
	lgrp_id_t          *parents;
	lgrp_mem_size_t    size;

	/*
	 * Print given lgroup, caller's affinity for lgroup,
	 * and desired content specified
	 */
	printf("LGROUP #%d:\n", lgrp);

	aff = lgrp_affinity_get(P_LWPID, P_MYID, lgrp);
	if (aff == -1)
		perror ("lgrp_affinity_get");
	printf("\tAFFINITY: %d\n", aff);

	printf("CONTENT %d:\n", content);

	/*
	 * Get CPUs
	 */
	ncpus = lgrp_cpus(cookie, lgrp, NULL, 0, content);
	printf("\t%d CPUS: ", ncpus);
	if (ncpus == -1) {
		perror("lgrp_cpus");
		return (-1);
	} else if (ncpus > 0) {
		cpuids = malloc(ncpus * sizeof (processorid_t));
		ncpus = lgrp_cpus(cookie, lgrp, cpuids, ncpus, content);
                if (ncpus == -1) {
			free(cpuids);
               	        perror("lgrp_cpus");
			return (-1);
		}
		for (i = 0; i &lt; ncpus; i++)
			printf("%d ", cpuids[i]);
		free(cpuids);
	}
	printf("\n");

	/*
	 * Get memory size
	 */
	printf("\tMEMORY: ");
	size = lgrp_mem_size(cookie, lgrp, LGRP_MEM_SZ_INSTALLED, content);
	if (size == -1) {
		perror("lgrp_mem_size");
		return (-1);
	}
	printf("installed bytes 0x%llx, ", size);
	size = lgrp_mem_size(cookie, lgrp, LGRP_MEM_SZ_FREE, content);
        if (size == -1) {
		perror("lgrp_mem_size");
		return (-1);
	}
	printf("free bytes 0x%llx\n", size);

	/*
	 * Get parents
	 */
	nparents = lgrp_parents(cookie, lgrp, NULL, 0);
	printf("\t%d PARENTS: ", nparents);
	if (nparents == -1) {
		perror("lgrp_parents");
		return (-1);
	} else if (nparents > 0) {
		parents = malloc(nparents * sizeof (lgrp_id_t));
		nparents = lgrp_parents(cookie, lgrp, parents, nparents);
               	if (nparents == -1) {
			free(parents);
                        perror("lgrp_parents");
			return (-1);
               	}
		for (i = 0; i &lt; nparents; i++)
			printf("%d ", parents[i]);
		free(parents);
	}
	printf("\n");

	/*
	 * Get children
	 */
	nchildren = lgrp_children(cookie, lgrp, NULL, 0);
	printf("\t%d CHILDREN: ", nchildren);
	if (nchildren == -1) {
		perror("lgrp_children");
		return (-1);
	} else if (nchildren > 0) {
		children = malloc(nchildren * sizeof (lgrp_id_t));
		nchildren = lgrp_children(cookie, lgrp, children, nchildren);
               	if (nchildren == -1) {
			free(children);
                        perror("lgrp_children");
			return (-1);
               	}
		printf("Children: ");
		for (i = 0; i &lt; nchildren; i++)
			printf("%d ", children[i]);
		printf("\n");

		for (i = 0; i &lt; nchildren; i++)
			lgrp_walk(cookie, children[i], content);

		free(children);
	}
	printf("\n");

	return (0);
}</programlisting>
</example><example id="lgroups-ex-50"><title>Find the Closest lgroup With Available
Memory Outside a Given lgroup</title><programlisting>#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;sys/lgrp_user.h>
#include &lt;sys/types.h>


#define	INT_MAX	2147483647


/*
 * Find next closest lgroup outside given one with available memory
 */
lgrp_id_t
lgrp_next_nearest(lgrp_cookie_t cookie, lgrp_id_t from)
{
	lgrp_id_t          closest;
	int                i;
	int                latency;
	int                lowest;
	int                nparents;
	lgrp_id_t          *parents;
	lgrp_mem_size_t    size;


	/*
	 * Get number of parents
	 */
	nparents = lgrp_parents(cookie, from, NULL, 0);
	if (nparents == -1) {
		perror("lgrp_parents");
		return (LGRP_NONE);
	}

	/*
	 * No parents, so current lgroup is next nearest
	 */
	if (nparents == 0) {
		return (from);
	}

	/*
	 * Get parents
	 */
	parents = malloc(nparents * sizeof (lgrp_id_t));
	nparents = lgrp_parents(cookie, from, parents, nparents);
	if (nparents == -1) {
		perror("lgrp_parents");
		free(parents);
		return (LGRP_NONE);
        }

	/*
	 * Find closest parent (ie. the one with lowest latency)
	 */
	closest = LGRP_NONE;
	lowest = INT_MAX;
	for (i = 0; i &lt; nparents; i++) {
		lgrp_id_t	lgrp;

		/*
		 * See whether parent has any free memory
		 */
		size = lgrp_mem_size(cookie, parents[i], LGRP_MEM_SZ_FREE,
		    LGRP_CONTENT_ALL);
		if (size > 0)
			lgrp = parents[i];
		else {
			if (size == -1)
				perror("lgrp_mem_size");

			/*
			 * Find nearest ancestor if parent doesn't
			 * have any memory
			 */
			lgrp = lgrp_next_nearest(cookie, parents[i]);
			if (lgrp == LGRP_NONE)
				continue;
		}

		/*
		 * Get latency within parent lgroup
		 */
		latency = lgrp_latency_cookie(lgrp, lgrp);
		if (latency == -1) {
			perror("lgrp_latency_cookie");
			continue;
		}

		/*
		 * Remember lgroup with lowest latency
		 */
		if (latency &lt; lowest) {
			closest = lgrp;
			lowest = latency;
		}
	}

	free(parents);
	return (closest);
}


/*
 * Find lgroup with memory nearest home lgroup of current thread
 */
lgrp_id_t
lgrp_nearest(lgrp_cookie_t cookie)
{
	lgrp_id_t	home;
	longlong_t	size;

	/*
	 * Get home lgroup
	 */
	home = lgrp_home(P_LWPID, P_MYID);

	/*
	 * See whether home lgroup has any memory available in its hierarchy
	 */
	size = lgrp_mem_size(cookie, home, LGRP_MEM_SZ_FREE,
	    LGRP_CONTENT_ALL);
	if (size == -1)
		perror("lgrp_mem_size");

	/*
	 * It does, so return the home lgroup.
	 */
	if (size > 0)
		return (home);

	/*
	 * Otherwise, find next nearest lgroup outside of the home.
	 */
	return (lgrp_next_nearest(cookie, home));
}</programlisting>
</example><example id="lgroups-ex-51"><title>Find Nearest lgroup With Free Memory</title><para>This example code finds the nearest lgroup with free memory to a given
thread's home lgroup.</para><programlisting>lgrp_id_t
lgrp_nearest(lgrp_cookie_t cookie)
{
        lgrp_id_t         home;
        longlong_t        size;

        /*
         * Get home lgroup
         */

        home = lgrp_home();

        /*
         * See whether home lgroup has any memory available in its hierarchy
         */

        if (lgrp_mem_size(cookie, lgrp, LGRP_MEM_SZ_FREE,
            LGRP_CONTENT_ALL, &amp;size) == -1)
                perror("lgrp_mem_size");

        /*
         * It does, so return the home lgroup.
         */

        if (size > 0)
                return (home);

        /*
         * Otherwise, find next nearest lgroup outside of the home.
         */

        return (lgrp_next_nearest(cookie, home));
}</programlisting>
</example>
</sect1>
</chapter>