跳轉到內容

Ada 樣式指南/改進效能

來自 Wikibooks,開放書籍,面向開放世界

面向物件特性 · 可移植的哲學家用餐問題示例

在許多方面,效能與可維護性和可移植性相矛盾。為了提高速度或記憶體使用率,最清晰的演算法有時會讓位於混亂的程式碼。為了利用專用硬體或作業系統服務,引入了不可移植的實現依賴項。在關注效能時,您必須確定每個演算法如何滿足其效能和可維護性目標。謹慎使用本章中的指南;它們可能對您的軟體有害。

構建滿足其效能要求的系統的最佳方法是透過良好的設計。您不應假設加速程式碼會導致系統執行速度的明顯提高。在大多數應用程式中,系統的整體吞吐量不是由程式碼的執行速度定義的,而是由併發程序之間的互動以及系統外圍裝置的響應時間定義的。

本章中的大多數指南都寫著“......當衡量的效能表明”。“表明”意味著您已確定,在您的環境中,應用程式效能提升帶來的好處勝過由此產生的程式碼的可理解性、可維護性和可移植性方面的負面影響。許多指南示例展示了您需要衡量的替代方案,以便確定是否需要使用該指南。

效能問題

[編輯 | 編輯原始碼]

效能至少有四個方面:執行速度、程式碼大小、編譯速度和連結速度。雖然所有四個方面都很重要,但大多數人在提到效能時都會想到執行速度,本章中的大多數指南都側重於執行速度。

效能受許多因素的影響,包括編譯軟體、硬體、系統負載和編碼風格。雖然通常只有編碼風格受程式設計師控制,但其他因素的影響如此之大,以至於不可能做出“case語句比if-then-else結構更高效”之類的斷言。當效能至關重要時,不能假設在一種系統上證明更高效的編碼風格在另一種系統上也會更高效。為了提高效能而做出的決定必須基於對應用程式將要執行的實際系統的替代方案進行測試。

效能測量

[編輯 | 編輯原始碼]

雖然大多數知名的效能測量工具都是獨立程式,專注於執行速度,但有一個全面的工具涵蓋了效能的四個方面。Ada編譯器評估系統(ACES)是合併了兩個早期產品的結果:美國國防部的Ada編譯器評估能力和英國國防部的Ada評估系統。它提供了一套全面的近2000個性能測試,以及自動設定、測試管理和分析軟體。該系統報告(並對統計資料進行分析)編譯時間、連結時間、執行時間和程式碼大小。分析工具可以比較多個編譯執行系統,並比較使用不同編碼風格以實現類似目的的測試的執行時效能。

效能問題工作組(PIWG)套件。Quick-Look工具被宣傳為易於下載、安裝和執行,並在不到一天的時間內提供與PIWG套件生成的相同有用的資訊。此外,sw-eng.falls-church.va.us,目錄 /public/AdaIC/testing/aces。對於全球資訊網訪問,請使用以下統一資源定位器(URL):http://sw-eng.falls-church.va.us/AdaIC/testing/aces/.

雖然測量效能似乎是一件比較簡單的事情,但任何計劃進行這種測量的人或工具集都必須解決一些重要問題。有關詳細資訊,請參閱以下資料:ACES(1995a、1995b、1995c);Clapp、Mudge 和 Roy(1990);Goforth、Collard 和 Marquardt(1990);Knight(1990);Newport(1995);以及Weidermann(1990)。

程式結構

[編輯 | 編輯原始碼]
  • 當測量效能表明時,使用塊(見指南 5.6.9)引入延遲初始化。
   ...
   Initial : Matrix;

begin  -- Find_Solution

   Initialize_Solution_Matrix:
      for Row in Initial'Range(1) loop
         for Col in Initial'Range(2) loop
            Initial (Row, Col) := Get_Value (Row, Col);
         end loop;
      end loop Initialize_Solution_Matrix;

   Converge_To_The_Solution:
      declare

         Solution       : Matrix           := Identity;
         Min_Iterations : constant Natural := ...;

      begin  -- Converge_To_The_Solution
         for Iterations in 1 .. Min_Iterations loop
            Converge (Solution, Initial);
         end loop;

      end Converge_To_The_Solution;

   ...
end Find_Solution;

基本原理

[編輯 | 編輯原始碼]

