XGBoost4J with OpenMP on macOS
macOS で GCC 7 を使って OpenMP 有効な XGBoost4J 0.7 のビルドをしても、そのままだとテストでこける。以下が問題のようだ。
ロケール
こんな感じの落ち方をする。
thread #71, stop reason = signal SIGSTOP frame #0: 0x00007fff57534e3e libsystem_kernel.dylib`__pthread_kill + 10 frame #1: 0x00007fff57673150 libsystem_pthread.dylib`pthread_kill + 333 frame #2: 0x00007fff57491312 libsystem_c.dylib`abort + 127 frame #3: 0x000000010968ccf3 libjvm.dylib`os::abort(bool) + 25 frame #4: 0x00000001097b4646 libjvm.dylib`VMError::report_and_die() + 2304 frame #5: 0x000000010968e91e libjvm.dylib`JVM_handle_bsd_signal + 1131 frame #6: 0x000000010968ab83 libjvm.dylib`signalHandler(int, __siginfo*, void*) + 47 frame #7: 0x00007fff57666f5a libsystem_platform.dylib`_sigtramp + 26 frame #8: 0x00007fff57467bad libsystem_c.dylib`__numeric_load_locale + 568 frame #9: 0x00007fff57469a68 libsystem_c.dylib`loadlocale + 212 frame #10: 0x000000012abba17c libxgboost4j.dylib`std::__convert_from_v((null)=<unavailable>, __out=":", __size=<unavailable>, __fmt="%.*f") at c++locale.h:67 frame #11: 0x000000012abc1a32 libxgboost4j.dylib`std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(this=0x000000012ace3800, __s=<unavailable>, __io=0x000070000ca85600, __fill=<unavailable>, __mod=<unavailable>, __v=0) const at locale_facets.tcc:1005 frame #12: 0x000000012abcd7ad libxgboost4j.dylib`std::ostream& std::ostream::_M_insert<double>(this=0x000070000ca85590, __v=0) at locale_facets.h:2434 frame #13: 0x000000012aa2dc3a libxgboost4j.dylib`xgboost::LearnerImpl::EvalOneIter(int, std::vector<xgboost::DMatrix*, std::allocator<xgboost::DMatrix*> > const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) + 538 frame #14: 0x000000012a9b470d libxgboost4j.dylib`XGBoosterEvalOneIter + 541 frame #15: 0x000000012a9a1640 libxgboost4j.dylib`Java_ml_dmlc_xgboost4j_java_XGBoostJNI_XGBoosterEvalOneIter + 1168
手元の環境では __convert_from_v
の定義は /usr/local/opt/gcc/include/c++/7.3.0/x86_64-apple-darwin17.3.0/bits/c++locale.h にあり、LC_NUMERIC
が C
でなかったら C
にして後で元に戻す、という実装になっていた。
このパスに入る箇所を調べて別実装に置き換えてまわるのも面倒そうだったので export LC_NUMERIC=C
として回避した。
そういえば P0067R5: Elementary string conversions, revision 5 を見たら Existing approaches が全てロケール依存のようでちょっと驚いた。
シグナル
pthread がシグナルハンドラを触るからだと思う。libxgboost4j より先に libjsig をロードしておくことで回避できた。
select()
socket()
が FD_SETSIZE
より大きい値を返すことがある。そのためアサーションにひっかかる。アサーションというよりは select()
の仕様が問題となっていそう。select()
の代わりに kqueue()
を使うように実装を書き換えたら回避できた、と思う。
追記: 0.81 において select()
を poll()
に置き換える形で直されたと思われる