BSR Shared Memory

The barrier synchronization register (BSR) is a hardware facility that efficiently shares small or dense memory regions. The memory regions are updated in parallel by multiple threads.

BSR memory allows the stores to be propagated through the system at a faster rate than normal cached memory. The BSR memory uses cache management semantics that is allocated for a highly parallelized application manipulating a small piece of memory from multiple processors. The cache management semantics is not intended to be used for general-purpose shared memory. This facility is useful for efficiently implementing barrier synchronization constructs that are used in highly parallel workloads.

BSR memory requires specific processor support, and resources must be configured to a logical partition (LPAR) to allow LPAR to use the BSR facility.

To allocate BSR shared memory, follow these steps:
  1. Allocate system V shared memory regions for the BSR shared memory using the shmctl() subroutine.
  2. Request that the allocated system V shared memory region be backed up by BSR memory by using the shmctl() subroutine and specifying the SHM_BSR command.
    Note: The shmctl() subroutine used with the SHM_BSR command is used on a shared memory. This step is performed immediately after the system V shared memory is created by using the shmget() subroutine, and before any process is attached to the shared memory. When the SHM_BSR command is used, the shmctl() subroutine attempts to use BSR memory for the specified shared memory region.
  3. Shows an error, if the available BSR memory is insufficient or the BSR facility is not supported by the hardware platform. The shmget() subroutine fails with errno set to ENOMEM
    Note: A non-root user must have the CAP_BYPASS_RAC_VMM capability to allocate the BSR memory. If a non-root user does not have this capability, the shmctl() subroutine with the SHM_BSR command fails with errno set to EPERM.

When using BSR shared memory, only 1-byte and 2-byte store instructions are permitted to the shared memory region. Store instruction that use more than 2-bytes do not function correctly with BSR shared memory. Load instructions of any size are allowed to BSR shared memory.

The VMINFO command is run on the vmgetinfo() subroutine, which is used to gather information about the BSR support available. When VMINFO command is specified to the vmgetinfo() subroutine, a vminfo struct is returned. The bsr_mem_total field reports the total amount of BSR memory configured to the LPAR. The bsr_mem_free field reports the total amount of BSR that is currently available for allocation.

The BSR shared memory regions cannot be dynamically resized with the SHM_SIZE option to the shmctl() subroutine. If an application attempts to resize a BSR shared memory region by specifying the SHM_SIZE parameter in the shmctl() subroutine, shmctl() fails with errno set to EINVAL. BSR shared memory is not supported with the EXTSHM environment variable. If the EXTSHM environment variable is set, when shmctl() is called with the SHM_BSR flag, shmctl() fails with EINVAL.

Example

The following example shows that an application can query the amount of BSR memory available on a system and then allocate and attach a BSR shared memory region. The example shows how an application would detach and delete a BSR shared memory region.
#include <errno.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/vminfo.h>

/* shm_rgn_size is the size of the shared memory region to
 * allocate. In this example, 4KB (PAGESIZE) is chosen.  4KB is the
 * smallest shared memory region size supported.  It is expected that
 * 4KB should be sufficient for most users of BSR memory.
 */
const size_t shm_rgn_size = PAGESIZE;

int main(int argc, char *argv[])
{
	struct vminfo my_info = { 0 };
	int           id;
	void          *ptr;
	
	/* Determine the amount of BSR memory available */
	if (vmgetinfo(&my_info, VMINFO, sizeof(my_info)) != 0)
	{
		perror("vmgetinfo() unexpectedly failed");
		return 1;
	}

	/* Check to see that sufficient BSR memory is available */
	if (my_info.bsr_mem_free < shm_rgn_size)
	{
		fprintf(stderr, "insufficient BSR memory\n");
		return 2;
	}

	/* Allocate a new shared memory region */
	id = shmget(IPC_PRIVATE, shm_rgn_size, IPC_CREAT|IPC_EXCL);

	if (id == -1)
	{
		perror("shmget() failed");
		return 3;
	}

	/* Request BSR memory for the shared memory region */
	if (shmctl(id, SHM_BSR, NULL))
	{
		perror("shmctl(SHM_BSR) failed");
		shmctl(id, IPC_RMID, 0);
		return 4;
	}
	
	/* Attach the shared memory region */
	ptr = shmat(id, NULL, 0);
	if ((int)ptr == -1)
	{
		perror("shmat() failed");
		shmctl(id, IPC_RMID, 0);
		return 5;
	}

	/* BSR memory can now be accessed starting at address - ptr */

	/* Detach shared memory region */
	if (shmdt(ptr))
	{
		perror("shmdt() failed");
		shmctl(id, IPC_RMID, 0);
		return 6;
	}

	/* Delete shared memory region */
	if (shmctl(id, IPC_RMID, 0))
	{
		perror("shmctl(IPC_RMID) failed");
		return 7;
	}

	return 0;
}