IBM XL 編譯器提供 10 級調試優化平衡選項(-g0 到 -g9),解決傳統「優化無法調試、調試無法優化」兩難。本文詳細解析各等級行為、優化對調試的影響與最佳選擇策略。
傳統兩難困境
-g -O0:完整調試資訊,但效能極差,無法重現優化後的 Bug。
-O2 -g:優化後代碼,調試資訊不準確(變數最佳化掉、指令重排、內聯)。
XL 編譯器 -g 等級完整對照
| 等級 | 調試資訊內容 | 適用場景 | 效能影響 |
-g0 | 無調試資訊 | 正式發布版本 | 無(最佳效能) |
-g1 | 行號 + 檔名(無符號表) | 最小化偵錯資訊 | 極小 |
-g2 | 傳統 -g 行為(完整符號,不保證準確) | 舊版相容 | 中等 |
-g3/-g4 | + 函式入口參數可見 | 需檢查呼叫參數 | 中等 |
-g5/-g6/-g7 | + 迴圈/分支/呼叫/首句程式狀態 | 關鍵路徑偵錯 | 較大 |
-g8 | 每行原始碼程式狀態完整可見 | 推薦:優化代碼生產環境調試 | 約保留 80% 優化效能 |
-g9 | + 允許調試器修改變數值影響執行 | 深度互動式修補 | 最大(幾乎禁用相關優化) |
優化對調試的三大核心衝擊
1. 指令重排與執行順序
- 編譯器重排指令以利流水線、隱藏延遲(如除法提前發射)。
-g8 保證:斷點停在第 N 行時,第 N-1 行副作用已完成。
- 單步執行可能「跳躍」行號,需檢查機器碼確認實際執行點。
2. 變數最佳化消失(存於暫存器/完全移除)
- 迴圈索引
i、累加器 sum 常只存在暫存器。
-g8/-g9 強制關鍵點將變數寫回記憶體,調試器可見。
-g9 更進一步:每次迴圈迭代皆寫回,允許調試器修改生效。
3. 函式內聯導致呼叫堆疊消失
- 內聯函式無
CALL 指令,Step Into 與 Next 行為相同(皆進入內聯本體)。
-g8+:內聯點插入狀態資訊,可單步進入內聯函式、查看正確區域變數。
- 呼叫堆疊**不會**顯示內聯函式框架。
效能數據參考
-O2 -g8 典型程式效能 ≈ -O2 的 **80%**。
- 遠優於傳統
-O0 -g(約 30-50% 效能)。
- 正式發布建議
-O3 -g1 或 -O3 -g0(最小偵錯資訊)。
選擇策略決策樹
- **生產環境除錯** →
-O2 -g8(平衡最佳)
- **需要修改變數驗證修正** →
-O2 -g9(接受效能代價)
- **僅需堆疊追蹤/參數檢查** →
-O2 -g3
- **效能極度敏感、不需調試** →
-O3 -g0
- **開發階段日常除錯** →
-O0 -g 或 -Og -g (GCC/Clang)
跨平台對應
| 編譯器 | 對應選項 | 備註 |
| GCC/Clang | -Og (優化不干擾調試) | GCC 4.8+,不等同 -g8 |
| MSVC | /Od (無優化) / /Zo (優化調試) | /Zo 為編譯器內部優化 |
| Intel ICC | -debug inline-debug-info | 類似 -g8 概念 |
最佳實踐建議
- 建構系統整合
-g8 為「除錯優化」建置模式。
- 發布套件包含
-g1 剝離符號表(strip / objcopy --strip-debug)。
- 原始碼映射:確保部署環境可存取原始碼路徑(
-fdebug-prefix-map 重映射)。
- 記錄建置精確編譯器版本、旗標、原始碼版本(Git commit),確保可重現。