我有運行在緩衝液中的3D分水嶺通一個C++擴展不同的行爲。它有一個很好的Cython包裝來初始化一個巨大的緩衝區signed char
s代表體素。我在python中初始化了一些本地數據結構(在編譯的cython文件中),然後調用一個C++函數來初始化緩衝區,另一個實際運行算法(我也可以用Cython寫這些數據結構,但我希望它工作作爲一個C++庫,以及沒有python.h扶養。)
怪誕
我在調試我的代碼,嘗試不同的圖像大小來衡量內存使用和速度等的過程是,並且我注意到結果有些奇怪 - 它們會根據我是否使用python test.py
(特別是在Mac OS X 10.7.5/Lion,它是python 2.7)或python
上運行(特別是/usr/bin/python
),並調用它的功能(事實上,在我的筆記本電腦上(OS X 10.6.latest,macports python 2.7))結果也是確定性不同的 - 每個平臺/情況都不同,但每一個都與它本身一樣)。在所有情況下,調用相同的函數,從文件加載一些輸入數據,並運行C++模塊。
關於64位python的說明 - 我沒有使用distutils來編譯這段代碼,但類似於我的回答here(即有明確的-arch x86_64
調用)。這不應該意味着什麼,並且活動監視器中的所有進程都稱爲Intel (64-bit)
。
正如您可能知道的,分水嶺的要點是在像素湯中尋找對象 - 在2D中它經常用於照片。在這裏,我用它來以同樣的方式在3D中查找腫塊 - 我從圖像中的一些腫塊(「顆粒」)開始,我想在它們之間的空間中找到相反的腫塊(「細胞」)。
結果變化的方式是我從字面上找到不同數量的腫塊。對於完全相同的輸入數據:
python test.py
:
grain count: 1434
seemed to have 8000000 voxels, with average value 0.8398655
find cells:
running watershed algorithm...
found 1242 cells from 1434 original grains!
...
然而,
python
,import test
,test.run()
:
grain count: 1434
seemed to have 8000000 voxels, with average value 0.8398655
find cells:
running watershed algorithm...
found 927 cells from 1434 original grains!
...
這是交互式Python外殼和bpython
相同,我原本認爲這是責任。
請注意,「平均值」數字是完全相同的 - 這表示相同比例的體素最初被標記爲問題空間 - 即我的輸入文件被初始化爲(很可能)完全相同在體素空間中都是這樣。
另請注意,該算法的任何部分都是非確定性的;沒有隨機數字或近似值;由於浮點錯誤(每次應該是相同的),我們應該在兩次完全相同的數字上執行完全相同的計算。分水嶺運行時使用大整數緩衝區(這裏是signed char
s),結果是對這些整數的簇進行計數,所有這些都是在一個大的C++調用中實現的。
我已經測試了相關模塊的對象(其本身屬性進口test
的)的__file__
屬性,他們指向同在我的系統的安裝site-packages
watershed.so
。
問題
我甚至不知道從哪裏開始調試這一點 - 它是如何可調用相同的輸入數據相同的功能,得到不同的結果? - 關於交互式python可能會導致這種情況(例如,通過更改數據初始化的方式)? - (相當大的)代碼庫的哪些部分與這些問題有關?
根據我的經驗,將所有代碼發佈到一個stackoverflow問題中,而不是假設你知道問題出在哪裏會更有用。然而,這裏有成千上萬行的代碼,我幾乎不知道從哪裏開始!我很高興根據要求發佈小片段。
我也很高興聽到調試策略 - 我可以檢查的解釋器狀態,有關Python可能會影響導入的C++二進制文件的方式的詳細信息,等等。
下面的代碼的結構:
project/
clibs/
custom_types/
adjacency.cpp (and hpp) << graph adjacency (2nd pass; irrelevant = irr)
*array.c (and h) << dynamic array of void*s
*bit_vector.c (and h) << int* as bitfield with helper functions
polyhedron.cpp (and hpp) << for voxel initialisation; convex hull result
smallest_ints.cpp (and hpp) << for voxel entity affiliation tracking (irr)
custom_types.cpp (and hpp) << wraps all files in custom_types/
delaunay.cpp (and hpp) << marshals calls to stripack.f90
*stripack.f90 (and h) << for computing the convex hulls of grains
tensors/
*D3Vector.cpp (and hpp) << 3D double vector impl with operators
watershed.cpp (and hpp) << main algorithm entry points (ini, +two passes)
pywat/
__init__.py
watershed.pyx << cython class, python entry points.
geometric_graph.py << python code for post processing (irr)
setup.py << compile and install directives
test/
test.py << entry point for testing installed lib
(文件標記爲*
已在其他項目中廣泛使用,是很好的測試,這些後綴irr
包含的代碼只能運行後,這個問題已經引起。)
詳細
的要求,主節在test/test.py
:
testfile = 'valid_filename'
if __name__ == "__main__":
# handles segfaults...
import faulthandler
faulthandler.enable()
run(testfile)
和我的交互式調用看起來像:
import test
test.run(test.testfile)
線索
,當我在直解釋器中運行這個:
import faulthandler
faulthandler.enable()
import test
test.run(test.testfile)
我得到的文件調用的結果(即1242個單元格),但是當我在bpython中運行它時,它只是崩潰。
這顯然是問題的根源 - 伊格納西奧巴斯克斯 - 艾布拉姆斯馬上要求正確的問題。
UPDATE:
我已經opened a bug on the faulthandler github,我爭取解決工作。如果我找到一些人們可以學習的東西,我會將其作爲答案發布。
主節嚴格調用'run()'嗎?差不多就是 –
。爲兩種情況添加了確切的代碼。 – tehwalrus
看到我的後續編輯 - 調用'faulthandler.enable()'似乎有所作爲!我會去挖掘它的來源[這裏](https://github.com/haypo/faulthandler)尋找答案。 – tehwalrus