延遲初始化允許編譯器在暫存器使用最佳化方面有更多選擇。根據具體情況,這可能會帶來顯著的效能提升。

有些編譯器在引入宣告塊時會造成效能損失。程式設計師需要仔細分析和計時測試,以識別應該刪除的那些宣告塊。

很難透過程式碼檢查準確預測哪些宣告塊會提高效能,哪些宣告塊會降低效能。但是,透過這些一般準則和對特定實現的熟悉,可以提高效能。

資料結構

[編輯 | 編輯原始碼]

動態陣列

[編輯 | 編輯原始碼]
  • 當測量效能表明時,使用約束陣列。

基本原理

[編輯 | 編輯原始碼]

如果陣列邊界在執行時之前未知,那麼這些邊界的計算可能會影響執行時效能。使用命名常量或靜態表示式作為陣列邊界,可能會比使用變數或非靜態表示式提供更好的效能。因此,如果 Lower 和 Upper 的值在執行時之前沒有確定,那麼

... is array (Lower .. Upper) of ...

可能會導致地址和偏移量計算延遲到執行時,從而造成效能損失。有關權衡和替代方案的詳細討論,請參閱 NASA(1992)。

基於零的陣列

[編輯 | 編輯原始碼]
  • 當測量效能表明時,為陣列使用基於零的索引。

基本原理

[編輯 | 編輯原始碼]

對於某些編譯器,下界為 0(整數零或列舉型別的第一個值)的陣列的偏移量計算會簡化。對於其他編譯器,如果下界為 1,則更有可能進行最佳化。

無約束記錄

[編輯 | 編輯原始碼]
  • 當測量效能表明時,為記錄使用固定大小的元件。
subtype Line_Range   is Integer range 0 .. Max_Lines;
subtype Length_Range is Integer range 0 .. Max_Length;

-- Note that Max_Lines and Max_Length need to be static
type Paragraph_Body is array (Line_Range range <>, Length_Range range <>) of Character;

type Paragraph (Lines : Line_Range := 0; Line_Length : Length_Range := 0) is
   record
      Text : Paragraph_Body (1 .. Lines, 1 .. Line_Length);
   end record;

基本原理

[編輯 | 編輯原始碼]

確定無約束記錄的大小和速度影響,這些記錄的元件取決於鑑別符。有些編譯器會為型別的每個物件分配最大可能的大小;其他編譯器會使用指向相關元件的指標,從而可能會造成堆效能損失。考慮使用固定大小的元件的可能性。

記錄和陣列

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,將記錄陣列定義為並行陣列。
    -- Array of records
    Process (Student (Index).Name, Student (Index).Grade);
    -- Record of arrays
    Process (Student.Name (Index), Student.Grade (Index));
    -- Parallel arrays
    Process (Name (Index), Grade (Index));

基本原理

[編輯 | 編輯原始碼]

確定將資料結構化為記錄陣列、包含陣列的記錄或並行陣列的影響。Ada 的一些實現會在這些示例中顯示出顯著的效能差異。

記錄和陣列聚合

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用一系列賦值來進行聚合。

基本原理

[編輯 | 編輯原始碼]

確定使用聚合與一系列賦值的影響。使用聚合通常需要使用臨時變數。如果聚合是“靜態的”(即,其大小和元件在編譯或連結時已知,允許連結時分配和初始化),那麼它通常比一系列賦值更高效。如果聚合是“動態的”,那麼一系列賦值可能更高效,因為不需要臨時變數。

有關從可讀性和可維護性角度討論聚合,請參見指南 5.6.10。

有關擴充套件聚合的討論,請參見指南 10.6.1。

演算法

[編輯 | 編輯原始碼]

Mod 和 rem 運算子

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用增量方案而不是 mod 和 rem。
   -- Using mod
   for I in 0 .. N loop
      Update (Arr (I mod Modulus));
   end loop;

   -- Avoiding mod
   J := 0;
   for I in 0 .. N loop
      Update (Arr (J));
      J := J + 1;
      if J = Modulus then
         J := 0;
      end if;
   end loop;

基本原理

[編輯 | 編輯原始碼]

確定使用 mod 和 rem 運算子的影響。上面的一種樣式可能比另一種明顯更高效。

