当前位置: 首页 > 工具软件 > OpenBLAS > 使用案例 >

OpenBLAS多线程使用教程

斜浩穰
2023-12-01

OpenBLAS 的编译运行可参考:https://github.com/xianyi/OpenBLAS/blob/develop/USAGE.md

函数参考:http://netlib.org/blas/

一、BLAS函数接口命名规范(可根据这个找到要调用的函数名称):

该部分转自:https://blog.csdn.net/cocoonyang/article/details/63068108

(1)根据运算对象不同,分为三个类

Level1:

Level 1 函数处理单一向量的线性运算以及两个向量的二元运算。
接口函数名称由前缀+操作简称组成。
例如:SROTG,其中:
            S         -- 标明矩阵或向量中元素数据类型的前缀;
            ROTG -- 向量运算简称。

Level2和Level3:

Level 2 函数处理 矩阵与向量的运算,同时也包含线性方程求解计算。
Level 3 函数包含矩阵与矩阵运算。
接口函数名称由前缀 + 矩阵类型 + 操作简称组成。
例如: SGEMV,其中:
            S      -- 标明矩阵或向量中元素数据类型的前缀;
            GE   -- 矩阵类型
            MV   -- 向量或矩阵运算简称

(2)BLAS库使用的矩阵类型

  GE - GEnearl  稠密矩阵
  GB - General Band 带状矩阵

  SY - SYmmetric    对称矩阵
  SB - Symmetric Band 对称带状矩阵
  SP - Symmetric Packed  压缩存储对称矩阵

  HE - HEmmitian     Hemmitian矩阵,自共轭矩阵
  HB - Hemmitian Band   带状Hemmitian矩阵
  HP - Hemmitian Packed  压缩存储Hemmitian矩阵

  TR - TRiangular      三角矩阵
  TB - Triangular Band  三角带状矩阵
  TP - Triangular Packed  压缩存储三角矩阵


二、函数中参数的含义

以下为 openblas 中双精度稠密矩阵向量乘函数,计算式为 y=alpha*A*x+beta*y

void cblas_sgemv(
    OPENBLAS_CONST enum CBLAS_ORDER order,          	//CblasRowMajor或者CblasColMajor(行主序或列主序,默认为行)
    OPENBLAS_CONST enum CBLAS_TRANSPOSE trans,      	//CblasNoTrans或者CblasTrans(矩阵不转置或者转置,需要时会自动转置)
    OPENBLAS_CONST blasint m,             //矩阵行数
    OPENBLAS_CONST blasint n,             //矩阵的列数
    OPENBLAS_CONST float alpha,           //y=alpha*A*x+beta*y中的alpha
    OPENBLAS_CONST float  *a,             //A矩阵的缓冲区首地址
    OPENBLAS_CONST blasint lda,           //A矩阵的列数
    OPENBLAS_CONST float  *x,             //x向量的缓冲区首地址
    OPENBLAS_CONST blasint incx,          //x里面每次跳跃累加的个数,默认为1
    OPENBLAS_CONST float beta,            //y=alpha*A*x+beta*y中的beta
    float  *y,                            //y的缓冲区首地址
    OPENBLAS_CONST blasint incy           //y里面每次跳跃累加的个数,默认为1
    )

三、运行OpenBLAS程序

我是在 Linux 下编译运行的,需要自己链接,过程如下:

1.编译:

gcc ./dgemv_test.c -I/opt/software/libopenblas/include -L/opt/software/libopenblas/lib -o ./dgemv_test.out -lopenblas -lpthread 
(多线程需要链接到pthread)

其中:-I(大写i)后面为 OpenBLAS 所需头文件 <cblas.h> 所在的目录;-L后面为 OpenBLAS 的库文件所在的目录。

2.设置线程数:

在环境变量中设置线程数为n(自己取值,取1为单线程):

export OPENBLAS_NUM_THREADS=4(已确认可行)。

3.运行:

./dgemv_test.out

注:该网站(https://github.com/xianyi/OpenBLAS/blob/develop/USAGE.md)给出了另外两种单线程方法,推测同理可设置多线程,但是没有继续尝试。

可以将23步改成:

a. make USE_THREAD=4(4自己设置线程数,取0为单线程)
b. ./dgemv_test.out openblas_set_num_threads2(2自己设置线程数,取1为单线程

 

附上自己测试时候的代码。

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <cblas.h>
#include <sys/time.h>
#define BUF_SIZE (1024)
char buf[BUF_SIZE];
int main(int argc, char** argv) {
    //读取矩阵数据
    long long n, m, num_items,indx;
    int row, col;
    double val;
    bool flag = false;
    double *matrix;
    FILE* fd = fopen(argv[1], "r");
    while (fgets(buf, BUF_SIZE, fd)) {
        if (buf[0] == '%') continue;
        if (flag) {
            sscanf(buf, "%d %d %le", &row, &col, &val);
            indx = (row-1)*m+(col-1);
            matrix[indx] = val;
        }
        else {
            sscanf(buf, "%lld %lld %lld", &n, &m, &num_items);
            long long nm = n * m * sizeof(double);
            matrix = (double*)malloc(nm);
            flag = true;
        }
    }
    fclose(fd);
    flag = false;
    
    
    //读取向量
    double *vect_x;
    long long i = 0;
    long long v_n,v_n_size;
    //FILE* fc = fopen(file_vect,"r");
    FILE* fc = fopen(argv[2],"r");
    while (fgets(buf, BUF_SIZE, fc)) {
        if (buf[0] == '%') continue;
        if (flag) {
            sscanf(buf, "%le", &val);
            vect_x[i++] = val;
        }
        else {
            sscanf(buf, "%lld", &v_n);
            v_n_size = v_n * sizeof(double);
            vect_x = (double*)malloc(v_n_size);
            flag = true;
        }
    }
    fclose(fc);
    
    //clock()测量你的进程使用的CPU时间,而不是挂钟时间。当你有多个线程同时运行时,你显然可以更快地消耗CPU时间。    
    //计算时间——开始
    struct timeval start_t,end_t;
    double *y = (double*)malloc(v_n_size);
    int j=0;
    gettimeofday(&start_t, NULL);
    
    //openblas函数计算 
    for(j=0;j<10;j++){
      //矩阵数据行列
      cblas_dgemv(CblasRowMajor, CblasNoTrans, n, m, 1, matrix, m, vect_x, 1, 0, y, 1);
      //矩阵数据列行
      //cblas_dgemv(CblasRowMajor, CblasTrans, n, m, 1, matrix, m, vect_x, 1, 0, y, 1);
      }
    //计算时间——结束
    gettimeofday(&end_t, NULL);
    //计算时间——过程(结束-开始)
    double total_t_sec, total_t_usec, total_t;
    total_t_sec = (double)(end_t.tv_sec - start_t.tv_sec);
    total_t_usec = (double)(end_t.tv_usec - start_t.tv_usec); 
    
    total_t = total_t_sec + total_t_usec / 1000000.0;
    printf("Time spent : %f seconds\n", total_t);

    return 0;
}

 

 类似资料: