ふと思いついたので特定コアに処理を割り当ててみた
スレッド(C#の場合はデリゲート)を使うと、「プログラムは上から順番に実行される」原則が覆され、う ち ゅ う の ほ う そ く が み だ れ る!
と思ってしまう。それが初心者クオリティ。
参考:
- http://d.hatena.ne.jp/naoya/20070824/1187945715
- http://www.thinkingparallel.com/2006/08/18/more-information-on-pthread_setaffinity_np-and-sched_setaffinity/
- http://surf.ml.seikei.ac.jp/~nakano/JMwww/html/LDP_man-pages/man2/sched_setaffinity.2.html
やってみた。以下サンプル。
#include <stdio.h> #include <stdlib.h> #include <iostream> #include <sched.h> #include <pthread.h> using namespace std; pthread_mutex_t mutex; int set_cpu_id(int cpu_id) { cpu_set_t mask; __CPU_ZERO(&mask); __CPU_SET(cpu_id, &mask); if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { std::cout << "Failed to set CPU affinity. " << endl; } else std::cout << "Succeed to set CPU " << cpu_id << "affinity. " << endl; return 0; } uint32_t waste_time(uint32_t n){ uint32_t i = 0; while (i < n*200000) { i++; } return i; } void* thread_main(void* pData){ int* cpuID = (int*)pData; set_cpu_id(*cpuID); uint32_t num = waste_time((uint32_t)cpuID); std::cout << "count " << num << endl; pthread_exit(NULL); } int main(){ pthread_t tid1, tid2; int num1 = 5, num2 = 6; int* cpuID1 = &num1; int* cpuID2 = &num2; pthread_mutex_init(&mutex, NULL); pthread_create(&tid1, NULL, thread_main, cpuID1); pthread_create(&tid2, NULL, thread_main, cpuID2); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_mutex_destroy(&mutex); return 0; }
たまにガイドラインを読むと非常に面白いのである
"An error occurred while creating an error report" この例では、問題を示す文が非常に風刺的で、解決策も提示されていません
http://msdn.microsoft.com/ja-jp/library/aa511267.aspx
これはクソ笑った。
MSは実は要所要所に面白いものを挟んでくるのがうまい。iOSのガイドラインは笑えるところなかったなぁ。
ちなみにGUI設計のポリシーはMicrosoftとiOSでは微妙に異なっている。Microsoftは「できるだけユーザーに取って有用な情報をできるだけ与えろ、でも一気には見せるな。階層構造を作りグルーピングしろ」だけど、iOSはそれを載せるマシンの性質上の問題もあるのか、「できるだけなにも見せず選択をしなければならない場合にだけ見せろ、見せるときは階層を作るな。人目で全てに目が通せるようにしろ」というポリシーの様子。んーまー一長一短すな。そしておいらはほとんどCUIアプリケーションばっかり作ってるのであまり関係ないのだった。
僕がテストについて思うこと
単体テスト好きというよりはモックの素晴らしさを喧伝したくてしょうがない僕ですが、モックいいよ!(それだけか(大好きなんだけどまだうまく伝えられるまでになっていない俺
t_wada「TDDはスキルです。才能ではない。努力した分伸びる。量は質に転化する。」 #devsumi
僕は全くスキルのないへなちょこプログラマの卵(まだへなちょこにすらなれていない)ですが、そういうひとほどテスト、特に単体テストを書くべきだと思う。理由はとっても簡単で、勉強になるから。副次的な理由でちょう簡単な間違いやバグをいれこまなくて良くなるというのもあるけど、メインは勉強になるからだなぁ。
いまJSTQB(JSQTB?)の資格取るために適当な勉強をしているところなんだけど、テスト(レビュー含む)って教育の意味合いを含んでいるものが少なからずあって、まぁなんでかっつーと人の書いたコードや設計を理解しないとできないからなんだよね。特にレビューはね。レビューをされることで勉強になるだけではなく、することでもわかるようになることはとてもたくさんある。ましてや単体テストは第三者の書いたコードを読み、仕様を読み解き、設計の意図を理解し(隠蔽されててテストできねーとか言いながら)、というのが一気にできるのだ。こりゃなかなかない機会っすよ。僕も別にもう若くはない(職歴は短いが)けど未だに卵な訳で、これから先すーぱーはかーやすーぱーぷろぐらまーになれる予定はないと思うけれども、自分自身を成長させることはできるんだよね。
テストは、一人でも始められる。全く賛同されなくても始められる。いつからでも始められる。ひどいレガシーコードが目の前にあっても修正することはできないかもしれないけれど、テストを書くことはできる。最初から全てを書くことはないのだ。出来るところから手をつけていき、一つ一つ成功するテストケースを書き上げていけば、最後には必ず整然とした動きの理解できるプログラムが出来上がる。それをたった一人で始めることができる。どんなにスキルがなくても、言語に対する知識がなくても、アルゴリズムや設計がわからなくても、レガシーコードはたくさんのことを僕に教えてくれる。こんがらがった醜いコードには数えきれない教訓と学ぶべき事柄が眠っている。
テストを書こう。テストを保守し、プログラムを守ろう。
Developers Summit 2011 行ってきた!
ある日突然上司から「デブサミ行く気ない?」と言われたときはデブですいませんと思ったものでしたが締切直前に滑り込みで登録、満席のセッションを目にさらしてアジャイル開発だけに的を絞って登録――というプロセスを経て本日行ってきました。スーツが多かった(感想はそれか)。明日は行く予定がありません……ははは。明日はTDD関連があるからちょっと興味はあるんだけどあえて今日にしたんですよ。ははは。
興奮覚めやらぬうちにとりあえず書いとく。しかしTwitter実況があるから入れなくてもかぶって入れなかったとしても結構普通に内容がわかるのなー。ありがたい時代だ。
http://twitter.com/#!/search?q=%23devsumi
続々と資料うpられ中。録画動画なども。これ会場行かなくてもいいんじゃね?(んなーこたない
- 17-B-2:アジャイル開発実戦 →かんそう:うちの上司もその上司もアジャイルに乗り気だからなー品証ていうかISOだけじゃね、問題は
- Jum Session: G* →かんそう:うおお空気読めてなかったかもでも面白かったし冊子ありがとうございます!これから読みます(マテ
- 17-B-5:今そこにあるScrum →かんそう:やっべえredmineとScrumはすごく相性がよさげなうえにおれTDD大好きだからちょいちょいとできそうなきがするけどScrumよくわかってNEEEEEEE そしてドヤ顔に吹いた
ほか会場には入れんかったけどTwitter実況(#devsumi)&TogetterまとめでRedmine チケット駆動開発なんかもざざっと要点は。
http://togetter.com/li/102077
個人的にはScrum面白かったー。あと昼にJum SessionでやってたTDDの聞けばよかったなぁ。なんか面白かったっぽいし。どうせ店混んでるんだからそこだけ聞いて遅れてから行けばよかったとすごく後悔。
Grooveyとか
おれは基本的にJavaを全然書かないひとなので(基本的なのは一応かけるしC#は書くので読めるは読める)あんま使う機会はなさそうだけどちょろちょろとObjective-Cぽいなーとか思ったりした。あの簡潔さ素晴らしい。C++は何かとめんどっちいんだよなー。ガベレージコレクションもねーし。あとJavaってHudsonJenkinsとの連携が良かったりEclipseのプラグインいっぱいあったりとかしてほんとに環境がいいよなー。あとテストの記述量少ないのはいいなぁ(またテストか)。関係ないけどMacbook Airの所持率高杉。
Scrum
まず俺あんまりScrumについて知らないんだけど要点を調べてみると
- プロダクトオーナー:プロダクト責任者
- 開発チーム
- すくらむマスター:開発の支援者(管理者とは微妙に意味合いが違うぽい?PMに近いらしい。関係ないけどひらがなでかくとぽけもんマスターぽい
開発チームのやること:実装とテスト&みんなで協力して問題を解決する
特色:
- プロダクトオーナーが持ってきた要求から作業を細分化する
- 2〜4週間で動くものができる(テストが完了する)ように計画をたてる
- 短いスパンでの進捗確認&効率を重視して各人が積極的に仕事をすすめる。進捗確認が終わって問題が特にないならあとは開発に集中。
- 動くものができたら反省会をして次のスプリント(実装&テスト)にフィードバックする(←ここ重要
XPとの違いがいまいちわからない……まぁ本質的には同じだという話だったからいいのかな。比較的プロセス側の観点から話してるだけでやること事態は同じなのかも。ちなみにひとつのスプリントに入る前に仕様ドキュメントは完成している必要があるらしい(Wikipediaより)
これはうけた。
「良くない朝会。ボソボソ喋る。チームに対して話さない。多分今日終わるはず・・・。自分でタスクを取れない。メンバーが助けを求めていても知らんぷり。」あるあるww
うちでやってる中で(Scrumではないけど割と近いことはやってる)できてないことだと、
- チケットの細分化→これ細分化するのはいいけどちゃんと管理しないとだめだからそこら辺の話はRedmineまとめ参照。
- タスクを取らない(もしくは自分で取る人が限られている)
- 朝ミーティングが長い!
あたりだなーとか思いながら聞いた。あとウォーターフォールなのでやっぱり期間が長いですね。実装期間自体はフェーズ分けたりver0.xxとかにしたりして短めにするようになってるから長くても一ヶ月程度だけど、検証含めると二ヶ月はかかる計算だし、基本設計ができるまでは次に行けないしなー。まぁ基本設計と言って曖昧にごまかしている部分はあるんだけども……。
今日の話を聞く限りは作業は一日から二日で終わる粒度にまで細分化されている必要があるような気がする。「多分今日中には…」と朝ミーティングでいっているときはなんで多分…って思うのかということに関して注意が必要?なにか気になることがある、うまくいかないことがある、ボトルネックがある場合は口にしようね、って言ってた。そして周りの人は目を逸らしたりせずに一緒に解決案について考えましょう、とのこと。
朝ミーティングででた懸念事項で短い時間内で解決できない場合は、朝MT後すぐに関係者で話し合う場を設けるってのはやってないなー。ちょいちょいと先延ばしにしたり午後一で…とかになっちゃうけどまぁでもそこら辺は運用の範囲か。
あーRedmine聞けなかったのマジで残念だった……。くそー。
Redmine チケット駆動開発(俺的メモ)
要点まとめ(まとめから見る限りだけど)。後ろの記号はすでにやってるか否かです。
参考はこちら:http://togetter.com/li/102077
- チケットは作業の漏れをなくすだけでなく,ものづくりをもうちょっと楽しくするもの ?
- TiDDは開発プロセスの即時性・効率化に寄与する
- チケット無しに構成管理上の変更をしない ×
- 変更の議論をチケットとして残しておく △(啓蒙中)
- 完全チケット方式 1. チケットがすべての作業を管理する 2. プロセスを変更するので社内調整が必要 ×
- 補完チケット方式 1. 既存の管理は変更しない 2. こっそり始められる ○(グループ内でだけど)
- チケット駆動による従来課題の解決: コミュニケーションのオンライン化 → 情報はRSSなどで即時に展開 △(プラグインとか必要、でもやっぱりアジャイルなら叩頭コミュニケーションも必要じゃない?)
- 問題解決支援- チケットによるトレーサビリテイ向上,作業スコープ(今日やること・優先度とか)の明確化.XPのタスクカードのイメージ △(人に寄るなぁ。ここら辺を意識してる人と単なる工数管理ツールだと思ってる人と)
- フィーチャーフリーズ、リリーススプリント (これよくわからない。フィーチャーフリーズはテストが一定値以下だったらソースコードの開発を止めることらしい。リリーススプリントはスクラムのはなし?)
- 親チケット=ストーリー、子チケット=タスク ○
- チケットの取捨選択が本来のマネジメント △(キャンセルとか保留とかをちゃんと使わないとですね)
見ていく限り作業の細分化をして適切な粒度のチケットをつくる必要性は感じる。多分感覚的に一日か二日でできる程度の粒度までは下げる必要があるだろうなぁ。でも三時間とかにしちゃうとものによるけど苦しい。
あと、TLで見かけた気がするんだけど、「チケットの定期的な棚卸」が必要とのこと。あるあるwwww
僕が基本的に個人で気をつけていることとしては
- まず先にチケットをつくってから作業する。突発的な作業が発生したらチケットを作成してから作業する。
- チケット進捗状況は割とこまめに変える(今どうなっているかを他の人からも分かるようにする)
- レビュー前に一つの親のレビュー以外のチケットをすべて閉じる→レビュー反映はレビュー作業の一環なのでレビューのチケットにつける
- ドキュメントはプロセス管理対象なのでいいんだけどコードレビューは口頭でやって指摘がなかった場合はエビデンスが残らないので、レビュー依頼チケットを出す(←New!)
テストに関しては他の人がいろいろと枠組みつくってやっているのでまだ俺はよくわかってないけど、チケット見れば全部わかるようになってるな。実はテストって結構チケット駆動と相性がいいと思うんだよなー。とかとか。
google test/mock導入
どうもこんにちは。google信者です。アンドロイドほしーい(というキャンペーンはやっておりません
信者なのでいけてるユニットテストライブラリgoogle test(およびgoogle mock)を紹介することにした。C++専用です*1 *2。CppUnitよりは確実にかなり断然記述量が少なくてお勧めです。結果も色で表示されるし!
インストール
http://www10.atwiki.jp/bambooflow/pages/187.html
基本はここのとおり。
- とりあえずtar.bz2ファイルをダウンロードしてきて展開
- 適当なところにgtestフォルダを作成
# mkdir /home/wonodas/gtest
- 後は中身をメイクするだけ!
# cd /home/wondoas/Desktop/gtest-x.x.x/ # ./configure --prefix=/home/wonodas/gtest --enable-shared=no # make # make install
これで さっきつくったgtestのところにライブラリが展開される。
2011.4.21追記
1.6.0にアップデートしようとしたんだけど、make installをしようとしたら、
make install is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system
と出てきてしまった。cmakeを使うことを推奨しているぽい。makeまでは今まで通りでOKなんだけどmakeのあとに
g++ -I ${GTEST_DIR}/include -I ${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc #libgtest.aを作成する ar -rv libgtest.a gtest-all.o
とする必要があるもよう。
使い方
- とりあえずテストプロジェクトを作成
- テストプロジェクトの環境設定で、[Settings]-[Tool Settings]-[GCC C++ Compiler]-[Includes]でgtest/includeを指定
- 同じくLibraries search pathでgtest/libを指定
- 同じくLibraliesでgtestを設定
- なんかマルチスレッド関連のエラーが出たので一応pthreadもライブラリに追加
ここまでで一応コンパイルは出来るようになる。
書くときは
#include <gtest/gtest.h> (省略) TEST(テスト名、ユニークな名前){ (テストの内容) } int main(int argc, char** argv){ testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
"テスト名_ユニークな名前"で一つのテストケースとして認識されるようなのでドキュメントには「アンダースコアを使ってはいけない」と書いてあった。
アンダースコアを使ってはいけないことが分かる例
ex.)
TEST(A_Test, constructor) →A_Test_constructorというテストケースとして認識
TEST(A, Test_constructor) →A_Test_constructorというテストケースとして認識
↑上二つの区別が実行時にわからなくなってしまう…とのこと
テスト名を「テストするクラス名+Test」, ユニークな名前を「test+何をテストしているかわかるような名前」にしておけばあまり問題は起きないような。まぁ一応推奨されている通りにやった方がいいんだろうけど…。
なおHudsonで自動ビルドするよ!とかいう場合はJUnit形式のxmlファイルを吐きだしてくれるので結果を表示することができます。
実行時のオプションに--gtest_output=xmlをつけてやればtest_detail.xmlという結果ファイルが実行ディレクトリにできるよ!Linux詳しくない人のために一応書いとこう。
#unitTestingという実行ファイルを実行する ./unitTesting --gtest_output=xml
[参考]
http://opencv.jp/googletestdocs/advancedguide.html#adv-generating-an-xml-report
googlemockのつかいかたまとめ
http://src.chromium.org/svn/trunk/src/remoting/client/chromoting_view_unittest.cc
ここらへんとかを読み解きながら。
基本の書き方
class Hoge{ public: Hoge(){}; ~Hoge(){}; public: int hogeMethod1(int x){ return x;}; };
というクラスがあった時は、まずモッククラスを作成する。
using ::testing::Mock; using ::testing::_; using ::testing::Invoke; using ::testing::Return; class MockHoge : public Hoge{ public: MockHoge(){ //モックのメソッドが呼び出されたときに、Hogeクラスの対応するメソッドを呼び出すように設定する(書かなくてもよい) ON_CALL(*this, hogeMethod1(_)).WillByDefault(Invoke(&hoge_, &Hoge::hogeMethod1)); }; //デコンストラクタはvirtualにすると書いてあったけどしなくてもよいかも? virtual ~MockHoge(){}; //引数が0だったらMOCK_METHOD0, 1だったらMOCK_METHOD1,...と書いていく //第1引数はメソッド名、第二引数は"戻り値(引数)" MOCK_METHOD1(hogeMethod1, int(int)); private: Hoge hoge_; //ON_CALL用。コンストラクタで書かない場合はいらない。 };
テストメソッドは以下のようにかく。
//TEST(任意、任意) TEST(MockHogeTest, invokeTest){ MockHoge mh; //引数が何であってもよい。1回呼ばれたらsuccessを返してくれる EXPECT_CALL(mh, hogeMethod1(_)).Times(1); EXPECT_EQ(1, mh.hogeMethod1(1)); //引数指定、WillOnce(Return(戻り値))で戻り値が本来かえってくるものとは別のものを指定することも可 EXPECT_CALL(mh, hogeMethod1(1)).Times(1).WillOnce(Return(10)); EXPECT_EQ(10, mh.hogeMethod1(1)); }
あるメソッドの中で同じクラスのメソッドが呼び出されることがあって、それをテストしたい場合はやり方が少し違うので注意。
例えばこんなクラスがあったとする。
class Calc{ public: Calc(){}; ~Calc(){}; int shiftUpNBit(int x, int n){ return x << n; }; int shiftDownNBit(int x, int n){ return x << n; }; bool isEven(int x){ return x % 2 == 0; }; //偶数だったらnビット左にシフト、奇数だったらnビット右にシフトする int calc(int x, int n){ return isEven(x) ? shiftUpNBit(x, n) : shigtDownNBit(x, n); }; };
calcを呼ぶと中でCalcクラスのshiftUpNBit, shiftDownNBit, isEvenが呼ばれる。全部pubicにしてるけど…
class MockCalc : public Calc{ public: MockCalc(){ ON_CALL(*this, shiftUpNBit(_, _)).WillByDefault(Invoke(&calc_, &Calc::shiftUpNBit)); ON_CALL(*this, shiftDownNBit(_, _)).WillByDefault(Invoke(&calc_, &Calc::shiftDownNBit)); ON_CALL(*this, isEven(_)).WillByDefault(Invoke(&calc_, &Calc::isEven)); ON_CALL(*this, calc(_, _)).WillByDefault(Invoke(&calc_, &Calc::calc)); }; virtual ~MockCalc(){}; public: MOCK_METHOD2(shiftUpNBit, int(int, int)); MOCK_METHOD2(shitDownNBit, int(int, int)); MOCK_METHOD1(isEven, bool(int)); MOCK_METHOD1(calc, int(int, int)); private: Calc calc_; };
ここまではその上とおんなじだが。
TEST(CalcTest, testCalcInvoke){ //ヒープ領域に取らないとエラーが出るぽい MockCalc* mc = new MockCalc(); { //順番のテストとメソッドの中でちゃんとメソッドが呼び出されているかテストする(EXPECT_CALLはまちがいでON_CALLが正しいです;#2011/2/17) InSequence s; EXPECT_CALL(*mc, calc(_, _)); EXPECT_CALL(*mc, isEven(_)).WillOnce(Return(true)); //どんな場合もtrueがかえる EXPECT_CALL(*mc, shiftUpNBit(_, _)); } EXPECT_EQ(4, mc->calc(1, 2)); //モックオブジェクトは勝手に解放されないので、メモリーリークするかもしれないというWarningが出力される //表示させたくない場合はMock::AllowLeakを使う MOCK::AllowLeak(&mc); //モックオブジェクトを初期化する Mock::VerifyAndClear(&mc); //普通に解放してもよい。 mc->~MockCalc(); //delete mc; //こちらでもよい。 }