- 博客(120)
- 收藏
- 关注
原创 cuda reduction&reduce
是一种并行计算中的操作概念或技术,指的是将一组数据通过某种特定的操作(如加法、乘法、求最大值、求最小值等)进行聚合,最终得到一个或几个汇总结果的过程。它强调的是这种数据处理的模式或任务类型,是一个较为宽泛的概念,在各种并行计算场景和框架中都可能存在。
2025-01-25 21:00:11
513
原创 cuda 内存作用域(memory scope)
系统级别的原子操作需要确保在整个系统中(可能包括多个GPU设备或CPU)数据的一致性。在这个例子中,blockSum是一个共享内存变量,每个线程块内的线程都会对其进行原子加操作。最终,每个线程块会将其计算的和累加到data[0]。假设我们在一个线程中进行自增操作,但由于原子操作仅对发起该操作的线程可见,所以在这种情况下,线程级别的原子操作几乎没有意义,通常不被使用。在设备级别的内存作用域中,所有线程(无论它们属于哪个线程块)都可以安全地对data[0]进行原子加操作。这确保了跨线程块的全局数据一致性。
2024-12-10 15:39:52
277
原创 git使用
如果直接在命令行用rm删除文件,git status会报信息,因为删除了文件,git记录的是修改,需要使用git rm或者git add提交修改到暂存区最后提交到仓库,区别在于,如果是git rm,能够直接删除文件并移到暂存区,如果想用git add,需要手动删除,然后add 并commit。初始化一个新的空白Git仓库,在执行git init之后,Git会在当前目录下创建一个新的.git文件夹,用来存储仓库的相关信息和元数据,就算当前文件夹下面有东西,git init也不会自动跟踪文件。
2024-11-23 11:49:19
622
原创 nv_triton_mm_lowering
这个pass消除了很多blocked类型,对于矩阵乘,之前转了两次layout,现在直接转mma相关的layout。因为输入进tt.dot的三个输入都不满足tt.dot所要求的layout,所以都额外产生了一句layout的转换。这里依据layout完成线程任务映射,可以从ptx看出,该指令从global加载数据。在这一层pass,将所有的tensor和tensor指针带上blocked标记。这里是计算完成的结果,从寄存器放回global。专门实现矩阵加速,也就是带上mma的pass。
2024-10-15 10:55:18
121
原创 Triton矩阵乘
如果k维度非常大,一个块任务的迭代次数过多,会导致计算资源浪费在迭代上,所以这种情况下需要对k进行切分,也就是增加一个维度的分块,也就是改变grid。本质上就是比如原来计算0块是一个块任务,现在分为两个块任务去计算,最后结果在累加。上述两种计算c小块顺序会影响缓存的命中率,所以官方文档的意思就是我们试图让代码运行按照下方的顺序进行矩阵乘法。所以当分块完毕之后,每个块任务需要加载a的一个小块和b的一个小块不断进行矩阵乘累加,在k方向上迭代。c矩阵的一小块需要a矩阵的一行和b矩阵一列。
2024-10-12 11:05:58
381
1
原创 bank冲突
一个bank只能接受一个thread访问自己银行里面的一个地址,或者多个thread访问同一个地址(有广播机制),每个位置可以放4B或者8B数据,就是32bit或者64bit数据,然后顺序是从上到下,从左到右。如果两个线程同时去访问一个bank的不同位置,就需要排队,而不是并行,这样就慢。bank号:i*sizeof(类型)/sizeof(bank)%32。所以尽量要让他们访问不同bank或者同一个bank的一个位置。一个线程可以做到同时访问多个bank,一个周期就能拿到数据。int[0]访问bank0。
2024-09-09 11:17:39
228
原创 vscode 远程连接linux docker
Vscode连接远程服务器中的docker容器进行开发(两种方法)_vscode连接远程服务器的docker容器-优快云博客
2024-09-04 11:21:17
481
原创 类实例化和构造函数
首先观察表,子类是肯定包含了父类的所有虚函数的,只是会把重新实现的,替换为自己的,所以体现多态就是这样,我们传入参数是基类指针,因为默认的虚函数表是在首地址的,大家都一样,然后我们都想调用show2(),因为穿进来的指针指向的地址拿到的虚函数表是不一样的,虽然偏移一样,但是最后调用的就是不同的虚函数实现。由之前的行为分析知道,子类实例化过程中,会去调用父类的构造函数,将对象的首地址设置为父类的虚函数表,再去设置父类的成员变量,再退回到子类构造函数重复一样的操作。行为和没有纯虚函数一样,也是替换表。
2024-08-31 18:57:15
610
原创 mmap和read/write
mmap直接把一片虚拟内存映射了文件内容,相当于用户区域的缓存,访问这片缓存自然是不需要切换内核态的。理解为,内核里有个缓存,来放磁盘文件的缓存。访问该缓存需要进入内核态。使用read/write每次调用都回去访问这个缓存。
2024-08-25 12:17:47
142
原创 指针编译后
指针变量存一个地址,在riscv下表现为s0-x,即以帧指针为偏移,在栈上存一个地址值。行为表现为,会把指针变量的地址加载到寄存器,在去加载这个地址的所在位置的标量。
2024-08-24 22:12:54
256
原创 函数调用哦
当传入参数过多的时候,策略是,多出的在调用前,放在调用者栈里,通过帧指针偏移去访问。当发生调用的时候,顺序如下。传指针进去,对指针操作。
2024-08-23 09:18:44
191
原创 (2)Dynamo
这里会改变实际执行的字节码,具体后面细看,简单来说就是把源代码部分抓成图,然后编译,返回这部分的编译函数来调用。源码生成的字节码经过改写后的。
2024-08-06 12:32:58
307
原创 Partial Lowering to Lower-Level Dialects for Optimization
toy部分lowering到affine,从toy变成混合的mlir使用DialectConversion框架需要提供两个东西(和一个可选的第三个)
2024-07-12 11:10:08
1124
原创 Pattern Rewriting : Generic DAG-to-DAG Rewriting
这是一个可选的参数,用于指明这个模式(pattern)要匹配的根操作的名称。如果没有指定,那么任何类型的操作都可能被提供。在MLIR中,模式匹配是将一个特定的代码模式转换为更优化的形式,而匹配谓词就是用来判断这个代码模式是否符合某些条件,从而决定是否进行转换。也就是说,我们可以为每种可能的情况预先创建一个模式,然后用简单的条件判断来选择合适的模式。预期好处:应用一个模式(pattern)可以带来一定的优化效果,这个优化效果在模式创建时是固定的,但也可以在模式初始化时根据具体情况(例如目标架构)动态计算。
2024-07-07 16:12:25
1201
原创 Table-driven Declarative Rewrite Rule (DRR)
源模式,用于匹配操作的DAG。一个或多个结果模式,用于生成操作的DAG以替换匹配到的DAG。我们允许多个结果模式以支持多结果操作和辅助操作,但通常我们只是想将一个操作的DAG转换为另一个操作的DAG。class Pat
2024-07-05 19:13:14
977
原创 MLIR
方言(Dialects)是参与并扩展MLIR(多级中间表示,多级中间语言)生态系统的机制。它们允许定义新的操作、属性和类型。每个方言都有一个唯一的命名空间,这个命名空间会作为前缀添加到每个定义的属性、操作和类型前。例如,Affine方言定义的命名空间是:affine。MLIR允许多个方言共存,即使这些方言不在主树结构内,也可以在一个模块内共同存在。方言由特定的传递过程产生和消费。MLIR提供了一个框架,可以在不同的方言之间进行转换,也可以在同一个方言内进行转换。
2024-07-03 09:53:53
1226
原创 Triton矩阵乘以及缓存优化
行坐标=组号*每组行数+pid%每组行数,pid%3知,pid三个三个一排,也就是算的当前pid在当前组里相对是第几行,比如如果是4,4%3=1,可知pid=4在当前组第一行(0,1,2),那么组号*每组行数就可以相对整组位移,最终可以知道pid和c矩阵中行位置的映射。num_pid_in_group = GROUP_SIZE_M * num_pid_n,算的是一个组有多少块,这里假设是3*9,所以一组27块。A,B形状是574*574,块形状是64*64,这样一共有81块,pid就是0~80,
2024-06-17 10:07:30
708
2
原创 模板方法。
所以就是流程固定下来,但是其中的步骤2、4设置为虚函数,也就是提供给用户实现,这样用户只需要实现2、4步骤,然后执行即可。其中有2、4步骤是可以改变的,那么这是变化的部分,所以需要将这部分和相对稳定的流程隔离。情况:有一个流程和五个步骤,这五个步骤执行逻辑确定。
2024-06-12 18:58:03
134
原创 单例模式。
综上,上述为饿汉模式的单例,代码在main之前就有了一个实例的位置,在main里面你只能能通过成员函数getInstance来得到这个实例。第二个就是类的静态成员就是在外部初始化的,所以他这里的能够new,是相当于在类内的,所以是能够调用私有的默认构造函数。单例模式要求对象创建受到控制,默认的构造函数是公共的,所以需要限制这些提供给外部创造类实例的构造函数。关于这句话,一个是如果是静态变量初始化,你需要带上他的变量类型,就是TaskQueue *;这样对于外部,是无法创建任何该对象的实例的。
2024-06-11 10:08:06
424
原创 找质数因子
2、如果是i>sqrt(n),这种情况是这样的,就是每次我们循环剩下的n,他是最开始我们的因数,但不是质因数,当最后剩下的n的sqrt(n)小于i,说明,他不能被之前的质数除,也就是从2到sqrt(n)的质数都无法成为这个n的因数。1、如果是i<=sqrt(n),也就是说,n不需要从2开始找因数,因为之前的操作保证他们不会是因数了,所以从i开始找。回到这里,n是奇数,从3开始找质因数,就算n一直变,对于每次新的n来说,找质因数也就是到sqrt(n)就行了,n可能等于1,比如6,但1不是质因数,不需要加入。
2024-04-17 11:28:38
325
原创 sort用法
前两个参数传范围,可以是迭代器也可以是指针,最后传比较方法。该方法判断cmp的第一个参数是否在第二个参数之前,比如这里想从小到大排序,x为小的时候在前,所以当x<y的时候我们返回1.
2024-04-16 18:15:26
241
原创 虚拟内存映像
bss放未初始化的变量、data是初始化的、text是代码内容,因为寄存器寻址也要编码,这个是消耗指令bit的。heap就是用户控制的地方,栈由编译器控制。stack放寄存器放不下的局部变量,为什么寄存器也不能很多?最下面是固定的内容,
2024-04-15 17:54:11
239
原创 bank冲突
就是share每一行是可以并行访问的,但是如果出现线程访问同一个bank,也就是同一行,就会串行,就是冲突。访问a[0]...a[31],在共享内存上就是share[0][1]...share[0][31],首先同一时间只有一个warp会去访问share,所以冲突来自同一个warp的不同thread。就是比如每行存32个位置,每个位置32bit,一行一行存。如果在共享内存上存了int数组a,
2024-04-11 17:17:36
197
原创 nvcc编译
我们如果选择了较小的虚拟架构,如果真实架构大,就没问题。如果你选择了一个架构功能你的程序没用到,那么你的虚拟架构打了,你可以选择的真实架构的数量就小了。上面的编译方式你必须要知道你的gpu是什么才能做到,所以多了即时编译,意思就是先只指定虚拟架构,最后实际上机跑的时候我们再决定实际架构到底是什么。因此,一个 nvcc 编译命令总是使用两个架构:一个虚拟中间架构,加上一个真实的 GPU 架构来指定要在其上执行的目标处理器。这里就编译了三个,两个设计实际的架构,一个只有虚拟架构,这样上机跑就就可能直接跑了。
2024-04-10 17:57:53
395
原创 gpu线程分支
因为和A之前的cbj指令是相对应的,所以会找到A指令之前的cbj存的a、w码,那么合并之后发现a、w码并不相等,那么说明还有分支没有执行,那么改变w码为0001,从栈里弹出B的pc+4以及掩码1110。E执行完成之后,遇到cbs,那么这是A的,A现在的信息为1111 0001合并a码之后为1111,和w码一样,说明合并完毕,然后所有线程继续往下执行。当D执行完毕之后,改变B的W码为1110,发现等于B的a码1110,说明B的所有分支重聚,那么当前a码改为1110,然后继续执行D的下一条指令。
2024-04-10 14:55:04
312
原创 gpu模拟器总体流程
3、划分形状,传入内核函数,形状参数和设备端数据地址、执行计算。2、创建页表,开设备端空间并复制数据。4、复制数据回主机端,释放gpu资源。这里显存就是运行模拟器的机器。1、开显存空间,初始化。
2024-04-09 14:44:23
427
原创 关于gpu模拟器任务发布
关于block如何分成warp,发现是blocksize来拆,blocksize是一个block所需要的总的线程数字,也就是说,这里是依赖所需要跑的warp总数来发布任务。然后这部分嵌套在csr指令里面,也就是读特殊的csr,会去执行getthreadid的操作,然后把threadid放到变量里。这里的warp就多一个block的信息,相当于warp是直到自己属于哪个block。那么发布任务,就每次增长block的size,如下。所以这里算的是线程在block里面的坐标位置。那我们看看warp有什么信息。
2024-04-09 14:03:19
181
原创 gpu模拟器内存使用
先看walk函数,参数前两个分别是根页表的起始地址和这次要分配的虚拟地址的起始,因为映射也是需要分配物理页表的,所以这里可以看到如果是没有分配的,我们会分配一个物理页表,然后把它映射到表上。这里就是要把最后一集的页表项和物理地址关联起来,64位地址,由于物理页是按照4096来划分的,就是2^12次方,所以物理页一页的起始地址总是低位为12个0,所以变成页表项目就需要右移12位然后左移10位,低10位是标志之类的。传入参数是根页表,起始地址,大小,以及申请的物理页总和的起始地址。比如一开始的显存拷贝。
2024-04-08 16:32:48
459
原创 GPU模拟器地址
512KB~1024KB:Local Memory地址空间,属于独立thread,19位。1MB~256GB:Global Mempry地址空间,属于独立grid,38位。0~128KB:sharememory,属于每个block。2^9*2^10B,一个B一个地址,所以有2^19个地址。128KB~512KB:无效地址空间。地址计算方式,如512KB大小。
2024-04-08 11:33:36
166
LLVM Techniques, Tips, and Best Practices Clang and Middle-End L
2024-01-09
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人