短路運算子

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用短路控制形式。
   -- Nested "if"
   if Last >= Target_Length then
      if Buffer (1 .. Target_Length) = Target then
         ...
      end if;
   end if;

   -- "and then"
   if Last >= Target_Length and then Buffer (1 .. Target_Length) = Target then
      ...
   end if;

基本原理

[編輯 | 編輯原始碼]

確定使用巢狀 if 語句與使用 and thenor else 運算子的影響。上面的一種可能比另一種明顯更高效。

Case 語句與 elsif

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用 case 語句。
   subtype Small_Int is Integer range 1 .. 5;
   Switch : Small_Int;
   ...
   -- Case statement
   case Switch is
      when 1 => ...
      when 2 => ...
      when 3 => ...
      when 4 => ...
      when 5 => ...
   end case;

   -- "elsif construct"
   if Switch = 1 then
      ...
   elsif Switch = 2 then
      ...
   elsif Switch = 3 then
      ...
   elsif Switch = 4 then
      ...
   elsif Switch = 5 then
      ...
   end if;

基本原理

[編輯 | 編輯原始碼]

確定使用 case 語句與 elsif 結構的影響。如果 case 語句是使用小型跳轉表實現的,那麼它可能比 if .. then .. elsif 結構明顯更高效。

有關表驅動程式設計替代方案的討論,另請參見指南 8.4.6。

檢查約束錯誤

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用硬編碼約束檢查。
   subtype Small_Int is Positive range Lower .. Upper;
   Var : Small_Int;
   ...

   -- Using exception handler
   Double:
      begin
         Var := 2 * Var;
      exception
         when Constraint_Error =>
            ...
      end Double;

      -- Using hard-coded check
      if Var > Upper / 2 then
         ...
      else
         Var := 2 * Var;
      end if;

基本原理

[編輯 | 編輯原始碼]

確定使用異常處理程式來檢測約束錯誤的影響。如果異常處理機制很慢,那麼硬編碼檢查可能更高效。

陣列處理順序

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用二維陣列的列優先處理。
    type Table_Type is array (Row_Min .. Row_Max, Col_Min .. Col_Max) of ...
    Table : Table_Type;
    ...
    -- Row-order processing
    for Row in Row_Min .. Row_Max loop
       for Col in Col_Min .. Col_Max loop
          -- Process Table (Row, Col)
       end loop;
    end loop;
    -- Column-order processing
    for Col in Col_Min .. Col_Max loop
       for Row in Row_Min .. Row_Max loop
          -- Process Table (Row, Col)
       end loop;
    end loop;

基本原理

[編輯 | 編輯原始碼]

確定以行優先順序處理二維陣列與以列優先順序處理二維陣列的影響。雖然大多數 Ada 編譯器可能使用行優先順序,但這不是必需的。在存在良好最佳化的前提下,上面的示例可能沒有顯著差異。在這裡,使用靜態陣列邊界也可能很顯著。請參見指南 10.4.1 和 10.4.2。

分配備選方案

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用覆蓋來進行條件賦值。
   -- Using "if .. else"
   if Condition then
      Var := One_Value;
   else
      Var := Other_Value;
   end if;
   -- Using overwriting
   Var := Other_Value;
   if Condition then
      Var := One_Value;
   end if;

基本原理

[編輯 | 編輯原始碼]

確定分配備選值的樣式的影響。示例說明了兩種常見的執行方法;對於許多系統,效能差異是顯著的。

壓縮布林陣列移位

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,透過使用切片賦值而不是重複位賦值來執行壓縮布林陣列移位操作。
   subtype Word_Range is Integer range 0 .. 15;
   type Flag_Word is array (Word_Range) of Boolean;
   pragma Pack (Flag_Word);
   Word : Flag_Word;
   ...

   -- Loop to shift by one bit
   for Index in 0 .. 14 loop
      Word (Index) := Word (Index + 1);
   end loop;
   Word (15) := False;

   -- Use slice assignment to shift by one bit
   Word (0 .. 14) := Word (1 .. 15);
   Word (15) := False;

基本原理

[編輯 | 編輯原始碼]

確定切片操作在移位壓縮布林陣列時的影響。對於使用壓縮布林陣列的 Ada 83 實現,當使用切片賦值而不是 for 迴圈每次移動一個元件時,移位操作可能快得多。對於 Ada 95 實現,考慮使用模組型別(參見指南 10.6.3)。

