高性能计算实验——矩阵乘法基于OpenMP的实现及优化

2023-11-09

1.实验目的

1.1.通过OpenMP实现通用矩阵乘法

熟练掌握OpenMP原理,完成通用矩阵乘法的OpenMP实现,为后续实验打下基础。

1.2.基于OpenMP的通用矩阵乘法优化

进一步熟悉OpenMP的任务调度机制,分别采用OpenMP的默认任务调度机制、静态调度和动态调度实现#pragma omp for,比较性能。

1.3.构造基于Pthreads的并行for循环分解、分配和执行机制

学习Pthreads多线程库提供的函数,构建parallel_for 函数对循环分解、分配和执行机制,将基于 OpenMP 的通用矩阵乘法的omp parallel for 并行,改造成基于parallel_for 函数并行化的矩阵乘法。

2.实验过程和核心代码

2.1.通过OpenMP实现通用矩阵乘法

2.1.1.问题描述
通过OpenMP 实现通用矩阵乘法(实验1)的并行版本,OpenMP 并行线程从 1 增加至 8,矩阵规模从 512 增加至 2048。
通用矩阵乘法(GEMM)通常定义为:
C = AB
输入:M , N, K 三个整数(512 ~2048)
问题描述:随机生成 MN 和NK 的两个矩阵 A,B,对这两个矩阵做乘法得到矩阵 C.
输出:A,B,C 三个矩阵以及矩阵计算的时间

2.1.2.实现过程
这里可以根据GEMM公式进行核心代码矩阵乘法部分的实现,将OpenMP多线程的核心#pragma omp parallel制导语句加在函数前面。

#pragma omp parallel num_threads(thread_count)
  • #pragma omp pallel
    使用parallel是用来表明之后的结构化代码块(一个结构化代码块时一条C语句或者只有一个入口和一个出口的一组复合C语句)应该被多个线程并行执行。完成代码块前会有一个隐式路障,先完成的线程必须等待线程组其他线程完成代码块。
  • num_threads 子句
    允许程序员指定执行后代码块的线程数,程序可以启动的线程数可能会受系统定义的限制。OpenMP标准并不保证实际能够启动thread_count个线程。

输入方面根据输入的矩阵信息分配对应的空间并产生随机数。

2.1.3.核心代码
①矩阵生成

void Gen_Matrix(){
    for(int i=0;i<M;i++){
        for(int j=0;j<N;j++){
            a[i][j] = rand()%10;
        }}
    for(int i=0;i<N;i++){
        for(int j=0;j<K;j++){
            b[i][j] = rand()%10;
        }}
}

②矩阵乘法
在这里插入图片描述
首先需要获取线程编号,根据编号得到起始和结束行,这里按照a矩阵的行数M进行线程任务划分。

③Main函数主要代码
在这里插入图片描述
首先计算出每个线程的执行的行数,接着将制导语句#pragma omp parallel标在函数前表示使用多线程并行执行。

2.2.通用矩阵乘法优化

2.2.1.问题描述
分别采用OpenMP 的默认任务调度机制和静态调度schedule(static, 1) 和动态调度schedule(dynamic,1)的性能,实现#pragma omp for,并比较其性能。

2.2.2.实现过程

  • #pragma omp for:
    #pragma omp parallel for是OpenMP中的一个指令,表示接下来的for循环将被多线程执行,另外每次循环之间不能有关系。
  • OpenMP的任务调度机制:
    OpenMP中,任务调度主要用于并行的for循环中,当循环中每次迭代的计算量不相等时,如果简单地给各个线程分配相同次数的迭代的话,会造成各个线程计算负载不均衡,这会使得有些线程先执行完,有些后执行完,造成某些CPU核空闲,影响程序性能。
  • schedule的使用格式为:
    schedule(type[,size])
    schedule有两个参数:type和size,size参数是可选的。
    • 静态调度(static) #pragma omp parallel for schedule(static, N)
      当parallel for编译指导语句没有带schedule子句时,大部分系统中默认采用static调度方式,这种调度方式非常简单。假设有n次循环迭代,t个线程,那么给每个线程静态分配大约n/t次迭代计算。
    • 动态调度(dynamic) #pragma omp parallel for schedule(dynamic, N)
      动态调度是动态地将迭代分配到各个线程,动态调度可以使用size参数也可以不使用size参数,不使用size参数时是将迭代逐个地分配到各个线程,使用size参数时,每次分配给线程的迭代次数为指定的size次。

