Я работаю над алгоритмом графического процессора, который выполняет сложные математические вычисления, в основном связанные с матрицами и векторами. Хотя у меня хорошие показатели с точки зрения времени обработки, я все еще чувствую, что есть место для улучшений.
Так что я открыл для себя Metal Performance Shaders
framework. Описание этого фреймворка взволновало меня, потому что я могу найти точно настроенные и оптимизированные шейдеры ядра для математических операций, которые выполняет мой алгоритм GPU.
Я решил сначала использовать MPSMatrixVectorMultiplication
, потому что у меня большое умножение 11000x500
матрица на 11000 vector
с выводом 500
вектора.
Так вот, как я это использую. Объявите MPS
оболочки для MTLBuffer
s и саму операцию:
MPSMatrix *model;
MPSVector *vector;
id<MTLBuffer> resultBuffer;
MPSVector *resultVector;
MPSMatrixVectorMultiplication *matrixVectorMultiplication;
Инициализируйте эти MPS
оболочки:
matrixVectorMultiplication = [[MPSMatrixVectorMultiplication alloc] initWithDevice:_ctx.device transpose:true rows:500 columns:11000 alpha:1 beta:0];
//......//
MPSVectorDescriptor *desc = [MPSVectorDescriptor vectorDescriptorWithLength:11000 dataType:MPSDataTypeFloat32];
vector = [[MPSVector alloc] initWithBuffer:vecBuffer descriptor:desc];
MPSVectorDescriptor *desc_out = [MPSVectorDescriptor vectorDescriptorWithLength:500 dataType:MPSDataTypeFloat32];
resultVector = [[MPSVector alloc] initWithBuffer:resultBuffer descriptor:desc_out];
//......//
MPSMatrixDescriptor *desc = [MPSMatrixDescriptor matrixDescriptorWithRows:11000 columns:500 rowBytes:500 * sizeof(float) dataType:MPSDataTypeFloat32]; //I need to transpose the matrix
model = [[MPSMatrix alloc] initWithBuffer:testBuffer descriptor:desc];
И сделайте умножение:
id<MTLCommandBuffer> cmdBuffer = [_ctx.commandQueue commandBuffer];
id<MTLComputeCommandEncoder> encoder = [cmdBuffer computeCommandEncoder];
// work with my own encoder, execute some commands
[encoder endEncoding];
[matrixVectorMultiplication encodeToCommandBuffer:cmdBuffer inputMatrix:model inputVector:vector resultVector:resultVector];
[cmdBuffer commit];
[cmdBuffer waitUntilCompleted]; // I have to wait because my algorithm is sequential at this point
Теперь функция ядра, которую я написал, выполняет точно такое же умножение примерно за 0.8-1.1
мс. И мне было очень грустно узнать, что MPSMatrixVectorMultiplication
сделал это за 18-19 ms
!
Это слишком медленно, и я не могу поверить в такой результат. Понятно, что мне не хватает какой-то крошечной детали, которая сильно влияет на производительность.
Есть ли кто-нибудь, кто использовал решения MPS
в чувствительном к производительности коде? Я был бы рад услышать несколько советов, которые я могу применить в своей рутине GPU.
Заранее спасибо!