MIT 6.172 笔记 现代硬件算法案例分析

本文是https://en.algorithmica.org/hpc/和MIT 6.172的课后题解析
课程地址:

文章目录

    • HW2 Profiling Serial Merge Sort
      • 测试DEBUG和非DEBUG区别
      • 测试inline和非inline区别
      • Coarsening
    • HW3 向量化
      • 为什么用负偏移量
      • 测量向量化
      • 跨步向量化
    • HW4 Reducer Hyperobjects
      • 比较openmp和pthread
      • omp汇编指令分析
      • omp task实现
      • 优化fib
      • 优化transpose
      • schedule dynamic/static/runtime
    • Cilk运行时
    • HW 6 & HW7: Custom Memory Allocators
    • HW9 & HW10 lock-free和wait-free
      • x86的默认内存模型
      • 并行编程的golden和silver法则
      • 使用setarch x86_64 -R来关闭ASLR
      • 确定性的hashtable
    • 矩阵乘法分析
      • strict alias能起到对齐的作用吗

HW2 Profiling Serial Merge Sort

HW2的课程对应的是L2: Bentley’s Rules和L3:Bit Hacks
关于Bit Hacks可以看https://zhuanlan.zhihu.com/p/37014715

测试DEBUG和非DEBUG区别

HW2介绍了下perf和valgrind,不多展开。
首先课程要求我们用cachegrind分析sort在DEBUG和非DEBUG模式下的命中情况,并且解释指令计数代替时间的优点和缺点。
课程默认是用clang的,但是clang14和clang17经过我测试对cachegrnd的兼容性都不好,读镜像文件报错,需要打补丁:https://bugs.kde.org/show_bug.cgi?id=452758
太麻烦了,因此我换成了gcc
DEBUG模式:
image.png
非DEBUG模式:
image.png

测试inline和非inline区别

这里和我的直觉相违背,事实上:
编译器几乎不需要inline辅助内联,但是我们仍然可以用inline增加被内联的概率。
image.png
这里的性能差距主要是下面的跨翻译单元的alloc函数带来的:

void inline mem_alloc(data_t** space, int size) {*space = (data_t*) malloc(sizeof(data_t) * size);if (*space == NULL) {printf("out of memory...\n");}
}void inline mem_free(data_t** space) {free(*space);*space = 0;
}

我们看这里生成的汇编代码:
image.png
指针和数组的比较比较简单,在此跳过。

Coarsening

void sort_c(data_t* A, int p, int r) {assert(A);// In practice, merge sort is slow for small array sizes. As such, using// faster sorting techniques (i.e. insertion sort) when the array size is// small (aka < 100), can make a significant improvement in the runtime.if (r-p < 16) {isort(&(A[p]), &(A[r]));} else {int q = (p + r) / 2;sort_c(A, p, q);sort_c(A, q + 1, r);merge_c(A, p, q, r);}
}

这里Coarsening的粒度主要收到cacheline的影响,因为L1的miss率是0。
用64字节的cacheline可以算出最佳参数应该是16。
16
image.png
image.png
100
image.png
image.png
剩下的就是空间重用,很简单不多介绍了。

HW3 向量化

为什么用负偏移量

第一个问题很申必:
image.png
f4f5f3b7563c766851fbceae8be56809.png
这里没有memcpy那种overlap问题,为什么用负偏移量呢?
问了下别人说是因为loop latch可以省一个cmp,而且现在clang已经不会这样做了(有指令fusion所以意义不大了),因此我们不需要太在意这个问题。

测量向量化

没有向量化的情况:
image.png
4宽向量化
image.png
perf分析乘法:
耗时最多的是索引更新操作
image.png
perf分析加法:
耗时最多的是向量化的加法
image.png

跨步向量化

跨步不会进行向量化:
image.png
强制进行向量化试试:
image.png
并没有变快
我们看看跨步向量化的汇编代码
image.png
跨步向量化会多出一个vextracti128指令进行提取,但是耗时很低

HW4 Reducer Hyperobjects

比较openmp和pthread