子程式排程

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用靜態子程式排程。

本例中的“靜態排程”一詞指的是使用 if/elsif 序列來顯式確定要呼叫的子程式,具體取決於某些條件。

    -- (1) Dispatching where tag is not known at compile time
    --     (See ACES V2.0 test "a9_ob_class_wide_dynamic_01")
    -- Object_Type is a tagged type
    -- The_Pointer designates Object_Type'Class;
    -- Subclass1_Pointer designates Subclass1 (derived from Object_Type)
    -- Subclass2_Pointer designates Subclass2 (derived from Subclass1)
    -- Subclass3_Pointer designates Subclass3 (derived from Subclass2)
    Random_Value := Simple_Random; -- Call to a random number generator
    if Random_Value < 1.0/3.0 then
       The_Pointer := Subclass1_Pointer;
    elsif Random_Value > 2.0/3.0 then
       The_Pointer := Subclass2_Pointer;
    else
       The_Pointer := Subclass3_Pointer;
    end if;
    Process (The_Pointer.all);  -- Tag is unknown
    -- (2) Tag is determinable at compile time (static dispatching)
    --     (See ACES V2.0, test "a9_ob_class_wide_static_01")
    -- Object_Type is a tagged type
    -- The_Pointer designates Object_Type'Class;
    -- Subclass1_Pointer designates Subclass1 (derived from Object_Type)
    -- Subclass2_Pointer designates Subclass2 (derived from Subclass1)
    -- Subclass3_Pointer designates Subclass3 (derived from Subclass2)
    Random_Value := Simple_Random; -- Call to a random number generator
    if Random_Value < 1.0/3.0 then
       Process (Subclass1_Pointer.all);
    elsif Random_Value > 2.0/3.0 then
       Process (Subclass2_Pointer.all);
    else
       Process (Subclass3_Pointer.all);
    end if;
    -- (3) No tagged types are involved (no dispatching)
    --     (See ACES V2.0, test "ap_ob_class_wide_01")
    -- Object_type is a discriminated type with variants; possible
    -- discriminant values are Subclass1, Subclass2, and Subclass3
    -- All the pointers designate values of Object_Type
    -- Subclass1_Pointer := new Object_Type (Subclass1);
    -- Subclass2_Pointer := new Object_Type (Subclass2);
    -- Subclass3_Pointer := new Object_Type (Subclass3);
    -- There is only one "Process" procedure (operating on Object_Type)
    Random_Value := Simple_Random; -- Call to a random number generator
    if Random_Value < 1.0/3.0 then
       Process (Subclass1_Pointer.all);
    elsif Random_Value > 2.0/3.0 then
       Process (Subclass2_Pointer.all);
    else
       Process (Subclass3_Pointer.all);
    end if;

基本原理

[編輯 | 編輯原始碼]

確定動態和靜態子程式排程的影響。編譯器可能為一種排程形式而不是另一種形式生成更高效的程式碼。

動態排程幾乎肯定比顯式的 if . . . elsif 序列更有效。但是,您應該注意編譯器可能做出的任何影響這種情況的最佳化決策。

型別擴充套件的聚合

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,只使用簡單的聚合。
   type Parent is tagged
      record
         C1 : Float;
         C2 : Float;
      end record;

   type Extension is new Parent with
      record
         C3 : Float;
         C4 : Float;
      end record;

   Parent_Var : Parent := (C1 => Float_Var1, C2 => Float_Var2);
   Exten_Var  : Extension;
   ...
   -- Simple aggregate
   -- (See ACES V2.0, test "a9_ob_simp_aggregate_02")
   Exten_Var := (C1 => Float_Var1, C2 => Float_Var2,
                 C3 => Float_Var3, C4 => Float_Var4);
   -- Extension aggregate
   -- (See ACES V2.0, test "a9_ob_ext_aggregate_02")
   Exten_Var := (Parent_Var with C3 => Float_Var3, C4 => Float_Var4);

基本原理

[編輯 | 編輯原始碼]

確定使用擴充套件聚合的影響。簡單聚合的評估與擴充套件聚合的評估之間可能存在顯著的效能差異。

受保護型別

