Metal入门学习:GPU并行计算大数组相加

news2024/11/25 2:35:15
一、编程指南PDF下载链接(中英文档)
  • 1、Metal编程指南PDF链接
    https://github.com/dennie-lee/ios_tech_record/raw/main/Metal学习PDF/Metal 编程指南.pdf

  • 2、Metal着色语言(Metal Shader Language:简称MSL)编程指南PDF链接
    https://github.com/dennie-lee/ios_tech_record/raw/main/Metal学习PDF/Metal 着色语言指南.pdf

  • 3、补充:官网API文档链接
    https://developer.apple.com/documentation/metal/performing_calculations_on_a_gpu

二、内容前述

本文章通过元素个数相同的两个数组对应位置相加来切入Metal(GPU)的并行计算着色函数(本篇文章未涉及渲染函数:顶点着色函数和片元着色函数,会另起一篇文章介绍)。在此示例中,可以了解所有 Metal 应用程序中使用的基本任务。 您将看到如何将用 C 编写的简单函数转换为Metal着色语言 (Metal Shader Language :MSL),以便它可以在 GPU 上运行。通过创建管道,准备MSL函数在其上运行,并创建GPU可访问的数据对象。要针对您的数据执行管道,创建命令缓冲区,将命令写入其中,然后将缓冲区提交到命令队列,Metal将命令发送到GPU执行。
(下图是官网并行计算着色函数流程原理图:)
在这里插入图片描述

三、C语言和MSL语言对两个数组相加的函数对比
  • 1、C语言函数:两个数组相加
void add_arrays(const float* inA,
                const float* inB,
                float* result,
                int length){
    for (int index = 0; index < length ; index++)
    {
        result[index] = inA[index] + inB[index];
    }
}
  • 2、MSL语言函数:两个数组相加
kernel void add_arrays(device const float* inA,
                       device const float* inB,
                       device float* result,
                       uint index [[thread_position_in_grid]]){
    result[index] = inA[index] + inB[index];
}

关键词解释说明(在MSL编程指南PDF中可查看,点击上面的链接下载即可)
在这里插入图片描述
[[thread_position_in_grid]]文档中也有,更加详细的解析说明可查看这篇文章:https://juejin.cn/post/7085633906501746724,文章中还有延伸说明解释[[threadgroup_position_in_grid]]和[[threads_per_threadgroup]]

四、关键代码段解析
  • 1、初始化、加载扩展名为.metal的文件、创建管道状态对象加载并行计算着色函数
//_mDevice = MTLCreateSystemDefaultDevice();
// Load the shader files with a .metal file extension in the project
id<MTLLibrary> newDefaultLibrary = [_mDevice newDefaultLibrary];
if (newDefaultLibrary == nil){
    NSLog(@"Failed to find the default library");
    return nil;
}
    
id<MTLFunction> newFunction = [newDefaultLibrary newFunctionWithName:@"add_arrays"];
if (newFunction == nil){
    NSLog(@"Failed to find the adder function");
    return nil;
}
    
NSError *error;
// Create a compute pipeline state object.
//根据扩展名为.metal文件中kernel定义的函数创建计算管道(项目Add文件)
_mAddFunctionPSO = [_mDevice newComputePipelineStateWithFunction:newFunction error:&error];
if (_mAddFunctionPSO == nil){
    //  If the Metal API validation is enabled, you can find out more information about what
    //  went wrong.  (Metal API validation is enabled by default when a debug build is run
    //  from Xcode)
    NSLog(@"Failed to create pipeline state object,error : %@)",error);
    return nil;
}

// 指令队列
_mCommandQueue = [_mDevice newCommandQueue];
if (_mCommandQueue == nil){
    NSLog(@"Failed to find command queue");
    return nil;
}
  • 2、初始化数组数据
//初始化数组数据
- (void)prepareData{
    _mBufferA = [_mDevice newBufferWithLength:bufferSize options:MTLResourceStorageModeShared];
    _mBufferB = [_mDevice newBufferWithLength:bufferSize options:MTLResourceStorageModeShared];
    _mBufferResult = [_mDevice newBufferWithLength:bufferSize options:MTLResourceStorageModeShared];
    [self generateRandomFloatData:_mBufferA];
    [self generateRandomFloatData:_mBufferB];
}

- (void)generateRandomFloatData:(id<MTLBuffer>)buffer{
    float *dataPtr = buffer.contents;
    for (int index = 0; index < arrayLength; index++){
        dataPtr[index] = (float)rand() / (float)RAND_MAX;
    }
}
  • 3、指令参数添加,提交GPU计算
- (void)sendComputeCommand{
    //create a command buffer to hold commands
    //创建指令缓存冲区
    id<MTLCommandBuffer> commandBuffer = [_mCommandQueue commandBuffer];
    assert(commandBuffer != nil);
    
    //开始进行指令添加参数
    id<MTLComputeCommandEncoder> computeEncoder = [commandBuffer computeCommandEncoder];
    assert(computeEncoder != nil);
    
    NSTimeInterval startTimeInterval = [[[NSDate alloc] init] timeIntervalSince1970];
    [self encodeAdderCommand:computeEncoder];
    
    //添加参数完毕,
    [computeEncoder endEncoding];
    //提交执行指令
    [commandBuffer commit];
    //等待计算完毕
    [commandBuffer waitUntilCompleted];
    NSTimeInterval endTimeInterval = [[[NSDate alloc] init] timeIntervalSince1970];
    NSLog(@"长度为:%u 的两个数组相加(Metal方式)花费的时间:%f",arrayLength,(endTimeInterval - startTimeInterval));
    //验证计算结果
    [self verifyResults];
}

