主要摘录《结构化并行程序设计》(Structured Parallel Programming) 中关于 TBB(现为oneTBB) 的一些知识和代码,并添加了一些其他东西。

安装

Intel TBB 安装可直接在 github 搜索 tbb,clone 下载后 cmake 安装即可,本文编写时(2021.7.12)tbb 已位于 oneapi 下:oneTBB,安装可参考:Intel TBB库+CMake+Ubuntu配置流程

Debian/Ubuntu 系列可直接安装

sudo apt install libtbb-dev libtbb-doc libtbb2

oneTBB 中 example 目录里有不少参考代码,整个 oneapi 的参考 demo 可以参见 oneAPI-samples,其中包含使用 GPU+CPU 的 TBB 代码。此外,目标大一统的 oneapi 也支持 FPGA 等,值得关注。

测试代码如下:

#include <iostream>
#include <tbb/tbb.h>

int main() {
  tbb::parallel_for(0, 100, 1, [](int i) {
    std::cout << i << std::endl;
    std::cout << "Hello World!" << std::endl;
  });

  return 0;
}

节选结果如下,可见乱序输出

Hello World!
28
Hello World!
66
Hello World!
98
Hello World!
Hello World!
Hello World!

Hello World!
Hello World!
60
Hello World!

SAXPY

SAXPY 的数学定义为

$$ \bm{y} \leftarrow a\bm{x}+\bm{y} $$

串行版本:

#include <cstdlib>
void saxpy_serial(
    size_t n,
    float a,
    const float x[],
    float y[])
{
    for (size_t i = 0; i < n; ++i)
        y[i] = a * x[i] + y[i];
}

TBB 版本,分块得到的每个子区间 r 由独立任务处理。

#include <cstdlib>
#include <tbb/tbb.h>
void saxpy_tbb(
    size_t n,
    float a,
    const float x[],
    float y[])
{
    tbb::parallel_for(
        tbb::blocked_range<int>(0, n),
        [&](tbb::blocked_range<int> r) {
            for (size_t i = r.begin(); i != r.end(); ++i)
                y[i] = a * x[i] + y[i];
        });
}

点积

数学定义:

$$ \bm{a} \cdot \bm{b} = \sum_{i=0}^{n-1}{a_i b_i} $$

串行版本

#include <cstdlib>
float sprod(
    size_t n,
    const float a[],
    const float b[])
{
    float res = 0.0f;
    for (size_t i = 0; i < n; i++)
    {
        res += a[i] * b[i];
    }
    return res;
}

TBB 单精度版本

#include <cstdlib>
#include <functional> // std::plus, std::divides
#include <numeric>    // std::inner_product
#include <tbb/tbb.h>
float sprod_tbb(
    size_t n,
    const float a[],
    const float b[])
{
    return tbb::parallel_reduce(
        tbb::blocked_range<size_t>(0, n),
        float(0),
        [=](
            tbb::blocked_range<size_t> &r,
            float in) {
            return std::inner_product(a + r.begin(), a + r.end(), b + r.begin(), in);
        },
        std::plus<float>());
}

TBB 提升到双精度版本

double sprod_tbb2(size_t n, const float a[], const float b[]) {
  return tbb::parallel_reduce(
      tbb::blocked_range<size_t>(0, n), double(0),
      [=](tbb::blocked_range<size_t> &r, double in) {
        return std::inner_product(a + r.begin(), a + r.end(), b + r.begin(), in,
                                  std::plus<double>(),
                                  std::multiplies<double>());
      },
      std::plus<double>());
}

注:来自书中的代码版权满足以下版权声明

Copyright (c) 2012 Michael McCool, Arch Robison, and James Reinders.
All rights reserved.

Alkaid
1 声望0 粉丝