2.2.3.核心代码
静态调度大致与任务一类似,制导语句以及位置改变:
在这里插入图片描述
制导语句从函数上移动到for循环上,此时不需要像是任务1需要在函数内进行需要处理的行数计算,这是根据调度策略自动决定的。
Static调度:
在这里插入图片描述
Dynamic调度:
在这里插入图片描述
可以看到只需要修改制导语句即可。

2.3.大规模矩阵计算优化

2.3.1.问题描述

  • 基于pthreads 的多线程库提供的基本函数,如线程创建、线程join、线程同步等。构建parallel_for 函数对循环分解、分配和执行机制,函数参数包括但不限于(int start, int end, int increment, void *(functor)(void), void *arg , in num_threads);其中 start 为循环开始索引;end 为结束索引; increment 每次循环增加索引数;functor 为函数指针,指向的需要被并行执行循环程序块;arg 为 functor 的入口参数; num_threads 为并行线程数。
  • 在Linux 系统中将parallel_for 函数编译为.so 文件,由其他程序调用。
  • 将基于 OpenMP 的通用矩阵乘法的omp parallel for 并行,改造成基于parallel_for 函数并行化的矩阵乘法,注意只改造可被并行执行的 for 循环(例如无 race condition、无数据依赖、无循环依赖等。

2.3.2.实现思想
这里我的理解比较简单,只要自己完成parallel_for函数(实现for循环Pthreads并行化),在parallel_for函数内完成分行(划分任务),创建任务,分配任务给线程执行即可。
将parallel_for函数打包为.so文件,在调用该函数时需要指定线程的工作函数,所以需要自己完成functor函数,较为简单,直接完成矩阵乘法就行。

2.3.3.核心代码
①Parallel_for函数
这里需要根据总行数和线程数进行划分,有可能出现不均匀的情况,所以划分的时候需要注意最后一个线程要处理的行数。之后为划分后的任务创建工作线程。
在这里插入图片描述

②For_index结构体
在这里插入图片描述
这个结构体用于表示线程需要处理的工作行数和跨度。(这里的跨度其实可以实现的很灵活,比如在矩阵乘法的最内层进行for_parallel函数调用时可以通过指定跨度轻松实现矩阵乘法)

③Functor函数
在这里插入图片描述
这里就是简单的将线程需要的行数从结构体中拿出来之后进行矩阵乘法。
在这里插入图片描述
Main函数里只需要调用parallel_for函数即可。

3.实验结果

3.1.基于OpenMP实现通用矩阵乘法

在这里插入图片描述
可以看到,计算结果正确;
矩阵大小从512-1024,线程从1~8所需要的时间:
在这里插入图片描述
可以看到线程在2到4时效率有明显提升,但是4至8却没有,主要原因还是虚拟机核心数不足。

3.2.基于OpenMP的通用矩阵优化

这里为了体现出OpenMP的任务调度机制,选择使用2线程。
在这里插入图片描述
可以看到static和dynamic差距并不大,我觉得是矩阵乘法任务本身for循环中的计算量大致相同的原因。

3.3.构造基于 Pthreads 的并行 for 循环分解、分配和执行机制。

在这里插入图片描述
成功生成.so文件;
在这里插入图片描述
成功生成可执行文件;
在这里插入图片描述
执行结果正确。

4.实验感想

本次实验是高性能实验OpenMP部分,由简入深掌握了OpenMP大致内容,同时任务三提高了实验的难度,更好的锻炼了编程能力。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高性能计算实验——矩阵乘法基于OpenMP的实现及优化 的相关文章

  • 使用 C++、libpng 和 OpenMP 并行化 PNG 文件创建

    我目前正在尝试在 C 中实现一个基于 libpng 的 PNG 编码器 它使用 OpenMP 来加速压缩过程 该工具已经能够从各种图像格式生成 PNG 文件 我将完整的源代码上传到pastebin com 这样你就可以看到我到目前为止所做的
  • 如何在python中将MPI信息传递给ctypes

    我的动机是将 MPI 信息有效地从 python 传递到通过 ctypes 调用的 C 函数 我在 python 中使用 mpi4py 进行 MPI 绑定 我想通过一个用 C 编写并通过 python 中的 ctypes 调用的简单示例 M
  • Xcode C++ omp.h 文件未找到

    我正在尝试将 openmp 包含到我的 Xcode C 项目中 我已将 Xcode 中的编译器更改为 LLVM GCC 4 2 添加 fopenmp 作为 CFlag 并在 xcode 中启用了 OpenMP 支持 但它仍然显示 omp h
  • c openmp并行用于并行区域内

    我的问题是这样的one https stackoverflow com questions 11493265 for loop inside parallel region 但我想做一些不同的事情 例如 在我的并行区域内 我想在 4 个线程
  • R 在 HPC MPIcluster 上运行 foreach dopar 循环

    我可以访问带有 MPI 分区的 HPC 集群 我的问题是 无论我尝试什么 我的代码 在我的 PC 上运行良好 都无法在 HPC 集群上运行 代码如下所示 图书馆 TM 图书馆 qdap 图书馆 雪 图书馆 doSNOW 库 foreach
  • OpenMP:不要使用超线程核心(一半“num_threads()”带有超线程)

    In g 4 7 中的 OpenMP 并行 效率不高吗 5x CPU 时为 2 5x https stackoverflow com questions 36950532 is openmp parallel for in g 4 7 no
  • 如何通过 mpi c++ 发送布尔数据类型?

    我是 C 新手 尝试通过 MPI 发送 bool 数据类型 但 C 不支持此数据类型 我试着做到了MPI BYTE and MPI INT但它什么也没打印 include
  • Android OpenCV 并行化循环

    我知道 OpenMP 包含在 NDK 中 使用示例如下 http recursify com blog 2013 08 09 openmp on android http recursify com blog 2013 08 09 open
  • 不确定 openmp 循环中应该共享或私有什么

    我有一个更新矩阵 A 的循环 我想将其设为 openmp 但我不确定哪些变量应该共享和私有 我本以为只有 ii 和 jj 就可以工作 但事实并非如此 我想我也需要在某个地方进行 OMP ATOMIC UPDATE 该循环仅计算 N 和 N
  • 在 openMP C++ 中并行化许多嵌套 for 循环

    你好 我是 C 新手 我编写了一个可以运行的代码 但是由于许多嵌套的 for 循环 它很慢 我想通过 openmp 来加速它 任何可以指导我的人 我尝试使用 pragma omp 并行 前ip循环并在这个循环中我使用了 pragma omp
  • 什么是“收到信号 15”

    什么可能导致 C MPI 程序使用名为的库日晷 CVODE https computation llnl gov casc sundials documentation documentation html 数值 ODE 求解器 在 Gen
  • MPI 矩阵向量乘法返回有时正确有时奇怪的值

    我有以下代码 Start MPI MPI Init argc argv int size atoi argv 1 int delta 10 int rnk int p int root 0 MPI Status mystatus MPI C
  • 测量 OpenMP Fork/Join 延迟

    由于 MPI 3 具有共享内存并行功能 并且它似乎与我的应用程序完美匹配 因此我正在认真考虑将我的混合 OpemMP MPI 代码重写为纯 MPI 实现 为了给棺材里钉上最后一颗钉子 我决定运行一个小程序来测试 OpenMP fork jo
  • 使用 openmp 优化 N-queen

    我正在学习 OPENMP 并编写以下代码来解决 n 皇后问题 Full Code https github com Shafaet Codes blob master OPENMP Parallel 20N Queen 20problem
  • 在不阻塞的情况下“通知”处理器的正确方法是什么?

    假设我有很多东西 我必须对所有这些东西进行一些操作 如果一个元素的操作失败 我想停止整个阵列的工作 这项工作分布在多个处理器上 我想实现这一目标 同时将发送 接收的消息数量保持在最低限度 另外 如果没有必要 我不想阻止处理器 我该如何使用
  • 我可以将多个线程分配给 OpenMP 中的代码段吗?

    我正在寻找一种方法来并行执行代码部分 每个部分使用多个线程 例如 如果我有 16 个线程和两个任务 我希望每个线程有 8 个线程同时执行这两个任务 OpenMP 有多种构造 section task 并行执行一般代码 但它们是单线程的 在我
  • openMPI/mpich2 不能在多个节点上运行

    我正在尝试在多节点集群上使用 install openMPI 和 mpich2 但在这两种情况下 我在多台计算机上运行时都遇到问题 使用 mpich2 我可以从头节点在特定主机上运行 但是如果我尝试从计算节点到不同节点运行某些内容 我会得到
  • OpenMP 线程映射到物理内核

    于是我在网上查了一段时间没有结果 我是 OpenMP 的新手 所以不确定这里的术语 但是有没有办法从 OMPThread 由 omp get thread num 给出 和线程将运行的物理核心找出特定机器的映射 我还对 OMP 分配线程的精
  • 为什么 mex 文件中的 OpenMP 仅产生 1 个线程?

    我是 OpenMP 新手 我有以下代码 使用配置了 MSVS2010 的 Matlab mex 可以正常编译 计算机有 8 个可用处理器 我也使用 matlabpool 检查过 include mex h include
  • OpenMP C 程序运行速度比顺序代码慢

    我是 OpenMP 的新手 正在尝试并行化 Jarvis 的算法 然而事实证明 与顺序代码相比 并行程序花费的时间要长 2 3 倍 难道问题本身就不能并行化吗 或者我并行化它的方式有问题 这是我针对该问题的 openMP 程序 其中有 2

随机推荐

  • anaconda用法

    查看已经安装的包 pip list 或者 conda list 安装和更新 pip install requests pip install requests upgrade 或者 conda install requests conda
  • LINUX权限-bash: ./startup.sh: Permission denied

    LINUX权限 bash startup sh Permission denied 执行 startup sh 或者 shutdown sh的时候 报 Permission denied 需要用命令 chmod 修改一下bin目录下的 sh
  • spring boot配置双Kafka方法

    第一步 application yml的配置 server port 8080 spring application name demo kafka one bootstrap servers xxx xxx xxx xxx consume
  • android动态毛玻璃,Android模糊处理简单实现毛玻璃效果

    自从iOS系统引入了Blur效果 也就是所谓的毛玻璃 模糊化效果 磨砂效果 各大系统就开始竞相模仿 这是怎样的一个效果呢 我们先来看一下 如下面的图片 实现效果大家都知道了 如何在Android中实现呢 说白了就是对图片进行模糊化处理 小编
  • Vue项目生成二维码

    场景 民主测评 闭卷测试 Vue项目生成二维码 使用手机浏览器扫码录入答题 一 创建vue项目 样式布局 接口联调 npm run build 打包成dist 文件 让后台发送到服务器中 页面地址就获取到了 二 前引入vue qr 二维码地
  • openwrt 编译笔记

    错误一 Creating filesystem with parameters Size 50331648 Block size 4096 Blocks per group 32768 Inodes per group 6000 Inode
  • 基于OpenCV-Python实现的人脸识别

    在初步学习了数字图像处理的相关知识并在Matlab进行了初步的模拟后 我将学习的中重点转向了Python环境下的OpenCV库的学习 以此博客记录一下学习的进程 本文章代码主要参考OpenCV库源代码 刘波译的 OpenCV3计算机视觉Py
  • Apache Tomcat

    简介 简而言之 Tomcat是一个免费的开放源代码的Web应用服务器 属于轻量级应用服务器 Apache Tomcat Tomcat是Apache 软件基金会 Apache Software Foundation 的Jakarta 项目中的
  • 邻接矩阵广度优先遍历算法 连通图采用邻接表深度优先遍历的非递归过程 图G中距离顶点v的最短路径长度最大迪杰斯特拉

    1 采用邻接矩阵存储图的广度优先遍历算法的实现 参考教材算法6 5选作 2 一个连通图采用邻接表作为存储结构 设计一个算法 实现从顶点v出发的深度优先遍历的非递归过程 3 设计一个算法 求图G中距离顶点v的最短路径长度最大的一个顶点 设v可
  • 函数调用之回调函数

    重新回到CSDN 工作以来写第一个博客 不码代码 不追求高大上的专业术语 只求通俗的理解 以前听过回调函数 也研究过 但由于没有在实际中用过 所以也没太懂 每次一听到回调函数这个词 感觉很高大上 最近在工作上遇到了 而且被公司前辈广而用之
  • Pickle包的使用

    想要将Python程序运行中得到的字符串 列表 字典等数据 长久的保存下来 而不是简单的放入内存中关机断电就丢失数据 Pickle模块就是专门用来完成此功能的模块 它可以将对象转换为一种可以传输或存储的格式 它实现了基本的数据序列和反序列化
  • 如何保证token的安全

    接口的安全性主要围绕token timestamp和sign三个机制展开设计 保证接口的数据不会被篡改和重复调用 下面具体来看 Token授权机制 用户使用用户名密码登录后服务器给客户端返回一个Token 通常是UUID 并将Token U
  • Sqli-labs之Less-29和Less-30和Less-31

    Less 29 基于错误 GET 双服务器 单引号 字符型注入 服务器 两层 架构 注 截图等来自 MySQL注入天书 Less 29 服务器端有两个部分 第一部分为 tomcat 为引擎的 jsp 型服务器 第二部分为 apache 为引
  • 传输线的物理基础(十):特性阻抗的频率变化

    到目前为止 我们一直假设传输线的特性阻抗随频率保持不变 正如我们所见 从传输线前端看 输入阻抗与频率密切相关 毕竟 在低频时 远端开路的传输线的输入阻抗看起来像一个电容器 阻抗开始很高 然后下降得很低 特性阻抗是否随频率变化 在本节中 我们
  • 【Linux入门】Linux编译器gcc/g++基础

    目录 1 背景知识 2 gcc g 的用法 3 指令补充 3 1 ldd指令 3 2 file指令 4 Linux下的头文件 库 4 1 指令的库 4 1 1 动态库 4 1 2 静态库 4 1 3 动静态库的优缺点 5 gcc g 静态链
  • v-if 和 v-show的区别 vue面试题

    v for 指令 作用 遍历数组 并重复生成对应长度的相同标签 语法 列表渲染 v for item in 数组名 遍历下标 v for item index in items 注意点 这个指令写在哪一个元素身上 就重复生成哪一个元素 数组
  • 小程序用户开放接口调整时间-2021年4月28日24时

    官方实例demo
  • 【编译原理龙书笔记】(三)词法分析(附联系答案)(仍未完成)

    这篇博客是根据自己学习龙书的过程编写 因为博主习惯了英语环境 在强行从英语转化为中文的时候难免会有些不自然 请大家谅解 配套的练习题答案可以在 https github com Oh233 Dragon book exercise 看到 感
  • L2F:第二层转发协议--网络大典

    第二层转发协议 L2F 是一种用来建立跨越公用结构组织 如因特网 的安全隧道 为企业家庭通路连接一个 ISP POP 的协议 这个隧道建立了一个用户与企业客户网路间的虚拟点对点连接 第二层转发协议 L2F 允许链路层协议隧道技术 使用这样的
  • 高性能计算实验——矩阵乘法基于OpenMP的实现及优化

    高性能计算实验 矩阵乘法基于OpenMP的实现及优化 1 实验目的 1 1 通过OpenMP实现通用矩阵乘法 1 2 基于OpenMP的通用矩阵乘法优化 1 3 构造基于Pthreads的并行for循环分解 分配和执行机制 2 实验过程和核