- (void)encodeAdderCommand:(id<MTLComputeCommandEncoder>)computeEncoder{
    //encode pipeline state object and its parameters
    [computeEncoder setComputePipelineState:_mAddFunctionPSO];
    //此处的atIndex为0,与MSL函数中参数对应顺序对应(也可以设置buffer(0),此处可先忽略buffer,详细信息可查看着色语言编程指南PDF)
    [computeEncoder setBuffer:_mBufferA offset:0 atIndex:0];
    //此处的atIndex为1,与MSL函数中参数对应顺序对应(也可以设置buffer(1),此处可先忽略buffer,详细信息可查看着色语言编程指南PDF)
    [computeEncoder setBuffer:_mBufferB offset:0 atIndex:1];
    //此处的atIndex为1,与MSL函数中参数对应顺序对应(也可以设置buffer(2),此处可先忽略buffer,详细信息可查看着色语言编程指南PDF)
    [computeEncoder setBuffer:_mBufferResult offset:0 atIndex:2];
    
    //全部线程数量,此处对应[[thread_position_in_grid]],理解此处请看第三.2对应关键词解释的文章
    MTLSize gridSize = MTLSizeMake(arrayLength, 1, 1);
    NSUInteger threadGroupSize = _mAddFunctionPSO.maxTotalThreadsPerThreadgroup;
    if (threadGroupSize > arrayLength){
        threadGroupSize = arrayLength;
    }
    //线程组大小
    MTLSize threadGroupsize = MTLSizeMake(threadGroupSize, 1, 1);
    [computeEncoder dispatchThreads:gridSize threadsPerThreadgroup:threadGroupsize];
}
五、完整代码

例子:github链接:https://github.com/dennie-lee/MetalArrayAddDemo

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

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

相关文章

【王道·计算机网络】第六章 应用层

一、基本概念 1.1 应用层概述 应用层对应用程序的通信提供服务应用层协议定义&#xff1a; 应用进程交换的报文类型&#xff0c;请求还是响应?各种报文类型的语法&#xff0c;如报文中的各个字段及其详细描述字段的语义&#xff0c;即包含在字段中的信息的含义进程何时、如何…

PathWise开发(1) 将增加节点的功能移动到鼠标右键 d3.js/vue.js

PathWise(1) 从零开始搭建知识图谱/个性化学习路径/d3.js/vue.js 2023年5月20日&#xff1a;将增加节点的功能移动到鼠标右键 跑起来先 思路&#xff1a; 将我们之前的MyTableAddNode.vue&#xff0c;删除其中的内容只留下下面的表单<template><!-- <div class…

【Linux Network】高级IO

目录 前言 五种IO模型 阻塞IO 非阻塞IO 信号驱动IO IO多路转接 异步IO 小结 同步通信 vs 异步通信 阻塞 vs 非阻塞 其他高级IO 非阻塞IO fcntl函数 代码测试 高级IO&#x1f337; 前言 IO&#xff1a;所谓的I便是 input&#xff0c;所谓的O便是 output&#xff0c;简单点来说&a…

VC++6.0掌握哈希表的基本操作和掌握几种内部排序的方法

问题描述 针对某个集体中人名设计一个哈希表&#xff0c;使得平均查找长度不超过R&#xff0c;并完成相应的建表和查表程序。 1.2基本要求 假设人名为中国人姓名的汉语拼音形式。待填入哈希表的人名共有30个&#xff0c;取平均查找长度的上限为2。哈希函数用除留余数法构造&…

【掌控安全】sql注入全集

掌控安全 &#x1f525;系列专栏&#xff1a;掌控安全 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2023年5月20日&#x1f334; &#x1f36d;作者水平很有限&#xff0c;如果发现错误&…

Linux---文件操作命令(touch、cat、more)

1. touch命令 可以通过touch命令创建文件 语法&#xff1a;touch [选项] Linux路径 touch命令&#xff0c;参数必填&#xff0c;表示要创建的文件路径&#xff0c;相对、绝对、特殊路径符均可以使用。 touch 命令不光可以用来创建文件&#xff08;当指定操作文件不存在时&a…

【Redis】聊一下缓存雪崩、击穿、穿透、预热

缓存的引入带来了数据读取性能的提升&#xff0c;但是因此也引入新的问题&#xff0c;一个是数据双写一致性&#xff0c;另一个就是雪崩、击穿、穿透&#xff0c;那么如何解决这些问题&#xff0c;我们来说下对应的问题和解决方案 雪崩 缓存雪崩&#xff1a;同一时间内大量请…

pg事务:事务相关元组结构