https://en.wikipedia.org/wiki/OpenMP#Pros_and_cons
优点:
可移植的多线程代码(在C/C++和其他语言中,通常必须调用特定于平台的原语才能获得多线程)。
简单:不需要像MPI那样处理消息传递。
数据布局和分解由指令自动处理。
可扩展性与共享内存系统上的MPI相当。[39]
增量并行:可以一次处理程序的一个部分,不需要对代码进行显著的更改。
串行和并行应用程序的统一代码:当使用顺序编译器时,OpenMP构造被视为注释。
在使用OpenMP并行化时,通常不需要修改原始(串行)代码语句。这减少了无意中引入错误的机会。
粗粒度和细粒度并行都是可能的。
在不完全遵循SPMD计算模式的不规则多物理应用中,如在紧密耦合的流体颗粒系统中遇到的那样,OpenMP的灵活性可以比MPI具有很大的性能优势。
可用于各种加速器,如GPGPU[41]和FPGA。
缺点:
引入难以调试的同步错误和竞争条件的风险。
截至2017年,仅在共享内存多处理器平台上有效运行(但请参阅Wayback Machine和其他分布式共享内存平台上的英特尔集群OpenMP存档2018-11-16)。
需要支持OpenMP的编译器。
可扩展性受到内存体系结构的限制。
不支持比较和交换。
缺少可靠的错误处理。
缺乏细粒度机制来控制线程处理器映射。
意外编写错误共享代码的几率很高。

omp汇编指令分析

见https://github.com/Chang-LeHung/openmp-tutorial/blob/master/docs/for.mdhttps://github.com/Chang-LeHung/openmp-tutorial/blob/master/docs/for.md
omp关键的几个操作用到了
lock cmpxchg、cmpxchg和__sync_fetch_and_add
如果划分的块比较小,那就不会用失败率比较高的cmpxchg,而是用__sync_fetch_and_add

omp task实现

见https://github.com/Chang-LeHung/openmp-tutorial/blob/master/docs/task.md
image.png

优化fib

#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>#include "omp.h"int64_t fib(int64_t n) {if (n < 2) return n;int64_t x, y;if (n < 19) {x = fib(n - 1);y = fib(n - 2);}else {
#pragma omp task shared(x)x = fib(n - 1);
#pragma omp task shared(y)y = fib(n - 2);
#pragma omp taskwait}return (x + y);
}int main(int argc, char* argv[]) {int64_t n = atoi(argv[1]);int64_t result;omp_set_num_threads(4);int nthreads = omp_get_num_threads();printf("N = %d\n", nthreads);// result = fib(n);
#pragma omp parallel{
#pragma omp master{result = fib(n);}}printf("Fibonacci of %" PRId64 " is %" PRId64 ".\n", n, result);
}

优化transpose


void transpose(Matrix* arr) {uint16_t i, j;// Parallel section:
#ifdef _OPENMP
#pragma omp parallel for private(i, j) num_threads(8) schedule(dynamic)for (i = 1; i < arr->rows; i++) {for (j = 0; j < i; j++) {uint8_t tmp = arr->data[i][j];arr->data[i][j] = arr->data[j][i];arr->data[j][i] = tmp;}}goto end;
#endif// Serial section:for (i = 1; i < arr->rows; i++) {for (j = 0; j < i; j++) {uint8_t tmp = arr->data[i][j];arr->data[i][j] = arr->data[j][i];arr->data[j][i] = tmp;}}goto end;end:return;
}

schedule dynamic/static/runtime

https://stackoverflow.com/questions/10850155/whats-the-difference-between-static-and-dynamic-schedule-in-openmp
schedule(static,2) 每个线程分配两个循环块
比如:

#pragma omp parallel for schedule(static,2) num_threads(8)
for (i = 0; i < 8; i++)memset(&a[i*4096], 1, 4096);
|             | core 0 | thread 0 | a[0]     ... a[8191]  <- OK, same memory node
| socket 0    | core 1 | thread 1 | a[8192]  ... a[16383] <- OK, same memory node
| NUMA node 0 | core 2 | thread 2 | a[16384] ... a[24575] <- Not OK, remote memory
|             | core 3 | thread 3 | a[24576] ... a[32768] <- Not OK, remote memory|             | core 4 | thread 4 | <idle>
| socket 1    | core 5 | thread 5 | <idle>
| NUMA node 1 | core 6 | thread 6 | <idle>
|             | core 7 | thread 7 | <idle>

#pragma omp for schedule(dynamic,1)
用在每个循环块执行时间由较大差别的情况。**schedule(runtime) 是 OpenMP 中用于动态选择循环迭代分配方式的一种方式。具体含义如下:

  • runtime:表示在运行时动态选择循环迭代分配方式。这意味着循环迭代的分配方式将在程序运行时由运行时系统根据环境和系统的情况进行选择。

Cilk运行时

