Intel Threading Building Blocks 编程指南 : 内存分配

来源:互联网 发布:淘宝网户外刀 编辑:程序博客网 时间:2024/06/01 19:26

(原文出自 tbb tutorial ,也许稍有改动。)

Intel Threading Building Blocks(Intel TBB)提供了两种与STL模板类(std::allocator)类似的内存分配器模板。这两类模板(scalable_allocator<T>、cache_aligned_allocator<T>)解决并行编程中的如下关键问题:

  • 可伸缩性    当在线程中使用原本为串行编程而设计的内存分配器因单个同一时间只允许一个线程分配的共享池而竞争的时候,可伸缩性的问题就会凸显。使用内存分配模板scalable_allocator<T>来避免此类可伸缩性瓶颈。这个模板可以提升急速分配、释放内存程序的性能。
  • 伪共享   当两个线程访问同一缓存行的不同字节时,伪共享的问题就会出现。这是因为,缓存行(cache line)是不同处理器缓存间交换信息的单位。如果一个处理器修改了一个缓存行而另外一个处理器读(或者写)同一个缓存行,那么它必须从一个处理器移动到另外一个处理器,即使两个处理处理的是这行内的不同字节。因为缓存行的移动会耗费数百个时钟周期,伪共享会损害性能。

使用cache_aligned_allocator<T>类在某个缓存行分配。两个使用cache_aligned_allocator分配的对象能被确保不会使用伪共享。如果一个对象使用cache_aligned_allocator<T>分配,而另外一个对象使用了不同的方式,就没有了这种保证。cache_aligned_allocator<T>的接口类似std::allocator,所以你可以将它作为allocator参数传递给STL的模板类。

下面的代码展示了如何声明一个使用cache_aligned_allocator作为分配器的STL vector:

std::vector<int,cache_aligned_allocator<int> >;

cache_aligned_allocator<T>的设计功能的实现伴随着空间开销,因为它必须至少分配一条缓存行占用的内存,即使是对很小的对象。所以,如果伪共享不成问题,就别使用cache_aligned_allocator<T>。可伸缩内存分配器包含了Intel的PSL CTG团队开发的McRT技术。

动态库的选择

scalable_allocator<T>模板需要Intel TBB 可伸缩内存分配器库。它并不需要Intel TBB的常规库,并且能与Intel TBB独立开来使用。如果没有指定可伸缩分配器库,模板tbb_allocator<T>、cache_aligned_allocator<T>就会使用malloc、free等标准库提供的内存分配函数。因此,甚至可以在忽略可伸缩内存分配器库的应用中使用这些模板。Intel Threading Building Blocks的其余部分,有没有Intel TBB可伸缩内存分配器库都可以使用。

模板与库模板
需求
注意事项
scalable_allocator<T>
Intel TBB可伸缩内存分配器库

tbb_allocator<T>、cache_aligned_allocator<T>

如果没有指定TBB库,就使用malloc、free

自动替换malloc等C/C++动态内存分配函数

在windows、Linux操作系统中,可以自动使用Intel TBB中相应的可伸缩实现替换所有标准动态内存分配函数调用(比如:malloc)。在一些场合,可以提升性能。

Linux C/C++动态内存借口替换

替换通过代理库(release:libtbbmalloc_proxy.so.x、debug:libtbbmalloc_proxy_debug.so.x)提供。替换行为可以通过运行时加载代理库(通过LD_PRELOAD)或者链接(linking)代理库实现。代理库实现了以下动态内存函数:

  • C library:malloc,calloc,realloc,free
  • 标准POSIX函数:posix_memalign
  • 废弃的函数:valloc,memalign,pvalloc,mallopt
  • 全局C++操作符:new、delete

动态加载时,要保证代理库以及相应的可伸缩内存分配器库可被访问。要做到这点,可通过在LD_LIBRARY_PATH中包含或者将其加入到/etc/ld.so.conf中(关于Linux下动态库的搜索路径,可参考)

替换存在以下限制:

  • 无法应用于使用非标准调用glibc的内存分配器的程序
  • 不支持Mono(一种跨平台的.net环境实现)

例:

下面是一个如何设置LD_PRELOAD以及链接程序使用替换的例子。

# Set LD_PRELOAD so that loader loads release version of proxy LD_PRELOAD=libtbbmalloc_proxy.so.2 # Link with release version of proxy and scalable allocator g++ foo.o bar.o -ltbbmalloc_proxy -ltbbmalloc -o a.out

使用Debug版本的库:

# Set LD_PRELOAD so that loader loads debug version of proxy LD_PRELOAD=libtbbmalloc_proxy_debug.so.2 # Link with debug version of proxy and scalable allocator g++ foo.o bar.o -ltbbmalloc_proxy_debug -ltbbmalloc_debug -o a.out


windows下C++动态内存接口替换

替换通过代理库(release:tbbmalloc_proxy.dll,debug:tbbmalloc_debug_proxy.dll)提供。能以下面的任一种方式实现:

  • 包含头文件 #include "tbb/tbbmalloc_proxy.h"
  • 设置链接参数 

         对于32位代码:tbbmalloc_proxy.lib /INCLUDE:"___TBB_malloc_proxy"  (三个下划线)

         对于64位代码:tbbmalloc_proxy.lib /INCLUDE:"__TBB_malloc_proxy"      (两个下划线)

代理库实现了下面的动态内存函数:

  • 标准C运行时动态内存函数:malloc,calloc,realloc,free
  • 全局C++操作符:new,delete
  • Microsoft C运行时库函数:_msize

同样要保证代理库、可伸缩内存分配库在程序启动时能被加载,例如,可将其路径包含在%PATH%环境变量中。

0 0
原创粉丝点击