事务相关的元组结构 元组结构中包含很多pg的mvcc所必要的信息&#xff0c;下面的内容将梳理xmin,xmax,t_ctid,cmin,cmax,combo cid,tuple id的含义和关系 物理结构 HeapTupleHeaderData相当于tuple的header&#xff0c;其结构在src/include/access/htup_details.h中定义 typ…

【BIO、NIO、AIO、Netty】

什么是IO Java中I/O是以流为基础进行数据的输入输出的&#xff0c;所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。简单来说就是java通过io流方式和外部设备进行交互。在Java类库中&#xff0c;IO部分的内容是很庞大的&#xff0c;因为它涉及的领域很广…

win--C盘程序员常见应用内存空间处理

写在前面&#xff1a; 本篇用于记录我对于C盘各个应用内存处理的总结&#xff0c; 文章目录 前置知识vscode的.vscode文件迁移可以移动 软件推荐wsl和docker存储管理修改安装目录压缩磁盘 pip缓存清理JetBrains系列 前置知识 在win中有着这样一个命令mklink&#xff0c;可以…

Java飞行记录器

目录 JFR和JMC启动飞行记录用JFR对比不同GC器运行结果记录结果GC配置GC Summary垃圾收集 JFR和JMC JFR全称为Java Flight Recorder&#xff0c;即Java飞行记录器 JMC全称为JDK Mission Control&#xff0c;即JDK任务控制 先贴一段官网的简介&#xff1a; Java Flight Recorder…

基于鸿蒙系统的智能衣柜管理系统设计与实现_kaic

摘 要 随着城市的扩大与科学技术的发展&#xff0c;人们逐渐开始关注衣柜功能的改进&#xff0c;存储效果的优化和智能使用的升级。个性化、功能化、智能化的衣柜将出现在人们的家庭生活中&#xff0c;并且起到重要作用。 为了满足当前人们对智能衣柜的需求&#xff0c;本设计…

面试真的被问麻了......

前几天组了一个软件测试面试的群&#xff0c;没想到效果直接拉满&#xff0c;看来大家对面试这块的需求还是挺迫切的。昨天我就看到群友们发的一些面经&#xff0c;感觉非常有参考价值&#xff0c;于是我就问他还有没有。 结果他给我整理了一份非常硬核的面筋&#xff0c;打开…

Java -并发(多线程)-Interview面试题收集

1、多线程并发 1&#xff09;多线程中 synchronized 锁升级的原理是什么&#xff1f; synchronized 锁升级原理&#xff1a;在锁对象的对象头里面有一个 threadid 字段&#xff0c;在第一次访问的时候 threadid 为空&#xff0c;jvm 让其持有偏向锁&#xff0c;并将 threadid…

Mabatis Plus 之ID生成策略控制(Auto、Input、assign_id、assign_uuid)

文章目录 知识点1&#xff1a;TableId1 环境构建2 代码演示AUTO策略步骤1:设置生成策略为AUTO步骤2:删除测试数据并修改自增值步骤3:运行新增方法 INPUT策略步骤1:设置生成策略为INPUT步骤2:添加数据手动设置ID步骤3:运行新增方法 ASSIGN_ID策略步骤1:设置生成策略为ASSIGN_ID步…

HTTPS的工作流程

hi,大家好,好久不见,今天为大家带来HTTPS协议的工作流程 认识HTTPS 加密是什么 HTTPS的工作流程 1.认识HTTPS HTTPS也是应用层协议,让我们再来回忆一下TCP/IP五层协议模型 HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP协议在传输的时候是以…

2023河海大学838计算机学硕考研高分经验分享

大家好&#xff0c;我是陪你考研每一天的大巴学长。 大巴学长为大家邀请到了2023年838计算机学硕初试第二名的高分学长&#xff0c;为大家分享一下他的考研经验&#xff0c;经验里详细介绍了各科的复习方法&#xff0c;很有参考意义。 希望对大家有所借鉴和帮助&#xff0c;在…

C++13-STL模板-01向量(vector)

C13-STL模板 在线练习&#xff1a; http://noi.openjudge.cn/ https://www.luogu.com.cn/ 大纲要求 【 3 】算法模板库中的函数&#xff1a;min、max、swap、sort 【 4 】栈 (stack)、队列 (queue)、链表 (list)、 向量&#xff08;vector&#xff09;等容器 1.函数模板 泛…

HNU数据结构与算法分析-作业1-算法分析

1. (简答题) 1.&#xff08;教材3.4&#xff09;&#xff08;a&#xff09;假设某一个算法的时间代价为 &#xff0c;对于输入规模n&#xff0c;在某台计算机上实现并完成该算法的时间为t秒。现在另有一台计算机&#xff0c;运行速度为第一台的64倍&#xff0c;那么t秒内新机器…

FreeRTOS(5)----互斥量

一&#xff0c;互斥信号量 互斥信号量是一个具有优先级继承的二值信号量&#xff0c;在同步的应用中二值信号量最合适。互斥信号量适合互斥访问的那些应用。在互斥访问中互斥信号量相当于一个钥匙&#xff0c;当一个任务使用这个资源&#xff0c;资源就会被上锁&#xff0c;防…