image.png

  1. RIP:RIP是英特尔x86处理器架构中的指令指针寄存器(Instruction Pointer Register)的缩写。该寄存器存储了当前正在执行的指令的内存地址。当处理器执行指令时,它会从RIP寄存器中获取下一条要执行的指令的地址。
  2. RBP:RBP是英特尔x86处理器架构中的基址指针寄存器(Base Pointer Register)的缩写。在函数调用过程中,RBP通常被用作栈帧的基址指针,用于定位函数的局部变量和参数。通过RBP,函数可以访问其局部变量和参数的内存位置。
  3. RSP:RSP是英特尔x86处理器架构中的栈指针寄存器(Stack Pointer Register)的缩写。栈是一种常用的数据结构,用于存储函数调用期间的局部变量、参数和返回地址等信息。RSP寄存器指向当前栈顶的内存地址,当新的数据被推入或弹出栈时,RSP的值会相应地更新。

HW 6 & HW7: Custom Memory Allocators

后面的两节都是选修课,因为有很多优秀的实现,比如mimalloc、tcmalloc,我之前也分析过,所以这节就跳过了,我们看下一节,lock free和wait free,这个还是很重要的。

HW9 & HW10 lock-free和wait-free

x86的默认内存模型

image.png

并行编程的golden和silver法则

golden rule:永远不要编写非确定性程序
silver rule:永远不要编写非确定性程序,如果必须要编写,那么使用完备的测试用例

使用setarch x86_64 -R来关闭ASLR

确定性的hashtable

e00dd9ba181b4aa04c87ba8ba2e7b1fa.png
这里的问题在于probe可能超出范围,所以我们通过控制线程数可以实现 good和bad
image.png

矩阵乘法分析

https://en.algorithmica.org/hpc/algorithms/matmul/

strict alias能起到对齐的作用吗

在https://en.algorithmica.org/hpc/algorithms/matmul/中说__restrict__能解决alias问题,获得性能提升,但实际上:
https://quick-bench.com/q/GxzfeO3Jmul8g0dw9K1oKgQ_9fw
image.png
可以看得出来,对齐比alias在矩阵乘中作用大得多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/4218.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac上用brew安装node

没有安装Homebrew的&#xff0c;可以参考mac安装Homebrew 1. 简介 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境&#xff0c;用于在服务器端运行 JavaScript 代码。它允许开发者使用 JavaScript 来编写服务器端的应用程序&#xff0c;例如网站后端、API 服务、…

[Qt的学习日常]--信号和槽

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习&#xff…

【JAVA】一文掌握Java并发编程

Java 开发中&#xff0c;并发编程属于相当重要的一个知识点&#xff0c;可以说&#xff0c;Java 的并发能力&#xff0c;是成就今日 Java 地位的因素之一。Java 的并发编程由浅入深实质上是包含 Java&#xff08;API&#xff09;层、JVM&#xff08;虚拟机&#xff09;层、内核…

[Linux][网络][网络编程套接字][一][预备知识][套接字地址结构]详细讲解

目录 0.预备知识1.理解源IP地址和目的IP地址2.理解源MAC地址和目的MAC地址3.端口号4.理解端口号和进程ID5.理解源端口号和目的端口号6.通过IP地址、端口号、协议号进行通信识别7.认识TCP协议和UDP协议8.网络字节序 1.套接字地址结构(sockaddr) 0.预备知识 1.理解源IP地址和目的…

初学软件工程后对其的希望及个人目标

&#xff08;学校作业&#xff09; flag&#xff1a; 希望这学期可以做出人生中第一个亲手开发的软件。 对软件工程的希望&#xff1a; 1、希望能在软件工程学到更多在软件方面的技能&#xff0c;可以对软件有更加深刻的理解。 2、希望这个专业可以发展的越来越好&#xff0c;软…

redisson分布式锁的单机版应用

package com.redis;/*** author linn* date 2024年04月23日 15:31*/ import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.…

从 0 到 1 创建、测试并发布属于自己的 Go 开源库

作者&#xff1a;陈明勇 个人网站&#xff1a;https://chenmingyong.cn 文章持续更新&#xff0c;如果本文能让您有所收获&#xff0c;欢迎点赞收藏加关注本号。 微信阅读可搜《程序员陈明勇》。 这篇文章已被收录于 GitHub https://github.com/chenmingyong0423/blog&#xff…

AIGC——什么是人工智能生成内容

