2003年10月14日(火)
■ [work][book] 開業のための本
仕事を開始するには個人事業主となり色々と手続きをする必要がある。ウェブでも色々調べられるが、本もあった方が便利なので買いに行った。次の2冊を購入。
書影がないとガッカリするな。下の方の本はタイトルや描かれているイラストがバカっぽいのだけれど、まあおれのレベルはこんなもんだろうからいいのだ。
あとは会計ソフトを買わないと。何がいいのかなあ。
■ [fs] 阿部ケガのため選手交代
阿部勇樹がケガをしてしまったようなので放出(±0)し、
- 二川孝広(2420万) ガンバが中盤を支配するはず
- 朴康造(250万) 知らない選手だがレギュラーのようなので
を獲得。二川を阿部に代えて先発させます。
■ 生活
- サムライスピリッツ零があったので遊んでみた。サムライスピリッツそのもので楽しい。みんななんであんな上手いのだ。おれはシャルロットとタムタムを使ってみたけれど、もう何もかも忘れていてピョンピョン飛んでばかりですぐ負ける。ゲーメストが必要だ。
- サムライスピリッツのサイトを見ちゃったりして。
- モー娘が18人特別編成、福田さんしのぶ会。福田明日香が死んじゃったのかと思った。
2004年10月14日(木)
- パケットが送信されずに困っていた。原因は、テストパケットとして送信していたRouter SolicitationのSLLオプションにあるMACアドレスが間違えていたことだった。ここがルータのMACアドレスになってしまっていて、近隣キャッシュができていなかった。ふー。
■ やること
- プリンタ処分
- リンク元のスリム化
2005年10月14日(金)
■ [life] 歯医者へ行く (6)
今日の担当は歯科医ではなく歯科衛生士。歯石を取ってもらった。歯と歯茎の間を機械でギュインギュインやられる。痛いし血だらけになった。毎日フロスを使えと言われた。支払いは1500円くらい。
今回取れなかった歯茎の奥の方の歯石を次回に取るらしい。恐ろしい。
■ やること
- 蛍光灯を捨てる
- 4000円払う
2006年10月14日(土)
■ [db] 「私的 SQL コーディング規約」 (MS-Access Discovery)
Baron SchwartzさんによるSQLのコーディング規約の翻訳をメモ。
SQLのコーディング規約に関する以前のメモもリンクしておく。
■ やること
- デザイン変更
- 保険
- 蛍光灯
- PHSのファームウェアアップデート
- 健康診断
2010年10月14日(木)
- ジャンボ宝くじ買った。10枚だけ。
■ [windows] Excelの「最後のセル」
Excel 2007を使っています。
最後のセルへのジャンプ
Ctrl-End 押下で「最後のセル」へジャンプできる。Excel で最後のセルをリセットする方法にはCtrl-Shift-End と書かれているけど、Shiftキー必要なのかなあ。
メニューからだと、[ホーム]→[検索と選択]→[ジャンプ]→[セル選択]→[最後のセル]で飛べた。
最後のセルのリセット
例えば10000行あるシートから後半5000行を削除したとき、「最後のセル」は5000行目にリセットされてほしいけど10000行目のままになっている。不便だなあと思っていたけど、保存を実行すると最後のセルがリセットされるみたいだった。Excel で最後のセルをリセットする方法にはブックを開きなおす必要があるように書かれているけれど。
■ [windows] Excelでグラフ専用のシートを作る
挿入メニューからグラフを作るとシート内にグラフが貼り付けられるけど、そのグラフを右クリックして[グラフの移動]→[新しいシート]を選ぶとそのグラフ専用のシートが作られる。
■ やること
- コンタクト
宝くじ
2011年10月14日(金)
- しばらく何もメモすることが無かった。成長していないということ。
■ [c++] std::ostringstream がマルチスレッド動作時に遅い
std::ostringstreamはログ出力などによく使うのだけれど、Linux上のマルチスレッドで動くプログラムの中では異様に遅いことが観測されたので調べてみた。
測定結果
最後に示すプログラムにより、
- func0: 文字列構築の度にostringstreamオブジェクトを作り直す
- func1: 1度作ったostringstreamオブジェクトを使い回す
- func2: sprintfを使う
の3通りで時間を計ってみた結果、次のようになった。環境により傾向が少し違った(どちらも古い環境で恐縮ですが)。
CPU数16, カーネル2.6.9, GCC 3.4.6
スレッド数1 | スレッド数2 | スレッド数4 | スレッド数8 | |
func0 | 4.365 | 6.380 | 10.329 | 21.490 |
func1 | 3.395 | 3.344 | 3.335 | 3.598 |
func2 | 2.622 | 2.535 | 2.547 | 2.740 |
数字はtimeコマンドで計った実行時間(単位は秒)。func0だけスレッド数の増加と共に性能が劣化している。
表には書いていないが、func0だけはスレッド数が増加するとシステム時間の比率がどんどん増え、8スレッドの場合はスレッドあたりのユーザ時間7.6秒に対しシステム時間13.0秒となっていた。どうしてそうなるのかはわからない。
ostringstreamを使っても、func1のようにオブジェクトを使い回すようにすると性能は劣化しない(sprintfよりは遅いが)。ということは、ostringstreamのコンストラクタに問題があると考えられる。
CPU数8, カーネル2.6.18, GCC 4.1.2
スレッド数1 | スレッド数2 | スレッド数4 | スレッド数8 | |
func0 | 4.592 | 5.894 | 7.370 | 13.933 |
func1 | 3.374 | 3.423 | 3.377 | 3.838 |
func2 | 2.689 | 2.706 | 2.709 | 3.050 |
こちらの方が少しバージョンが高いが、同じくfunc0だけ性能が劣化していく。ただし、先の環境よりは改善されている。
また、こちらの環境だとスレッド数が増えてもシステム時間は増えず、ずっとほぼ0秒だった。
使ったプログラム
上の測定は、以下のプログラムの実行時間をtimeコマンドを使って測定した。
#include <cstdio> #include <iomanip> #include <ios> #include <iostream> #include <sstream> #include <boost/bind.hpp> #include <boost/function.hpp> #include <boost/lexical_cast.hpp> #include <boost/thread.hpp> using namespace std; using namespace boost; // 毎回ostringstreamを作成 string func0(long l) { ostringstream oss; oss << l << " " << showpoint << fixed << setprecision(3) << l * 1.05; return oss.str(); } thread_specific_ptr<ostringstream> ts_oss; // スレッドローカルなostringstreamを使い回す string func1(long l) { ostringstream* oss = ts_oss.get(); if (oss) { oss->str(""); } else { ts_oss.reset(new ostringstream()); oss = ts_oss.get(); } *oss << l << " " << showpoint << fixed << setprecision(3) << l * 1.05; return oss->str(); } // sprintfを使う string func2(long l) { char s[1000]; sprintf(s, "%ld %.3f", l, l * 1.05); return s; } // boost::threadが実行する関数 void loop(function1<string, long> func) { string s; for (long l = 0; l < 2000000; ++l) { s = func(l); } cerr << s << endl; } void print_usage(const char* program) { cerr << "Usage: " << program << " NUM_THREADS FUNC_TYPE" << endl; } int main(int argc, char* argv[]) { if (argc != 3) { print_usage(argv[0]); exit(1); } int num_threads = lexical_cast<int>(argv[1]); int func_type = lexical_cast<int>(argv[2]); if (func_type < 0 || func_type > 2) { print_usage(argv[0]); exit(1); } string (*functions[])(long) = {func0, func1, func2}; thread_group threads; for (int i = 0; i < num_threads; ++i) { threads.create_thread(bind(loop, functions[func_type])); } threads.join_all(); }
■ [c++] std::ostringstreamのコンストラクタの実装
GCC 3.4.6(古いです)のソースをSVNからチェックアウトして、ostringstreamのコンストラクタを見てみたのでメモ。途中で力尽きています。
STL関連のソースは libstdc++-v3/include/ 配下の std/ や bits/ 辺りにあった。
basic_ostringstream
まず、basic_ostringstreamクラスのコンストラクタを見てみる。
libstdc++-v3/include/std/std_sstream.h
459 explicit 460 basic_ostringstream(ios_base::openmode __mode = ios_base::out) 461 : __ostream_type(), _M_stringbuf(__mode | ios_base::out) 462 { this->init(&_M_stringbuf); }
- __ostream_typeは、基底クラスのbasic_ostreamのこと。また、_M_stringbufは本クラスのストリームバッファであるbasic_stringbufクラスのインスタンス。だから、461行目ではbasic_ostreamクラスとbasic_stringbufクラスのコンストラクタが呼ばれる。
- this->init()は基底クラスのメンバ関数のようだ。
basic_ostream
次に、basic_ostreamクラスのコンストラクタを見てみる。
libstdc++-v3/include/std/std_ostream.h
104 explicit 105 basic_ostream(__streambuf_type* __sb) 106 { this->init(__sb); }
- this->init()はこのクラスにも定義されていない。更なる基底クラスのメンバ関数のようだ。基底クラスはbasic_ios。
basic_ios
basic_iosクラスのコンストラクタを見てみる。
libstdc++-v3/include/bits/basic_ios.h
255 explicit 256 basic_ios(basic_streambuf<_CharT, _Traits>* __sb) 257 : ios_base(), _M_tie(0), _M_fill(), _M_fill_init(false), _M_streambuf(0), 258 _M_ctype(0), _M_num_put(0), _M_num_get(0) 259 { this->init(__sb); }
- 色々呼んでるな…。
- _M_tieはbasic_ostreamオブジェクトへのポインタ。
- _M_fillはchar型の変数と考えてよい。
- _M_fill_initはbool。
- _M_streambufはbasic_streambufオブジェクトへのポインタ。
- _M_ctypeはstd::ctypeオブジェクトへのポインタ。ctypeて知らない。「文字を分類するためのファセット」とのこと。
- _M_num_putはstd::num_putオブジェクトへのポインタ。num_putも知らないが「数値出力のためのファセット」らしい。
- _M_num_getはstd::num_getオブジェクトへのポインタ。num_getは「数値入力のためのファセット」。ファセットとはlocale関連処理を行う何かみたい。
- this->init()はこのクラスで宣言されていた。実装は別ファイル。
- 結局、見るべきは基底クラスios_baseのコンストラクタとinit()の呼び出しだけだった。
先にinit()の内容を確認。
libstdc++-v3/include/bits/basic_ios.tcc
137 template<typename _CharT, typename _Traits> 138 void 139 basic_ios<_CharT, _Traits>::init(basic_streambuf<_CharT, _Traits>* __sb) 140 { 141 // NB: This may be called more than once on the same object. 142 ios_base::_M_init(); 143 144 // Cache locale data and specific facets used by iostreams. 145 _M_cache_locale(_M_ios_locale); 146 147 // NB: The 27.4.4.1 Postconditions Table specifies requirements 148 // after basic_ios::init() has been called. As part of this, 149 // fill() must return widen(' ') any time after init() has been 150 // called, which needs an imbued ctype facet of char_type to 151 // return without throwing an exception. Unfortunately, 152 // ctype<char_type> is not necessarily a required facet, so 153 // streams with char_type != [char, wchar_t] will not have it by 154 // default. Because of this, the correct value for _M_fill is 155 // constructed on the first call of fill(). That way, 156 // unformatted input and output with non-required basic_ios 157 // instantiations is possible even without imbuing the expected 158 // ctype<char_type> facet. 159 _M_fill = _CharT(); 160 _M_fill_init = false; 161 162 _M_tie = 0; 163 _M_exception = goodbit; 164 _M_streambuf = __sb; 165 _M_streambuf_state = __sb ? goodbit : badbit; 166 }
- 見るべきはios_base::_M_init()と_M_cache_locale(_M_ios_locale)しかない。後者のソースは同じファイルにあった。
168 template<typename _CharT, typename _Traits> 169 void 170 basic_ios<_CharT, _Traits>::_M_cache_locale(const locale& __loc) 171 { 172 if (__builtin_expect(has_facet<__ctype_type>(__loc), true)) 173 _M_ctype = &use_facet<__ctype_type>(__loc); 174 else 175 _M_ctype = 0; 176 177 if (__builtin_expect(has_facet<__num_put_type>(__loc), true)) 178 _M_num_put = &use_facet<__num_put_type>(__loc); 179 else 180 _M_num_put = 0; 181 182 if (__builtin_expect(has_facet<__num_get_type>(__loc), true)) 183 _M_num_get = &use_facet<__num_get_type>(__loc); 184 else 185 _M_num_get = 0; 186 }
- __builtin_expect()が分からない(gccの方でマクロを使って定義されているみたい)けど、ロケールがファセットをサポートしているならファセットをキャッシュしているのだろう。ここはスルーする。
ios_base
ios_baseクラスのソースを見てみる。このクラスのソースは別のディレクトリにあった。まずはコンストラクタ。
libstdc++-v3/src/ios.cc
115 ios_base::ios_base() 116 : _M_precision(), _M_width(), _M_flags(), _M_exception(), 117 _M_streambuf_state(), _M_callbacks(0), _M_word_zero(), 118 _M_word_size(_S_local_word_size), _M_word(_M_local_word), _M_ios_locale() 119 { 120 // Do nothing: basic_ios::init() does it. 121 // NB: _M_callbacks and _M_word must be zero for non-initialized 122 // ios_base to go through ~ios_base gracefully. 123 }
- うーん、基本的には何もしていないに等しいと思われる。
- ただし、最後の_M_ios_localeはlocaleクラスのインスタンスなので、localeクラスは見る必要がありそう。
あとはさっき呼ばれていたios_base::_M_init()のソースを確認する必要がある。別ファイル。
libstdc++-v3/src/ios_locale.cc
40 // Called only by basic_ios<>::init. 41 void 42 ios_base::_M_init() 43 { 44 // NB: May be called more than once 45 _M_precision = 6; 46 _M_width = 0; 47 _M_flags = skipws | dec; 48 _M_ios_locale = locale(); 49 }
- む、ここでも_M_ios_localeを初期化している。
locale
ここでlocaleクラスのコンストラクタを見ておく。
libstdc++-v3/src/locale_init.cc
100 locale::locale() throw() : _M_impl(0) 101 { 102 _S_initialize(); 103 __gnu_cxx::lock sentry(__gnu_internal::locale_mutex); 104 _S_global->_M_add_reference(); 105 _M_impl = _S_global; 106 }
- あ、なんかロックしてる!!これが悪いのか!?
- _S_globalというのが「Current global locale」を表しているようで、これはstaticなメンバ変数。これへのアクセスの際に排他制御が必要なんだな。
同ファイルにある_S_initialize()も見ておく。
147 void__ 148 locale::_S_initialize() 149 { 150 #ifdef __GTHREADS 151 if (__gthread_active_p()) 152 __gthread_once(&_S_once, _S_initialize_once); 153 #endif 154 if (!_S_classic) 155 _S_initialize_once(); 156 }
- うーん。__GTHREADSが定義されているのかは不明。
_S_initialize_once()は
137 void 138 locale::_S_initialize_once() 139 { 140 // 2 references. 141 // One reference for _S_classic, one for _S_global 142 _S_classic = new (&c_locale_impl) _Impl(2); 143 _S_global = _S_classic; 144 new (&c_locale) locale(_S_classic); 145 }
- えー、ここでlocaleをnewするのか。
きりがないのでここで終わり。
わかったこと
- basic_ostringstreamのコンストラクタを呼ぶと、色々な処理が動く。
- localeオブジェクトの構築時にロックをしている。これがボトルネックになっている可能性あり。
- そのlocaleオブジェクトを2度構築しているようだ。益々怪しい。
- コンストラクタの中で色々やらないで欲しい。深い継承も罪だ。
2021年10月14日(木)
■ [dev] CMakeのfind_packageでOpenCVを見つけるのに必要なパッケージ
Debian, Ubuntu上での話。CMakeのfind_packageでOpenCVを見つけるにはlibopencv-devパッケージが必要。このパッケージに
- /usr/lib/x86_64-linux-gnu/cmake/opencv4/OpenCVConfig.cmake
が含まれている。
分かってしまうと当たり前に感じるが、色々調べたのでメモしておく。
CMakeLists.txtには次のような感じで書いた。
find_package(OpenCV REQUIRED) target_include_directories(target_name PRIVATE ${OpenCV_INCLUDE_DIRS})
検索結果が格納される変数の名前は OpenCVConfig.cmake の先頭のコメントに説明がある(ここが唯一の情報源?)