Locality Group Affinity
The kernel assigns a thread to a locality group when the light weight
process (LWP) for that thread is created. That lgroup is called the thread's home lgroup. 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.
There are three affinity levels:
LGRP_AFF_STRONG 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
may still result in thread rehoming.
LGRP_AFF_WEAK indicates weak affinity.
If this lgroup is the thread's home lgroup, the operating system rehomes the
thread if necessary for load balancing purposes.
LGRP_AFF_NONE indicates no affinity. If
a thread has no affinity to any lgroup, the operating system assigns the thread
a home lgroup.
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 may restrict the lgroups on which a thread can run.
Using lgrp_affinity_get()
The lgrp_affinity_get() function returns the affinity
that a LWP or set of LWPs have for a given lgroup.
#include <sys/lgrp_user.h>
lgrp_affinity_t lgrp_affinity_get(idtype_t idtype, id_t id, lgrp_id_t lgrp);
|
The idtype and id arguments
specify the LWP or set of LWPs that the lgrp_affinity_get()
function examines. If the value of idtype is P_PID, the lgrp_affinity_get() function gets
the lgroup affinity for one of the LWPs in the process whose process ID matches
the value of the id argument. If the value of idtype is P_LWPID, the lgrp_affinity_get() function gets the lgroup affinity for the LWP of the current process
whose LWP ID matches the value of the id argument.
If the value of idtype is P_MYID,
the lgrp_affinity_get() function gets the lgroup affinity
for the current LWP or process.
The lgrp_affinity_get() function returns EINVAL when the given lgroup, affinity, or ID type is not valid.
The lgrp_affinity_get() function returns EPERM when the effective user of the calling process is not the superuser
and the calling process' ID does not match the real or effective user ID of
one of the LWPs. The lgrp_affinity_get() function returns ESRCH when a given lgroup or LWP is not found.
Using lgrp_affinity_set()
The lgrp_affinity_set() function sets the affinity
that a LWP or set of LWPs have for a given lgroup.
#include <sys/lgrp_user.h>
int lgrp_affinity_set(idtype_t idtype, id_t id, lgrp_id_t lgrp,
lgrp_affinity_t affinity);
|
The idtype and id arguments
specify the LWP or set of LWPs the lgrp_affinity_set()
function examines. If the value of idtype is P_PID, the lgrp_affinity_set() function sets
the lgroup affinity for all of the LWPs in the process whose process ID matches
the value of the id argument to the affinity level
specified in the affinity argument. If the value of idtype is P_LWPID, the lgrp_affinity_set() function sets the lgroup affinity for the LWP of the current process
whose LWP ID matches the value of the id argument to
the affinity level specified in the affinity argument.
If the value of idtype is P_MYID,
the lgrp_affinity_set() function sets the lgroup affinity
for the current LWP or process to the affinity level specified in the affinity argument.
The lgrp_affinity_set() function returns EINVAL when the given lgroup, affinity, or ID type is not valid.
The lgrp_affinity_set() function returns EPERM when the effective user of the calling process is not the superuser
and the calling process' ID does not match the real or effective user ID of
one of the LWPs. The lgrp_affinity_set() function returns ESRCH when a given lgroup or LWP is not found.
Examples of API usage
This section contains code that performs example tasks by using the
APIs that are described in this chapter.
Example 4-7 Move Memory to a Thread
The following code sample moves the memory in the range from the address
specified by addr to the address specified by addr+len to the thread specified by MADV_ACCESS_LWP.
#include <sys/mman.h>
#include <sys/types.h>
/*
* Move memory to thread
*/
mem_to_thread(caddr_t addr, size_t len)
{
if (madvise(addr, len, MADV_ACCESS_LWP) < 0)
perror("madvise");
}
|
Example 4-8 Move a Thread to Memory
This sample code uses the meminfo() function to return
the lgroup of a specified memory page and raises the specified
thread's affinity to that lgroup with the lgrp_affinity_set function().
#include <sys/lgrp_user.h>
#include <sys/mman.h>
#include <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(&addr, 1, &request, 1, &lgrp, &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);
}
|
Example 4-9 Walk the lgroup Hierarchy
The following sample code walks through and prints out the lgroup hierarchy.
#include <stdlib.h>
#include <sys/lgrp_user.h>
#include <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_MYID, 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 < 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 < 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 < nchildren; i++)
printf("%d ", children[i]);
printf("\n");
for (i = 0; i < nchildren; i++)
lgrp_walk(cookie, children[i], content);
free(children);
}
printf("\n");
return (0);
}
|
|