人工智能生成内容&#xff08;AIGC&#xff09;是当今数字时代的一个引人注目的前沿技术&#xff0c;它借助深度学习和自然语言处理等技术&#xff0c;使计算机系统具备了生成高质量文本、图像、音频等多媒体内容的能力。AIGC的出现不仅推动了信息技术的发展&#xff0c;也在多…

判断字符串由几个单词组成(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int world 0;int i 0;char c 0;char string[81] { 0 };int num 0;//提示用户&#xff…

C++---重载

1、运算符重载 #include <iostream> using namespace std; class complex { int rel; int vir; public: complex(){} complex(int rel,int vir):rel(rel),vir(vir){} void show() { cout << rel << "" << vir << "i" <&l…

(待更)DRF: 序列化器、View、APIView、GenericAPIView、Mixin、ViewSet、ModelViewSet的源码解析

前言&#xff1a;还没有整理&#xff0c;后续有时间再整理&#xff0c;目前只是个人思路&#xff0c;文章较乱。 注意路径匹配的“/” 我们的url里面加了“/”&#xff0c;但是用apifox等非浏览器的工具发起请求时没有加“/”&#xff0c;而且还不是get请求&#xff0c;那么这…

31.Gateway网关-跨域问题

跨域 1.域名不同&#xff1a;www.baidu.com和www.taobao.com,www.taobao.org 2.域名相同&#xff0c;端口不同。localhost:8080和localhost:8081 跨域问题 浏览器禁止请求的发起者与服务端发生跨域ajax请求&#xff0c;请求被浏览器拦截的问题。 解决方案 CORS 浏览器询…

0426_C高级4

练习1&#xff1a; 输入一个数字&#xff0c;实现数字逆置&#xff08;不使用字符串截取方式&#xff09; 1 #!/bin/bash2 read -p "输入一个数字&#xff1a;" number3 p$number4 result5 while [ $p -ne 0 ]6 do7 result$((result*10p%10))8 p$((p/10))9 …

what are the different types of redundancy in an image.

在图像中&#xff0c;冗余主要表现为以下几种形式&#xff1a; 空间冗余&#xff1a;这是指图像内部相邻像素之间存在较强的相关性所造成的冗余。例如&#xff0c;在图像中&#xff0c;如果存在一片连续的区域&#xff0c;其像素颜色相同&#xff0c;这就产生了空间冗余。这种…

c++类基础知识

引入 下面是一个从菜鸟抄来的例子&#xff0c;可以看到BOX定义了两个公共函数&#xff0c;get和set&#xff0c;在类里面声明&#xff0c;在外面定义&#xff0c;也可以直接在里面定义。 #include <iostream>using namespace std;class Box {public:double length; /…

Docker Compose详细使用讲解!超全!(入门到精通)

Docker Compose详细使用讲解&#xff01;超全&#xff01;(入门到精通) Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过使用Compose&#xff0c;您可以使用YAML文件来配置应用程序的服务、网络和卷&#xff0c;然后使用一个命令来创建和启动所有服务。本…

数据安全的定义及其分类分级

数据安全是指保护数据免受未经授权的访问、使用、泄露、破坏或篡改的过程。数据安全的目标是确保数据的机密性、完整性和可用性&#xff0c;以防止数据被盗窃、篡改或丢失&#xff0c;从而保护个人隐私和组织机密信息。 数据安全可以根据其保护的对象和级别进行分类分级&#x…

input框添加验证(如只允许输入数字)中文输入导致显示问题的解决方案

文章目录 input框添加验证(如只允许输入数字)中文输入导致显示问题的解决方案问题描述解决办法 onCompositionStart与onCompositionEnd input框添加验证(如只允许输入数字)中文输入导致显示问题的解决方案 问题描述 测试环境&#xff1a;react antd input (react的事件与原生…

Linux Systemd服务创建与配置

在/etc/systemd/system/目录创建并配置服务: 创建一个新的systemd服务单元文件&#xff0c;以描述你的服务配置。 sudo vi /etc/systemd/system/my-service.service 在打开的文件中&#xff0c;添加以下内容来定义你的服务配置&#xff1a; [Unit] Descriptionmqnamesrv After…

无人机GB42590接收端 +接收端模组,同时支持2.4G与5.8G双频

严格按照GB42590的协议开发的发射端&#xff0c;通过串口和模块通讯&#xff0c;默认波特率 921600。 http://www.doit.am/深圳四博智联科技有限公司https://shenzhendoit.taobao.com/category-1734422372.htm?spma1z10.1-c-s.0.0.560c74d77eT01G&searchy&catNameGB4…