[編輯 | 編輯原始碼]
  • 對於互斥,當測量的效能表明時,使用受保護型別作為任務會合的替代方案。
  • 要實現中斷處理程式,當效能測量表明時,使用受保護過程。
   -- (1) Using protected objects
   --     (See ACES V2.0, test "a9_pt_prot_access_02")
   protected Object is
      function Read return Float;
      procedure Write (Value : in Float);
   private
      Data : Float;
   end Object;
   protected body Object is
      function Read return Float is
      begin
         return Data;
      end Read;
      procedure Write (Value : in Float) is
      begin
         Data := Value;
      end Write;
   end Object;
   task type Modify is
   end Modify;
   type Mod_Bunch is array (1 .. 5) of Modify;
   task body Modify is
      ...
   begin -- Modify
      for I in 1 .. 200 loop
         The_Value := Object.Read;
         Object.Write (The_Value - 0.125);
         if The_Value < -1.0E7 then
            The_Value := 1.0;
         end if;
      end loop;
   end Modify;
   ...
   -- Block statement to be timed
   declare
      Contending_Tasks : array (1 .. 5) of Modify;
   begin
      null;  -- 5 tasks contend for access to protected data
   end;
   ------------------------------------------------------------------------------
   -- (2) Using monitor task
   --     (See ACES V2.0, test "tk_rz_entry_access_02")
   Task Object is
      entry Write (Value : in     Float);
      entry Read  (Value :    out Float);
   end Object;
   task body Object is
      Data : Float;
   begin -- Object
      loop
         select
            accept Write (Value : in     Float) do
               Data := Value;
            end Write;
         or
            accept Read  (Value :    out Float) do
               Value := Data;
            end Read;
         or
            terminate;
         end select;
      end loop;
   end Object;
   -- Task type Modify declared as above
   -- Block statement to be timed as above

基本原理

[編輯 | 編輯原始碼]

受保護物件旨在比用於相同目的的任務快得多(參見指南 6.1.1)。確定使用受保護物件在併發程式中安全地訪問封裝資料的效能影響。

