嵌入式系統設計中你所不知的經驗法則


本文爲譯文,原作者:PHILLIP JOHNSTON 菲利普 · 約翰斯頓,發表在Embedded artistry。
下文爲節選原文章中個人感覺不錯的地方,不足之處還請多多指教。

引言

​ 本文可稱之爲指導方針、啓發法或經驗法則。 但不管怎樣,目的是相同的:提供一個合理的近似真理。 這些經驗法則可以幫助您理解您所工作的系統,將您的注意力集中在正確的解決方案上,並突出潛在的問題領域。

通用

  • 保持一個系統運轉比在系統崩潰後修復它要容易得多
  • 儘可能將錯誤從運行時移動到編譯時
  • 沒有文檔的程序沒有價值
  • 明顯註釋永遠不應該重述代碼的作用
  • 註釋應該通過描述意圖來幫助維護
  • 頭文件中的所有內容都應該至少在兩個源文件中使用
  • 通過消除干擾和中斷,開發人員的工作效率會顯著提高
  • 作爲一個經驗法則,你花在缺陷預防上的每一個小時將會減少你的修復時間,從三到十個小時

設計

  • 複雜的系統從簡單的系統演化而來
  • 如果你不能用簡單的語言描述這種行爲,你就不能用代碼成功地實現它
  • 將複雜的問題分解爲較小的子問題
  • 一個函數應該只執行一個概念性任務
  • 不要解決不存在的問題
  • 解決具體的問題,而不是一般的問題
  • 設計是一個迭代的過程。 所需的迭代次數比當前完成的次數多一次。 這在任何時候都是正確的
  • 從來沒有一個正確的解決方案,但總是有多個錯誤的解決方案
  • (愛迪生定律)“好”是“好”的敵人
  • (謝伊定律)改進設計的能力主要在於接口。 這也是把事情搞砸的首要地點
  • 研究發現,修改有缺陷的需求、設計和代碼通常會消耗軟件開發總成本的40% 到50%
  • 在最壞的情況下,一旦軟件開始運行,重新處理軟件需求問題的成本通常是在需求階段重新處理問題所需成本的50到200倍

成本

  • 軟件是昂貴的
    • “更新,2015年10月。 現在每行代碼大概要花費25-50美元。 隨着工資和對稀缺程序員的競爭加劇,外包到亞洲的項目成本大幅上升。” (菲爾 · 庫普曼)
    • 一項又一項的研究表明,商業代碼在所有沒有記錄在案的混亂中,每條線路的成本爲15至30美元。 一個糟糕的1000行代碼——並且很難在一千行中做很多事情——有一個非常真實的成本可能是30,000美元。 老話說‘這只是一個軟件改變’ ,等同於‘這只是一塊金磚’。” (傑克 · 甘塞爾)
  • 如果您想要降低軟件開發成本,那麼查看每一個需求文檔並殘酷地剔除一些功能特性
    • 功能特性繁多就等同於緩慢的進度和昂貴的開發
  • 一次性工程費用(NRE)成本必須平攤到銷售的每個產品上
    • 通過減少功能來節省 NRE 費用
    • 通過將軟件功能減少到硬件組件中來節省 NRE 費用,增加BOM成本
      • 只有當硬件已經存在時纔有用
      • 應該在設計過程的早期評估軟件 / 硬件分區
    • 通過更快地交付產品來節省 NRE
  • 完全重寫5% 的有問題的函數,而不是修復現有的實現,這比較容易而且便宜

計劃

  • 永遠沒有足夠的時間去做正確的事情,但是不管怎樣,總有足夠的時間去重做
  • 評估日期而不是小時保證了一個晚期的項目
    • “當開發人員不把日曆時間和工程時間分開時,日程安排災難就不可避免”
  • 如果計劃表產生了人員利用率超過50%的假象,那麼項目就會成比例地落後
  • 我們往往未能預見到發展的困難領域
  • 5% 的功能消耗了 80% 的調試時間
  • 當將舊代碼移植到新項目時,如果超過25% 的代碼被修改,那麼就不會有太大的進度提升
  • 系統加載佔用了90% 處理器能力,比加載到70% 或更少的系統上多花2倍的開發時間。 如果95% 的加載則需要 3 倍的開發時間
    • 當只剩下幾個字節時,即使是微不足道的特性也可能需要幾周時間,因爲開發人員必須重寫大量代碼以釋放內存或 CPU 週期
  • 你制定的時間表看起來像是一個完整的虛構作品,直到你的客戶因爲你沒有滿足它而解僱你
  • 有時候,最快到達終點的方法就是拋開一切重新開始
  • (巴頓的計劃規劃法)現在大力執行的好計劃勝過下週完美的計劃

硬件

  • 增加硬件會增加功耗
  • 使用硬件加速器來卸載基於 cpu 的算法可以降低功耗
  • 每個傳感器都是一個溫度傳感器,一些傳感器還可以測量其他東西
  • 將討厭的實時硬件功能分解爲獨立的 cpu
    • 從設備每秒處理1000次中斷? 將其分割到自己的控制器上,並將所有 ISR 開銷從主處理器上卸載下來
  • 只要能簡化軟件,就增加硬件
    • 這將顯著降低 NRE 和軟件開發成本,作爲 BOM 成本增加的權衡
    • 系統加載佔用了90% 處理器能力,比加載到70% 或更少的系統上多花2倍的開發時間。 如果95% 的加載則需要 3 倍的開發時間, 添加額外的硬件以減少負載(意思是加CPU、內存,就不用花大量時間進行算法代碼優化了)
  • 當硬件運行良好時,真正重要的訪問者不會出現

軟件重用

  • 更喜歡使用已經被其他人重新使用過的現有的、經過評審的代碼
  • 比起自定義通信協議,更喜歡簡單、標準的通信協議
  • 遵循“三分律” : 允許複製和粘貼代碼一次,但是當同一代碼複製三次時,應該將其提取到一個新的過程中
  • 在一個包真正可重用之前,它必須至少被重用三次
    • 我們還不夠聰明,不足以真正瞭解一大塊軟件可能被使用的應用範圍。 每個領域都需要自己獨特的特性和調整; 除非我們真正多次使用這些代碼,在足夠廣泛的應用程序上使用,否則我們不會對它進行足夠的概括,使它真正可重用
  • 在大段代碼中進行重用效果最好——考慮重用整個驅動程序或庫,而不是函數

優化

  • 過早的優化是浪費時間
    • “與其他任何單一原因(包括盲目的愚蠢)相比,更多的計算原罪是以效率的名義(不一定能實現)犯下的。”
    • 程序優化的第一條規則: 不要這樣做。 程序優化的第二條規則(僅限專家!) : 先別這麼做。
  • 只有在對代碼進行分析之後才能對其進行優化,以識別問題區域
    • “瓶頸出現在意想不到的地方,所以在你證明瓶頸在哪裏之前,不要試圖事後諸葛亮,提高速度。” 羅伯 · 派克
    • “我們應該忘記小效率,比如說97% 的時間: 過早的優化是一切罪惡的根源。 然而,我們不應該錯過這3% 的關鍵機會。 一個好的程序員不會因爲這樣的推理而自滿,他會明智地仔細檢查關鍵代碼; 但只有在代碼被識別之後纔會”
  • Pareto理論可以應用於資源優化: 80% 的資源被20% 的操作使用
    • 另外,軟件工程中也有90 / 10法則: 一個程序90% 的執行時間花費在執行10% 的代碼上
  • 算法優化比微優化有更大的影響
  • 永遠不要爲了提高效率而犧牲透明度,尤其是當效率改進還沒有被數據證明的時候

紅旗及問題範疇

  • 當開發人員害怕更改一個函數時,是時候從頭開始重寫那段代碼了
  • 複製代碼是糟糕的設計或糟糕的編程習慣的表現,必須消除
    • “複製是一種不好的做法,因爲它使代碼更難維護。 當在複製代碼片段中編碼的規則發生更改時,維護代碼的人必須在所有地方正確地更改它。 這個過程很容易出錯,並且常常導致問題。 如果代碼只存在於一個地方,那麼就很容易在那裏進行更改。”
    • ”此規則甚至可以應用於少量代碼行,甚至是單行代碼。 例如,如果你想調用一個函數,然後在它失敗時再次調用它,那麼有兩個調用是可以的,但是,如果你想在放棄之前嘗試五次,那麼在一個循環中應該只有一個調用,而不是五個獨立的調用。”
  • 儘可能避免共享資源
  • 消除全局變量
  • 禁用中斷往往是一件壞事
    • 即使在最好的情況下,它也會增加系統延遲並可能降低性能
    • 延遲的增加導致錯過中斷和錯誤的設備管理
  • 提防單獨的啓用中斷命令
    • 除了啓動代碼中的初始中斷之外,位於中斷之外的中斷服務程序,通常比較危險
    • 如果 enable 不是 禁用中斷 / 使能中斷 對的一部分(這兩個指令必須非常接近,以保持延遲降低和可維護性提高) ,那麼代碼很可能是令人費解的
  • 當代碼中加入禁用中斷/使能中斷對時要小心
    • 過度使用禁用中斷指令表明設計不良
    • “但是,當出現系統設計問題,導致大量關鍵區域容易出現可重入性問題時,這些禁用中斷/使能中斷對就會大量進入代碼。 你知道這是怎麼回事: 追蹤一個 bug,勇敢的開發人員發現了一個被上下文切換丟棄的變量。 快速插入禁用中斷/使能中斷對。 然後是另一個。 再來一杯。 就像吸食海洛因的人吸了最後一口。 它永遠不會結束。”

打斷/中斷

  • 除了嘴短暫的時間和最迫切的需要之外,不要打斷別人的話
  • 如果在一段代碼中禁用中斷,那麼應在同一段代碼中重新啓用它們
  • 中斷服務程序(ISR)代碼儘可能小巧
    • 注意不超過半頁
    • 在大多數情況下,處理程序內部應該很少甚至沒有處理
    • 設置一個標誌,向隊列添加一個值,然後依靠用戶空間代碼來處理更復雜的任務
  • 減小中斷服務程序(ISR)延遲以確保系統不漏掉中斷
  • 檢查任何中斷服務程序(ISR),在返回前立即重新啓用中斷
    • 減小中斷服務程序(ISR)內的關鍵部分
    • “允許其他設備中斷 ISR 是完全沒有問題的! 甚至允許相同的中斷這樣做,給予足夠的堆棧空間。 這意味着我們應該儘早創建處理所有不可重入內容(如服務硬件)的服務例程,發出 EI,並繼續執行可重入活動。 然後彈出寄存器,再返回。”
  • 在中斷處理程序中避免以下操作:
    • 不要在處理程序中聲明任何非靜態變量
    • 避免阻塞函數調用
    • 避免不可重入的函數調用
    • 避免任何佔用大量時間的處理
    • 避免使用鎖進行操作,因爲這樣會在 ISR 中使程序陷入死鎖
    • 避免涉及動態內存分配的操作,因爲分配可能需要一個鎖並且需要不確定的時間
    • 避免堆棧分配

進一步閱讀

譯文不易,請多支持,更多延伸閱讀,歡迎v關注我們【攝星科技】。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章