交易记忆简介
事务性存储是二十多年前在学术界首次提出的功能,它是一种在任意一组存储位置上启用原子操作的机制。 它旨在简化并行编程,特别是用于跨多个线程访问共享数据。
在事务存储之前,通过使用锁来同步对共享数据的访问。 需要访问共享数据的线程代码必须首先获取数据锁,然后访问共享数据,然后释放该锁。 在许多系统上,获取锁可能很昂贵,这使得访问共享数据的过程比访问非共享数据的过程要昂贵得多。 当共享数据在多个线程之间的争用较低时,此附加锁定可能会特别麻烦。 事务性内存的主要用途之一是通过使用基于锁的关键部分的推测性执行来加快基于锁的程序的速度,而无需先获取锁。 这使得尚未针对性能进行仔细调整的应用程序可以利用细粒度锁定的优势。 在开发基于锁的共享内存程序时,事务编程模型还可以提高生产率。
硬件事务性内存支持
鉴于在硬件中实现事务存储的成本很高,因此研究团体开发了几种软件事务存储的实现。 尽管近年来在实用和高效的软件事务存储方面取得了重大进展,但越来越多的共识认为,需要一些对事务存储的硬件支持。
IBM率先推出了使用硬件事务存储器的商用微处理器。 从2011年开始,在IBM Blue Gene / Q系统上,事务性内存模型在硬件中实现,以访问最大16 GB边界的所有内存。 IBM POWER8是最新的IBM Power Systems™处理器(在本出版物发行时),包含对硬件事务性内存的支持,这是一项重要的性能功能。 IBM POWER8处理器支持IBM AIX,IBM i和Linux。
IBM XL编译器上的硬件事务性内存固有功能支持
IBM XL编译器使用最新的POWER8架构的功能。 在用于AIX V15.1的IBM XL Fortran和用于AIX V13.1的XL C / C ++中,引入了一组POWER8事务内存内置函数,以支持POWER8处理器中的硬件事务内存功能。
在用于AIX的IBM XL Fortran中,引入了TRANSACTIONAL_MEMORY内部模块。 该模块提供的功能允许您指定要原子处理的指令或语句块。 这样的原子块称为事务。 当一个线程运行一个事务时,从其他线程的角度来看,该事务内的所有内存操作都同时发生。 对于某些并行程序,事务实现可能比其他实现方法(例如锁)更高效。 这些内在过程可用于标记事务的开始和结束以及诊断失败的原因。
TRANSACTIONAL_MEMORY模块提供以下过程:
- 交易开始和结束功能
- 事务中止功能
- 交易查询功能
在成功调用TM_BEGIN或TM_SIMPLE_BEGIN之后,进入事务状态,并以TM_END,TM_ABORT,TM_NAMED_ABORT或由于事务失败而结束。
满足以下任一条件时,将发生事务失败:
- 在事务完成之前,由另一个线程访问处于事务状态的内存。
- 超出了事务中内存访问的体系结构定义的占用空间。
- 超出了嵌套事务的体系结构定义的嵌套限制。
事务可以嵌套。 可以在事务状态下使用TM_BEGIN或TM_SIMPLE_BEGIN。 在以TM_BEGIN发起的最外部事务中,必须使用TM_SIMPLE_BEGIN或TM_BEGIN使用包含最外部事务的相同缓冲区来发起嵌套事务。 嵌套事务包含在包含事务中。 因此,嵌套事务的失败被视为所有包含事务的失败,并且嵌套事务仅在所有包含事务完成时才完成。
类似地,在用于AIX的IBM XL C / C ++中,引入了一组事务性内存内置函数,包括事务BEGIN,END和ABORT函数。
在事务性内存内置函数中, TM_buff
参数允许用户提供一个内存位置来存储事务状态和调试信息。 在成功调用__TM_begin
或__TM_simple_begin
进入事务状态,并以__TM_end
, __TM_abort
, __TM_named_abort
或事务失败来结束。
事务可以嵌套。 __TM_begin
或__TM_simple_begin
可以在事务状态下使用。 在使用__TM_begin
启动的最__TM_begin
事务中,嵌套事务必须使用__TM_simple_begin
或__TM_begin
使用包含最__TM_begin
的相同缓冲区启动。 嵌套事务包含在包含事务中。 因此,嵌套事务的失败被视为所有包含事务的失败,并且嵌套事务仅在所有包含事务完成时才完成。
硬件事务性内存内置示例
本节提供了使用Fortran和C / C ++语言的示例。 这些示例说明了如何使用硬件事务性内存内置功能进行事务的开始和结束,以及如何确定可能失败的原因。
IBM XL Fortran
以下是Fortran语言的硬件事务内置内存内置函数的示例代码:
清单1. Fortran硬件事务性内存内置函数的示例代码
! HTM_demo.f: an example of using HTM built-in
program main
use transactional_memory
implicit none
type(tm_buff_type) tstatus
integer :: arr1(5), arr2(5), i
integer(8) :: rc_failcode
! Initialize both array with same element
do i = 1, 5
arr1(i) = i
arr2(i) = i
end do
if (tm_begin(tstatus) == tm_success) then
! Transaction started successfully
arr1(3) = 0
arr2(3) = 0
if (tm_end() /= tm_success) then
print *, 'transaction end fail'
error stop 1
end if
else
! Transaction has failure, print failure code
rc_failcode = tm_failure_code(tstatus)
print *, 'transaction failed, failure code is:', rc_failcode
error stop 2
end if
print *, arr1
print *, arr2
! Verify each element of this array is still identical
do i = 1, 5
if (arr1(i) .NE. arr2(i)) then
print *, 'No.', i, ' element is not identical'
error stop 3
end if
end do
end program
当程序在一系列操作中遇到故障时,它可能会使函数处于半完成状态,因此会使数据处于意外状态。 在此示例中,两个数组都使用相同的元素初始化。 使用硬件事务性内存内置功能,无论事务成功与否,都可以确保两个阵列的状态一致。 交易后,每个元素都是相同的。
要编译和运行上述代码,必须首先确保在带有POWER8处理器的AIX系统上正确安装和配置XL Fortran for AIX V15.1。 有关更多信息,请参阅《 XL Fortran安装指南》 。
运行以下命令来编译示例代码:
xlf2003 HTM_demo.f
生成可执行文件a.out
。 要运行该程序,请在命令行上输入a.out
,您将看到如图1所示的结果。
图1. Fortran示例代码的输出
IBM XL C / C ++
以下是C语言的硬件事务内置内存内置函数的示例代码:
清单2. C ++硬件事务性内存内置函数的示例代码
#include <builtins.h>
#include <stdio.h>
char buf[256] __attribute__((aligned(8)));
unsigned long long zero = 0;
int main(void)
{
long rc_begin, rc_end, i;
long arr1[5], arr2[5];
unsigned long long rc_buf;
rc_begin = rc_end = -1;
// Initialize both array with same element
for (i = 0; i < 5; i++)
{
arr1[i] = arr2[i] = i;
}
if ( (rc_begin = __TM_begin(buf)) == 0 )
{
// Transaction started successfully
arr1[2] = 0;
arr2[2] = 0;
if ( (rc_end = __TM_end()) != 0 )
{
printf("the transaction failed\n");
return 1;
}
}
else
{
if (__TM_failure_code(buf) == zero)
{
printf("The transaction failed, but an abort is not reported in the buffer\n");
return 2;
}
}
for (i = 0; i < 5; i++) printf("arr1[%ld] = %ld; ", i, arr1[i]);
printf("\n");
for (i = 0; i < 5; i++) printf("arr2[%ld] = %ld; ", i, arr2[i]);
printf("\n");
// Verify each element of this array is still identical
for (i = 0; i < 5; i++)
{
if (arr1[i] != arr2[i])
{
printf("No. %ld element is not identical", i);
return 3;
}
}
}
同样,要编译和运行上述代码,必须首先确保在具有POWER8处理器的AIX系统上正确安装和配置了用于AIX V13.1的XL C / C ++。 有关更多信息,请参阅XL C / C ++安装指南 。
运行以下命令来编译示例代码:
xlc HTM_demo.c
生成可执行文件a.out
。 要运行该程序,请在命令行上输入a.out
,您将看到如图2所示的结果。
图2. C / C ++示例代码的输出
翻译自: https://www.ibm.com/developerworks/aix/library/au-aix-ibm-xl-compiler-built-in-functions/index.html