模組型別上的位操作

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用模組型別而不是壓縮布林陣列。
   -- (1) Packed Boolean arrays
   --     (See ACES V2.0, test "dr_ba_bool_arrays_11")

   type Set is array (0 .. 15) of Boolean;
   pragma Pack (Set);

   S1     : Set;
   S2     : Set;
   Empty  : Set := (Set'Range => False);
   Result : Boolean;

   ...

   -- Is S1 a subset of S2?
   Result := ((S1 and not S2) = Empty);

   ---------------------------------------------------------------------

   -- (2) Modular types
   --     (See ACES V2.0, test "a9_ms_modular_oper_02")

   type Set is mod 16;

   S1     : Set;
   S2     : Set;
   Empty  : Set := 0;
   Result : Boolean;

   ...

   -- Is S1 a subset of S2?
   Result := ((S1 and not S2) = Empty);

基本原理

[編輯 | 編輯原始碼]

確定對模組型別執行位操作的影響。這些操作的效能可能與對壓縮布林陣列執行的類似操作有很大不同。另請參見指南 10.5.7。

定長字串

[編輯 | 編輯原始碼]
  • 當可預測的效能是一個問題並且測量的效能表明時,使用預定義的定長字串。

基本原理

[編輯 | 編輯原始碼]

不定長字串可能分配在堆上。如果定長字串沒有分配在堆上,那麼它們可能會提供更好的效能。確定在 Ada.Strings.Bounded.Generic_Bounded_Length 的例項中宣告的字串型別與在 Ada.Strings.Unbounded 中宣告的型別之間的效能影響。

預定義的 Ada 95 語言環境定義了支援定長和不定長字串的包。使用定長字串可以避免與使用堆儲存相關的延遲的不可預測持續時間。

字串處理子程式

[編輯 | 編輯原始碼]
  • 當測量的效能指標表明時,使用字串處理子程式的程式形式。

基本原理

[編輯 | 編輯原始碼]

確定 Ada.Strings.Fixed、Ada.Strings.Bounded、Ada.Strings.Unbounded 以及包含 Wide 的相應子包中具有相同名稱和功能的函式和過程的相對效能成本。

雖然函式式表示法通常會導致更清晰的程式碼,但它可能會導致編譯器生成額外的複製操作。

約束檢查

[編輯 | 編輯原始碼]
  • 當測量的效能指標表明時,使用強型別和精心選擇的約束來減少執行時約束檢查。

在這個例子中,消除了兩個潛在的約束檢查。如果函式 Get_Response 返回 String,那麼變數 Input 的初始化將需要約束檢查。如果變數 Last 的型別為 Positive,那麼迴圈中的賦值將需要約束檢查。

   ...
   subtype Name_Index is Positive range 1 .. 32;
   subtype Name       is String (Name_Index);
   ...
   function Get_Response return Name is separate;
   ...
begin
   ...
   Find_Last_Period:
      declare
         -- No Constraint Checking needed for initialization
         Input       : constant Name       := Get_Response;
         Last_Period :          Name_Index := 1;
      begin  -- Find_Last_Period
         for I in Input'Range loop
            if Input(I) = '.' then
               -- No Constraint Checking needed in  this `tight' loop
               Last_Period := I;
            end if;
         end loop;
         ...
      end Find_Last_Period;

基本原理

[編輯 | 編輯原始碼]

由於執行時約束檢查與效能下降有關,因此新增約束子型別實際上可以提高效能並不直觀。但是,無論是否使用約束子型別,都需要在許多地方進行約束檢查。即使是對使用預定義子型別的變數進行賦值也可能需要約束檢查。透過始終如一地使用約束子型別,可以消除許多不必要的執行時檢查。相反,檢查通常被移到與系統輸入相關的執行頻率較低的程式碼中。在這個例子中,函式 Get_Response 可能需要檢查使用者提供的字串的長度並引發異常。

一些編譯器可以根據約束子型別提供的資訊進行額外的最佳化。例如,雖然非約束陣列沒有固定大小,但它具有可以從其索引範圍確定的最大大小。透過將此最大大小限制為“合理”的數字,可以提高效能。請參考 NASA (1992) 中關於非約束陣列的討論。

即時系統附錄

[編輯 | 編輯原始碼]

基本原理

[編輯 | 編輯原始碼]

Ada.Synchronous_Task_Control 和 Ada.Asynchronous_Task_Control 包已被定義為提供對任務和受保護型別的替代方案,用於在需要最小執行時的應用程式中 (Ada 參考手冊 1995,附錄 D [帶註釋的])。

編譯指示

[編輯 | 編輯原始碼]

Pragma Inline

[編輯 | 編輯原始碼]
  • 當測量的效能指標表明時,在呼叫開銷是例程執行時間的重要部分時,使用 pragma Inline。
procedure Assign (Variable : in out Integer;
                  Value    : in     Integer);
pragma Inline (Assign);
...
procedure Assign (Variable : in out Integer;
                  Value    : in     Integer) is
begin
   Variable := Value;
end Assign;

基本原理

[編輯 | 編輯原始碼]

如果呼叫開銷是子程式執行時間的重要部分,那麼使用 pragma Inline 可能會減少執行時間。

過程和函式呼叫包括在程式碼很小時不必要的開銷。這些小的例程通常是為了維護包的實現隱藏特性而編寫的。它們也可能只是將它們的引數不變地傳遞給另一個例程。當這些例程之一齣現在需要更快執行的某些程式碼中時,要麼需要違反實現隱藏原則,要麼需要引入 pragma Inline。

使用 pragma Inline 確實有其缺點。它會建立對主體檔案的編譯依賴;也就是說,當規範使用 pragma Inline 時,規範和對應的主體檔案都需要在規範可以被使用之前進行編譯。隨著程式碼的更新,例程可能會變得更加複雜(更大),並且繼續使用 pragma Inline 可能不再合理。

雖然很少見,但內聯程式碼可能會增加程式碼大小,這可能會導致由於額外的分頁而導致效能下降。pragma Inline 實際上可能會阻止編譯器使用某些其他最佳化技術,例如暫存器最佳化。

當編譯器已經很好地選擇例程進行內聯時,pragma 可能幾乎不會帶來任何效能提升。

Pragma Restrictions

[編輯 | 編輯原始碼]
  • 使用 pragma Restrictions 來表達使用者遵守某些限制的意圖。

基本原理

[編輯 | 編輯原始碼]

這可能有助於構建更簡單的執行時環境 (Ada 參考手冊 1995,§§13.12 [帶註釋的], D.7 [帶註釋的], 和 H.4 [帶註釋的])。

Pragma Preelaborate

[編輯 | 編輯原始碼]
  • 在允許的情況下使用 pragma Preelaborate。

基本原理

[編輯 | 編輯原始碼]

這可能會減少載入後記憶體寫入操作(Ada 參考手冊 1995,§§10.2.1 [註釋]C.4 [註釋])。

Pragma Pure

[編輯 | 編輯原始碼]
  • 在允許的情況下使用 Pragma Pure。

基本原理

[編輯 | 編輯原始碼]

這可能允許編譯器省略對庫單元中庫級子程式的呼叫,如果在呼叫之後不需要結果(Ada 參考手冊 1995,§10.2.1 [註釋])。

Pragma Discard_Names

[編輯 | 編輯原始碼]
  • 當應用程式不需要名稱且資料空間非常寶貴時,使用 Pragma Discard_Names。

基本原理

[編輯 | 編輯原始碼]

這可能會減少儲存 Ada 實體名稱所需的記憶體,其中沒有操作使用這些名稱(Ada 參考手冊 1995,§C.5 [註釋])。

Pragma Suppress

[編輯 | 編輯原始碼]
  • 在需要的情況下使用 Pragma Suppress 以實現效能要求。

基本原理

[編輯 | 編輯原始碼]

參見指南 5.9.5。

Pragma Reviewable

[編輯 | 編輯原始碼]
  • 使用 Pragma Reviewable 來幫助分析生成的程式碼。

基本原理

[編輯 | 編輯原始碼]

參見 Ada 參考手冊((1995,附錄 H [註釋])。

  • 謹慎使用本章中的指南;它們可能對您的軟體有害。

程式結構

[編輯 | 編輯原始碼]
  • 當測量到的效能表明時,使用塊來引入延遲初始化。

資料結構

[編輯 | 編輯原始碼]
  • 當測量效能表明時,使用約束陣列。
  • 當測量效能表明時,為陣列使用基於零的索引。
  • 當測量效能表明時,為記錄使用固定大小的元件。
  • 當測量的效能表明時,將記錄陣列定義為並行陣列。
  • 當測量的效能表明時,使用一系列賦值來進行聚合。

演算法

[編輯 | 編輯原始碼]
  • 當測量的效能表明時,使用增量方案而不是 mod 和 rem。
  • 當測量的效能表明時,使用短路控制形式。
  • 當測量的效能表明時,使用 case 語句。
  • 當測量的效能表明時,使用硬編碼約束檢查。
  • 當測量的效能表明時,使用二維陣列的列優先處理。
  • 當測量的效能表明時,使用覆蓋來進行條件賦值。
  • 當測量的效能表明時,透過使用切片賦值而不是重複位賦值來執行壓縮布林陣列移位操作。
  • 當測量到的效能表明時,使用靜態子程式排程。
  • 當測量的效能表明時,只使用簡單的聚合。
  • 對於互斥,當測量的效能表明時,使用受保護型別作為任務會合的替代方案。
  • 為了實現中斷處理程式,當測量到的效能表明時,使用受保護的過程。
  • 當測量的效能表明時,使用模組型別而不是壓縮布林陣列。
  • 當可預測的效能是一個問題並且測量的效能表明時,使用預定義的定長字串。
  • 當測量的效能指標表明時,使用字串處理子程式的程式形式。
  • 當測量的效能指標表明時,使用強型別和精心選擇的約束來減少執行時約束檢查。
  • 對於既是 rendezvous 又受保護型別效率低下的情況,請考慮使用即時系統附錄((Ada 參考手冊 1995,附錄 D [註釋])。

編譯指示

[編輯 | 編輯原始碼]
  • 當測量的效能指標表明時,在呼叫開銷是例程執行時間的重要部分時,使用 pragma Inline。
  • 使用 pragma Restrictions 來表達使用者遵守某些限制的意圖。
  • 在允許的情況下使用 pragma Preelaborate。
  • 在允許的情況下使用 Pragma Pure。
  • 當應用程式不需要名稱且資料空間非常寶貴時,使用 Pragma Discard_Names。
  • 在需要的情況下使用 Pragma Suppress 以實現效能要求。
  • 使用 Pragma Reviewable 來幫助分析生成的程式碼。

可移植的哲學家用餐示例

華夏公益教科書