1. C++ 17 if constexpr 述句

    C++ 17 新增的 if constexpr 述句能讓我們用更簡潔的方式編寫樣版特化(Template Specialization)。本文會介紹它的語法與應用。

    語法

    if constexpr 述句的語法與一般的 if 述句相似。兩者的差異在於 if 關鍵字與刮號之間多了一個 constexpr 關鍵字:

    if constexpr ( condition ) then-statement

    if constexpr ( condition ) then-statement else else-statement

    其中,condition 必須是編譯期能確定數值的 constexpr 且該數值必須能被轉型為 boolconstexpr 包含以下常用的表達式:

    • <type_traits> 標頭檔定義的 Type Traits:
      • std::is_integral_v<T>
      • std::is_array_v<T>
      • std::is_reference_v …

    More

  2. C++ 17 類別樣版參數推導

    今天我想要介紹 C++ 17 的類別樣版參數推導(Class Template Argument Deduction)。在 C++ 17 之前,樣版參數推導(Template Argument Deduction)只會被施行於「函式樣版(Function Template)」。以 std::pair 為例,如果我們要呼叫 std::pair 的建構式創建一個 std::pair<double, int> 暫時物件,我們必須指定所有 std::pair 的樣版參數:

    std::pair<double, int>(5.0, 1)
    

    然而明確地指定樣版參數太過繁瑣,我們通常會另外定義一個函式樣版(Function Template …

    More

  3. C++ 17 折疊表達式

    C++ 11 引入了 Variadic Template,讓我們得以宣告任意個數的樣版參數。C++ 標準函式庫的 std::make_tuple 就是一個典型的例子:

    #include <tuple>
    
    int main() {
      auto a = std::make_tuple("a");
      auto b = std::make_tuple(1, "a");
      auto c = std::make_tuple(1.0, 1, "a");
    }
    

    如果我們想要編寫一個 sum() 函式累加所有的參數,我們該怎麼作呢?更具體的說,我們要怎麼改寫以下 sum() 函式,使它們能接收任意個數任意型別的參數:

    int sum(int x0 …

    More

  4. C++ 17 選擇述句與初始化述句

    C++ 98 程式語言標準將 if、switch、while 與 for 述句的文法依序定義為:

    if (condition) statement
    if (condition) statement else statement
    switch (condition) statement
    while (condition) statement
    for (for-init-statement conditionopt; expression) statement

    其中,我們能在 condition 宣告一個變數[1],並使用此變數的數值控制執行流程。例如:

    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    
    int main() {
      std::srand(std::time(NULL));
    
      if …

    More

  5. C++ 17: 以 std::scoped_lock 避免 Dead Lock

    最佳化多執行緒程式時,為了減少非必要阻塞(Blocking),常見作法是將一個 Mutex 依照保護對象拆分為多個 Mutex。如此一來,一個執行緒只需鎖定它需要的 Mutex,不必等待它不需要的 Mutex。有時我們會進一步實作「並行資料結構(Concurrent Data Structure)」,將 Mutex 的保護對象縮小到資料結構的節點,讓多個執行緒能同時讀寫一個資料結構。

    然而,同時操作多個 Mutex 必需留意一些技術細節。舉例來說,以下程式碼有問題:

    #include <mutex>
    
    struct Node {
      std::mutex m;
      int data;
    };
    
    void swap(Node &lhs, Node &rhs) {
      if (&lhs == &rhs) return;
      std::lock_guard …

    More

  6. C++ 17 結構化綁定

    今天我想要介紹 C++ 17 新增的 Structured Binding(結構化綁定)。以 std::pair 為例,Structured Binding 能讓我們能直接將 std::pair 的內容綁定到我們指定的識別字:

    auto [a, b] = std::make_pair("str", 0);
    

    在這個例子𥚃,a 是型別為 const char *"str"b 是型別為 int0。換句話說,上面的程式碼相當於:

    const char *a = "str";
    int b = 0;
    

    這讓我們能簡化「接收 std::pair …

    More

  7. 漫談 C/C++ 巨集展開規則

    最近工作上遇到一個和 C/C++ 巨集有關的問題。我想要使用巨集將原本呼叫 bcopy 的程式碼導向另一個實作 __bionic_bcopy。所以我寫出以下的程式碼:

    #define bcopy __bionic_bcopy
    

    然而這段程式碼會使得部分程式無法被正常地編譯。如果我將上面的 #define 改為:

    #define bcopy(src, dst, size) __bionic_copy(src, dst, size)
    

    原本被第一個 #define 弄壞的程式就能被正常地編譯了。然而這兩個 #define 的差異是什麼呢?以下是引起錯誤的程式片段:

    builtin.def

    #ifndef BUILTIN_LIBC
    #define BUILTIN_LIBC(NAME) BUILTIN(NAME)
    #endif
    
    BUILTIN_LIBC(bcopy)
    

    builtin.cpp

    enum BuiltinFunction {
    #define BUILTIN …

    More

  8. 簡介 perf_events 與 Call Graph

    Call Graph 是幫助 Perf Events 使用者判讀效能瓶頸成因的重要工具。Call Graph 優雅地結合「花去最多執行時間的熱區」與「為什麼要執行熱區內的程式碼」進而讓使用者能快速判斷程式有沒有改進空間。本文會從 Call Graph 的基本概念著手,再介紹記錄 Stack Trace 的注意事項與判讀 Call Graph 的方式。最後,本文會以一個文字處理程式示範如何利用 Call Graph 找出效能問題。

    Call Graph 概論

    perf report 印出的 Call Graph(呼叫圖)是以各個樣本的 Stack Trace(堆疊回溯)為基礎繪製而成的樹狀圖。因此本節會依序介紹 Stack Trace 與兩種不同的 Call Graph。

    Stack …

    More

  9. 使用 perf_events 分析程式效能

    在最佳化程式之前,我們必須要先測量程式的執行狀況,如此我們才能對症下藥。本文要介紹 Linux 核心內建的系統效能分析工具——perf_events

    perf_events

    perf_events 是 Linux 核心內建的系統效能分析工具。perf_events 一開始的主要功能是存取硬體效能計數器,所以最早的名字是 Performance Counters for Linux (PCL)。隨著功能不斷擴充,perf_events 能處理的事件來源已經不限於硬體效能計數器,所以改名為 perf_events

    有時候 perf_events 也被簡稱為 Perf。然而因為 Perf 作為一個單字是難以搜尋的常見字𢑥,所以 Vince WeaverBrendan Gregg 前輩通常使用 perf_events 稱呼這套工具。

    perf_events 這套工具分為三個部分:

    • 在 User Space 的 perf 指令
    • 在 …

    More

  10. The Case of the Missing Supercomputer Performance 心得

    因為最近的工作需求,我開始學習與補強系統效能分析方面的知識。所以我把同事之前推薦的論文 The Case of the Missing Supercomputer Performance [Fabrizio Petrini et al. 2003] 拿出來仔細研究。

    摘要

    這篇論文提出一個重要觀察:背景程式(Daemon)的干擾有時會嚴重影響特定負載(Workload)的執行速度。如果能妥善處理這些干擾,有機會可以讓總執行時間減半。

    這個結論在當時是非常特別的。因為在分析程式效能的時候,直覺的作法是專注分析「程式本身」的問題。有時候會從理論分析演算法或計算流程有沒有改善空間。有時是對程式做 Profiling,尋找有沒有明顯的熱區或者效能瓶頸。有時是改進編譯器,讓編譯器可以產生比較好的機器碼。然而這些作法背後都隱含一個假設:執行程式時,這個程式可以完全享有整個系統的計算資源。這對現代「分時多工的計算系統」而言是不成立的。

    論文舉出需要「Fine-Grained Synchronization」的負載特別容易被背景程式影響。以下是用 OpenMP 編寫的示意程式碼:

    for …

    More

« Prev Page 2 / 3 Next »