向量化實現矩陣運算優化(一)

来源:https://www.cnblogs.com/ChebyshevTST/archive/2023/09/28/17736015.html
-Advertisement-
Play Games

文件目錄結構 tree . ├── bin ├── include │ └── calc.h ├── lib │ ├── add.c │ ├── div.c │ ├── mul.c │ └── sub.c └── src └── main.c 4 directories, 6 files 靜態庫生成 ...


xsimd簡介

  xsimd是C++的一個開源simd庫,實現了對常見simd指令的封裝,從而使得simd的操作更為簡單。接下來先從兩個簡單的例子來入門xsimd。

void average(const std::vector<double>& v1, const std::vector<double>& v2, std::vector<double>& v) {
    int n = v.size();
    int size = xsimd::batch<double, xsimd::avx>::size;
    int loop = n - n % size;

    for (int i = 0; i < loop; i += size) {
        auto a = xsimd::batch<double>::load_unaligned(&v1[i]);
        auto b = xsimd::batch<double>::load_unaligned(&v2[i]);
        auto res = a + b; 
        res.store_unaligned(&v[i]);
    }
    for (int i = loop; i < n; ++i) 
        v[i] = v1[i] + v2[i];
}

  上述demo實現了兩個向量相加的操作,由於每次都能從vector當中載入size個數據,因此對剩餘的不能進行vectorize的數據進行了分別處理。比如說,有一百個數據,每次處理8個數據,到最後剩下4個數不能湊到8,所以用朴素的迭代方式進行求和。這個demo是非對齊記憶體的處理方式。

using vector_type = std::vector<double, xsimd::default_allocator<double>>;
std::vector<double> v1(1000000), v2(1000000), v(1000000);
vector_type s1(1000000), s2(1000000), s(1000000);

void average_aligned(const vector_type& s1, const vector_type& s2, vector_type& s) {
    int n = s.size();
    int size = xsimd::batch<double>::size;
    int loop = n - n % size;

    for (int i = 0; i < loop; i += size) {
        auto a = xsimd::batch<double>::load_aligned(&s1[i]);
        auto b = xsimd::batch<double>::load_aligned(&s2[i]);
        auto res = a + b;
        res.store_aligned(&s[i]);
    }

    for (int i = loop; i < n; ++i) 
        s[i] = s1[i] + s2[i];
}

  要實現對齊記憶體的操作方式,我們必須對vector指定特定的分配器,不然最後運行出來的代碼會出現segment fault。

  總之,要記住常用的api,load_aligned, store_aligned, load_unaligned, store_unaligned,它們分別對應了記憶體對齊與否的處理方式。接下來我們再講解另外一個demo,並且提供與openmp的性能對比。

auto sum(const std::vector<double>&v) {
    int n = v.size();
    int size = xsimd::batch<int>::size;
    int loop = n - n % size;

    double res{};
    for (int i = 0; i < loop; ++i) {
        auto tmp = xsimd::batch<int>::load_unaligned(&v[i]);
        res += xsimd::hadd(tmp);
    }

    for (int i = loop; i < n; ++i) {
        res += v[i];
    }

    return res;
}

auto aligned_sum(const std::vector<double, xsimd::default_allocator<double>>& v) {
    int n = v.size();
    int size = xsimd::batch<int>::size;
    int loop = n - n % size;

    double res{};
    for (int i = 0; i < loop; ++i) {
        auto tmp = xsimd::batch<int>::load_aligned(&v[i]);
        res += xsimd::hadd(tmp);
    }

    for (int i = loop; i < n; ++i) {
        res += v[i];
    }
    
    return res;
}

  這個例子實現了對向量求和的功能。總體與前面基本一樣,這裡hadd是一個對向量求和的函數。

  對於openmp的向量化實現,則較為簡單,只需要在for迴圈上面加上特定指令即可。不過需要註意的是,openmp支持C語法,有一些C++的新特性可能並不支持,而且需要把花括弧放到下一行,我們來看具體操作。

auto parallel_sum(const std::vector<double>& v) {
    double res{};

    int n = v.size();
    #pragma omp simd
    for (int i = 0; i < n; ++i)
        res += v[i];

    return res;
}

  不要忘記加上編譯選項-fopenmp和-march=native,為了性能測試,我開啟了O2優化,以下是簡單的測試結果,數據規模是一千萬。

  一般情況下進行了記憶體對齊都會比沒有對齊的要快一些,同時可以看到openmp與xsimd也差了一個量級。當然不同平臺的結果可能會有差異,需要用更專業的工具進行測量比較。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在Python中,字元串可以用單引號或雙引號括起來。'hello' 與 "hello" 是相同的。您可以使用print()函數顯示字元串文字: 示例: print("Hello") print('Hello') 將字元串分配給變數是通過變數名後跟等號和字元串完成的: 示例 a = "Hello" p ...
  • 前言 ThreadLocal可以用來存儲線程的本地數據,做到線程數據的隔離 ThreadLocal的使用不當可能會導致記憶體泄漏,排查記憶體泄漏的問題,不僅需要熟悉JVM、利用好各種分析工具還耗費人工 如果能明白其原理並正確使用,就不會導致各種意外發生 本文將從使用場景、實現原理、記憶體泄漏、設計思想等層 ...
  • 目錄場景1 定義全部異常處理類2 替換request引用3 代碼優化總結 場景 本文前端用的是阿裡的Ant-Design框架,其他框架也有全局攔截器,思路是相同,具體實現自行百度下吧 因為每次都需要調介面,都需要單獨處理異常情況(code !=0),因此前端需要對後端返回的通用響應進行統一處理,比如 ...
  • 在Dart學習的第02天,我們通過基礎語法說明和樣例代碼的方式,學習了Dart的16個基礎語法,這些基礎語法給我們後面編寫的Flutter程式打下來堅實基礎。今天,我們繼續深入學習Dart乃至所有編程語言都非常重要的部分:可迭代的集合…… ...
  • 本篇博文圍繞使用Python開發熱門游戲2048 GAME(命令行版本) 代碼未做任何優化(原生且隨意)、全程以面向過程、MVC的設計思想為主、開發環境是Ubuntu系統下的Pycharm 2048是我很久以前學習Python過程中的一個作業,接下來直入正題—— 一、瞭解游戲 1. 介紹 《2048 ...
  • 這是一個FTP(文件傳輸協議)管理工具,能夠支持文件上傳下載以及操作服務端的文件。 該工具由客戶端和服務端組成。客戶端與服務端通過Socket連接實現通信,客戶端發送命令,服務端解析並執行相應的操作。部分代碼已省略,下麵是服務端和客戶端代碼的詳細解釋。 GitHub:https://github.c ...
  • 基於java線上調查問卷系統設計與實現(含配套lun文,ppt),可適用於基於java線上校園調查問卷,基於java校園問卷調查系統,java問卷調查系統,校園線上問卷調查,校園線上調查問卷系統設計,調查問卷管理系統,基於Javaweb實現線上調查問卷系統,網上調查問卷系統,網上問卷調查系統等等; ...
  • 現象 大量的分支選擇型代碼段看著讓人頭疼 for (Field field : declaredFields) { Class<?> type = field.getType(); String key = field.getName(); Element result = resultMap.ad ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...