前幾天在運行一個模型訓練工具的時候,發現了一個Illegal instruction (core dumped)的錯誤。話說這種錯誤以前沒怎么見過。這是一個開源的項目,我是運行的從同事那邊拿來的工具,就會這樣,但是我自己下載源碼重新編譯后運行一切正常。於是就查了查這個Illegal instruction是怎么回事,畢竟這貨不比segmentfault常見。
查閱顯示,illegal instruction,即SIGILL, 是POSIX標准中提供的一類錯誤。 從名字上看,SIGILL是啟動的某個進程中的某一句不能被CPU識別成正確的指令。 此類錯誤是由操作系統發送給進程的,在進程試圖執行一些形式錯誤、未知或者特權指令時操作系統會使用SIGILL信號終止程序。果然如名字一樣,非法指令。那么,在什么情況下會出現這種錯誤呢,一般來說,有兩種可能,一是將數據錯誤地寫進了代碼段,導致將本不是指令的數據當成指令去執行;第二種可能是編譯時指定的CPU架構與實際運行的機器不一致。這里主要講講第二種。
由於CPU架構的演進,CPU指令集一直在不斷地拓展,SSE、SSE2、SSE3、SSE42、AVX、AVX2等。不同的CPU能支持的指令集是不一樣的,如果編譯程序時指定了使用新的CPU架構進行編譯,則該程序在老的CPU上運行時,其指令就不能被執行,從而引發Illegal instruction錯誤。查閱gcc資料,gcc是提供了一個march編譯選項來指定所使用的CPU架構的。如果不清楚自己的CPU類型,可以使用gcc -c -Q -march=native --help=target | grep march來查看:
music@ds01:~$ gcc -c -Q -march=native --help=target | grep march -march= corei7-avx music@ds01:~$
如果在編譯時指定了-march參數,gcc將不會再用兼容的指令去編譯,而是根據指定的CPU架構,采用其特定的指令集如AVX去生成二進制代碼。因此,當你確定所編譯的程序只會在特定的環境中運行時,可以使用-march參數來指定CPU架構,這樣編譯器就可以根據你的CPU架構進行指令上的優化,而這個指定帶來的結果就是,如果你將程序放在其他機器上運行,有可能得到Illegal instruction的運行錯誤。