2014年2月23日日曜日

Chromium OSを試してみる

Windowsの代わりとしてMac OSやLinuxだけでなく、Google Chrome OSというOSが存在しています。

このChrome OSは、以下のような特徴があります。
  • ブラウザに機能を絞っている
  • Googleのサービスに頼っている
  • 機能を絞っているので速い
  • 機能を絞っているのでセキュリティに強い
  • アップデートが容易
  • 安い
このOSを乗せたChromebookが米国の法人市場で2013年11月に9.6%のシェアを獲得したそうです。

この数字はAndroidタブレットの8.7%を凌ぐものとなっています。

Chrome OSのフリーソフト版であるChromium OSが存在し、Chromebookのような専用ハードで無く、普通のPCでも使えるようになっています。今は日本では発売もされておらず有名ではないですが、今後成長する可能性もあり、古いPCで使ってみるのも良いかと思います。


以下のサイトから、USBメモリから起動するためのイメージや、VirtualBoxの仮想環境で動作させるためのイメージがダウンロードできます。

http://chromeos.hexxeh.net/
http://chromium.arnoldthebat.co.uk/

私はEee PC 901-Xを持っているのですが残念ながら、どちらのUSBメモリ用のイメージもkernel panicになってしまい、動作しませんでした。Eee PC 1015PEMでは動作するようなのですが。

USBメモリへのイメージの書き込みはRaspberry Piでの記事で紹介した、 Win32 Disk Imagerで出来ますので、挑戦してみてください。

私はVirtualBox上で動かしてみました(古いPCは使えませんでしたが)。ただしViratulBoxもhttp://chromeos.hexxeh.net/側のイメージしか使えませんでした。こちらのほうが少し古いです。

Viratual Box の新規でダウンロードしたvdiファイルを選択するとChromius OS の環境ができます。たぶんタイプはUbuntuで良いと思われます。





作成したら、起動します。最初に言語を設定します。日本語にも対応しています。ただマウスが正しく動きませんでした。ViratualBoxのメニューの「仮想マシン」-「マウス統合の無効化」をしてください。


次にGoogleのアカウントでログインします。


アカウントの画像を選択します。



画面が起動します。


キー入力の設定において、日本語入力にmozcを使用することができます。mozcはGoogle日本語入力のフリー版で、非常によい日本語変換ができるようになっています。







Ctrl+Alt+Tキーを押すと、croshという、コンソールが環境が起動します。ここでshellと入力すると、通常のLinuxのシェルのようなものが使えるようになります。

Googleのサービスをよく利用している人、ネット利用が主なPCの用途の人にはそれなりに使えるのではないかと思います。一度お試しください。


なお、私のPCでは動きませんでしたが、もしかすると自分でビルドをすれば動かすことも出来るのかもしれません。以下の環境で自分でChromium OSがビルドができるようです。
  • Ubnutu 12.04 LTS(64bit版)
  • メモリ 4Gバイト以上
  • ストレージ 10GB以上の空き容量
日経Linux 2013年12月号にて、Chrimoum OSのビルドの仕方や、その他の設定方法について書かれているので、力のある人は試してみてはいかがでしょうか。

2014年2月16日日曜日

大画面のスマートフォン

Nexus 5は、約5インチ(正確には4.95インチ)と大型の画面サイズのスマホとなっています。大画面になると片手で使えず不便という話があります。

私も男としては手の大きさはそれほど大きくはありません(だいたい手の付け根から中指の先までが7.5cmほどです)。そのため、私も正直Nexus 5ほどの大画面は必要なく、できればもっと小さい画面のスマホが欲しいと思っていました。しかし、SIMフリーであること、価格が安いこと、OSのアップデートが期待できること、などの利点からNexus 5の購入を決めました。

実際に使ってみて、最初は確かに使いにくかったです。しかし、現在では思ったより片手で使えるという印象があります。もちろん全ての操作は無理ですが。

例えば、最近のアプリはナビゲーションドロワーという左側から引き出すメニューがよく使われています。下はGoogle Mapでのナビゲーションドロワー表示画面です。



これは左上のアイコンをタップすることでも表示できるのですが、どこか左端を掴んで引っ張ることで表示することもできます。この方法では、無理に左上のボタンを押す必要がなくなっています。

また、Nexus 5標準のIMEでは日本語変換は手が小さいと大変ですが、Google日本語入力であれば下のように左寄せにすることができます(右寄せもできます)。このように設定することで、文字の打ち間違いが少なくなりました。


2013年のベストアプリでSmartNewsというアプリがあるのですが、これは操作方法もフリックメインで非常によく出来ており大画面であっても片手で操作しやすいです。全ての操作を片手で行うのは無理ですが、必要な時のみ両手を使えばいいと感じました。


結局のところ、大画面が片手で使いやすいかどうかはアプリ次第ではないかと感じました。Nexus 5の表示は非常に綺麗で、広い画面は効果的で良かったのではないかと思います。


ここから大画面とは少し関係がなくなりますが、むしろ必要無いのは、1920×1080のHDの解像度だったと思います。確かに解像度は細かければ細かいほど良いです。しかし必要以上なスペックは速度やバッテリーに悪影響なだけです。個人的な事ですが、私は目が悪いということもあって「細かい文字が読める」と宣伝されても小さい文字を読む気にはなれません。Nexus 5は特にバッテリーの持ちが良くなく、無理な解像度だったと感じます。

iPhoneも6インチが出るなどの噂がありますが、実際はどうでしょう?Androidと違い、解像度に柔軟性のない今のiPhoneの仕組みでは大画面化は非常に難しいと思われます。

今の9.7インチのiPadは、現在主流の縦横比である16:9にしようとして2731×1536ドットとすると丁度12インチぐらいになります(iPhone5のときのように従来のアプリは左右が黒くなりますが)。そのためiPadの12インチは出そうな気がします。

しかしiPhoneで6インチ版が出るとしたら、私では従来のアプリは真ん中に表示するか、拡大表示するぐらいしか方法が思いつず、見た目も使い勝手が悪くなりそうです。ですが、なんとかして大画面でも片手で使いやすいようにUIを大幅変更するのでは無いでしょうか。

2014年2月15日土曜日

WindowsからLinuxへの移行

世の中、ほとんどの人はOSはWindowsを使っていると思いますが、私はLinuxデスクトップのFedoraを使っています。私も昔はWindowsを使用していました。なぜLinuxを使用しようとしたか?理由は今サポート切れで話題になっているWindows XPが原因の一つでした。

Windows XPでは、アクティベーションというネットワーク等で認証をしなければインストールが出来ないという仕組みが初めて入ったWindowsでした。この仕組みは確かに海賊版を防ぐという目的には良いのですが、Microsoftが認証をしてくれなくなったら、自分の意志とは関係なく使えなくなるのでは無いかという不安があったためでした。

どうやらその不安は当たったようで、サポート切れ間近となった今もMicrosoftはWindows XPのアクティベーションをどのようにするかの発表は特にないようです。噂では2017年までは認証サーバーが動作するなどの話もあるようですが、どうなるのでしょう?

個人的にはサポート切れよりもアクティベーションがどうなるかの方が気になります。サポート切れになった場合、ネットに繋がない、ウィルスに感染したら再インストールと言う手もありますが、アクティベーションでインストールができなくなったら元も子もないです。

WindowsからLinuxへの移行は個人的には非常に良かったと思っています。Windows XPのサポート終了にともない、Linuxデスクトップが気になる人もいると思いますので参考にLinuxへの移行について書いてみます。



1.第一の難関、インストールを越えられるか?


ほとんどの方はWindowsが最初から入っている状態でPCを買っていて、OSのインストールはしたことが無いと思います。OSのインストールはそれほど難しくはないのですが、やはり多少の知識が必要です。それを苦と思うのであれば、Linuxは使用しない方が良いかと思います。

2.自作派には向いているかも


自作派の人はイントールはもちろんできると思いますが、さらにHDDを交換してLinuxを試すといったハードウェアまで含めた作業が出来るのが強みだと思います。また、自作の場合はWindowsも別途購入する必要があるので、その購入費用を抑えることもできます。

3.何に使うか?


WindowsやLinuxも道具の一つでしかありません。自分のしたいことが出来なくては意味がないでしょう。Windowsで動くソフトウェアはLinuxでは動かないので、そのソフトウェアがどうしても使いたい場合はLinuxは使用できません。Windowsのソフトウェアを動かすためのWineというソフトがありますが、あまり期待しない方がいいです。

しかし、インターネット使用であればFirefoxやGoogle ChromeはLinux用があります。Flash Playerも動作しますので、「艦これ」や「アメーバピグ」等のFlash Playerを使ったゲームなら動作すると思います。

WordやExcelやPowerPointの代わりとしてはLibreOfficeといったソフトウェアがあります。代わりのソフトウェアは使い勝手が違っていたり、機能が少ない場合もありますが、あまり難しいことをしないのであれば十分かと思います。

Linuxへの移行はやりたいことが出来るか確認することが大事でしょう。

4.大きな心が必要


一番重要なことかもしれません。Linux自体やLinuxで動くソフトウェアは無料であることが多いです。LinuxでもWindows等と同様(以上?)に不具合もありますし、使い勝手が悪いソフトウェアもあります。しかし、サポートを望むのは難しいです。多少の使い勝手の悪さは仕方ないと思う大きな心が無いと使えないかもしれません。

例えばWindows 8 などで使い勝手が変わったことに文句を言う人も多いですが、Linuxではそれ以上に使い勝手が変わって行くことを覚悟した方が良いです。

5.LiveDVDでとりあえず試す


Linux系のインストール用DVDは、LiveDVDといって、インストールを行う目的と試しに使う目的の2つの目的のDVDとなっています。つまりイントールをせずに動かすことができます。一度この状態で使用してみて、使えそうだったらインストールすると言う手があると思います。私の場合はKnoppixを最初に使ってこれなら使える!と考えました。

なお、DVDでなくUSBメモリから起動することができる場合もあります。

6.Ubuntuをおすすめ


Linuxというのは基本的な部分の名前で、実際にはこのLinuxを使ったいくつもの種類のOS(ディストリビューションと言う)があります。その数は600近いです。どれを使うかは悩むかもしれませんが、UbuntuがLinuxでは一番良く使われており、日本語の情報も多く、関連雑誌も多く、一番おすすめできるかと思います。

ただ、なぜか私の場合はLiveDVDでは動くのにインストールすると動かないと言うことがありました。そういう場合はFedoraなど別のLinuxを使うといいでしょう。

もし、PCが非常に古いのであれば、軽量のLinuxであるPuppy Linuxを選ぶと言う手もあります。

7.安くコンピュータを勉強するには一番?


最近はPCの勉強をしようと思う人は少ないかもしれませんが、コンピュータの仕組みが知りたい、プログラミングを勉強したい、と言う方にはLinuxはよい選択肢になると思います。やはり情報はWindowsの方が多いですし、開発環境としても Visual Studio の方が優れていると思いますが、使いにくいのも勉強になるのではないかと思います(汗)

使いやすさはともかく、プログラミング言語の選択肢の多さや、それらを試すことの気軽さはWindows以上と思っています。プログラミングは慣れればテキストやCUIベースが一番つぶしが効いて便利かとも思います。

8.将来性は?


アクティベーションの不安からFedoraへの移行をした私ですが、Linux OSに不安が無いかと言えば、将来性には不安はあります。少数ゆえにソフトウェアの新バージョンがでなかったり・・・。実際にFirefox用(正確にはNPAPI)のFlash Playerは開発終了が宣言されました。

ただアクティベーションのあるWindowsとは異なり、セキュリティの問題はあっても、今のハードウェアが壊れるまで使い続けることは可能だと思っています。そのときには別のディストリビューションに移行したり、Windowsに戻ればいいだけでしょう。

Fedrora 20 で Emscripten

ブラウザで動くプログラミング言語といえば、Javascriptです。Javascriptも良い言語だとは思いますが、やはりC/C++言語が使いたいこともあります。

今の所、ブラウザ上でC/C++で作成したプログラムを動かすには以下の2通りだと思います。

Native Client

Google Chromeのみで動作可(モバイルは現時点では不可?)。 普通のC/C++コンパイラのようにバイナリを作成する。サンドボックス化やジャンプ指令など危険な命令を使用させないことで、安全を確保。

Emsclipten

C/C++のプログラムからアセンブラっぽいJavascriptのコードを生成する。どのブラウザでも動作するが、最適化のための特殊なヒントを入れることでFirefoxではより高速に動作可能(asm.js)。




今回はEmscliptenをFedora 20で試してみました。

環境として、git, python, Node.js, clangが必要です。 pythonは最初から入っていると思うので、以下のようにgit, Node.js, clangをインストールします。

$ sudo yum install git nodejs clang


Fedora 19からNode.jsが追加されています。Fedora 18以前の場合は、Node.jsは以下のようにインストールします。

$ sudo yum --enablerepo=updates-testing install nodejs


次に、emscriptenのコードをGithubから持ってきます。

$ git clone https://github.com/kripken/emscripten.git


いつものように、Hello Worldのプログラムを作成して、以下のようにコンパイルします。emccがコマンドとなっています。C++の場合はem++です。

$ emscripten/emcc -o hello.html hello.c

hello.htmlができていると思うので、Firefoxで確認してみます。
$ firefox hello.html


以下のようにhello!が表示されます。


サンプルもいくつか入っているので、以下のように試してみると良いかと思います。

$ emscripten/em++ -o test.html emscripten/tests/hello_world_sdl.cpp

2014年2月1日土曜日

C++11のムーブコンストラクタの速度を試す

もうC++14が出ると言う話なので今更ですが、C++の2011年バージョン(C++11)のムーブコンストラクタ(右辺値参照)についてです。

C++11ではC++の機能アップが色々とありましたが、特にムーブコンストラクタ(右辺値参照)はSTLを使っていれば何もプログラムを変更せずに速度向上が見込めますし、素晴らしいです。

ムーブコンストラクタ(右辺値参照)のテスト用に以下のrvalue.cppを作成してみました。動作を切り替えるためのマクロが多く、見にくいプログラムですみません。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <memory>

/**
 * 数値を文字列で持つクラス
 * コンストラクタで数値を指定する
 */
class NumStr {
private:
        int capa_;
        char *str_;
public:
        explicit NumStr(int n) {
                capa_ = 16;
                str_ = new char[capa_];
                sprintf(str_, "%d", n);
        }

        ~NumStr() {
                delete[] str_;
        }

        NumStr(const NumStr& ns) {
                capa_ = ns.capa_;
                str_ = new char[capa_];
                strcpy(str_, ns.str_);
                #ifdef PRINT
                printf("copy1 %s\n", str_);
                #endif
        }

        NumStr& operator=(const NumStr& ns) {
                 capa_ = ns.capa_;
                 str_ = new char[capa_];
                strcpy(str_, ns.str_);
                return *this;
        }

// C++11からの新機能 ムーブコンストラクタ
#if __cplusplus >= 201103L
        NumStr(NumStr&& ns) {
                str_ = ns.str_;
                ns.str_ = nullptr;
                #ifdef PRINT
                printf("move1 %s\n", str_);
                #endif
        }

        NumStr& operator=(NumStr&& ns) {
                str_ = ns.str_;
                ns.str_ = nullptr;
                return *this;
        }
#endif
};

/**
 * メイン
 */
int main()
{

// 普通にNumStrを使う
#if !(defined(SHARED_PTR)||defined(PTR))

        std::vector<NumStr> list;
        #ifdef RESERVE
        list.reserve(9999999 * 2 + 1);
        #endif
        for (int i = -9999999; i < 9999999; i++) {
                list.push_back(NumStr(i));
        }
#endif

// NumStrをnewでメモリ確保する
#ifdef PTR
        std::vector<NumStr*> list;

        #ifdef RESERVE
        list.reserve(9999999 * 2 + 1);
        #endif
        for (int i = -9999999; i < 9999999; i++) {
                list.push_back(new NumStr(i));
        }
        // メモリの解放が必要
        for (std::vector<NumStr*>::iterator i = list.begin();
                                        i < list.end(); i++) {
                delete (*i);
        }
#endif

// NumStrをnewでメモリ確保。shared_ptrで自動でメモリ解放
#ifdef SHARED_PTR
        std::vector<std::shared_ptr<NumStr> > list;

        #ifdef RESERVE
        list.reserve(9999999 * 2 + 1);
        #endif
        for (int i = -9999999; i < 9999999; i++) {
                list.push_back(std::make_shared<NumStr>(i));
        }
#endif
        return 0;
}

ムーブコンストラクタの動きが分かりやすいようにstd::stringクラスの代わりとして、NumStrクラスを作成しています。16バイトサイズ固定で、数値を文字列して持つ、簡単なクラスです。

そして、そのクラスで作成した文字列をstd:vector(配列のクラス) に保存するだけです。

配列に保存する方法として、以下の3つで動作を試します。
  1. 普通(C++98)
  2. 普通(C++11)
  3. newのメモリ確保
  4. スマートポインタを使ってメモリ確保
速度比較の結果は以下です(上記の順番です。環境はFedora 20、gcc 4.8.2です。)

$ g++ -std=c++98 -O2 rvalue.cpp
$ time ./a.out

real 0m4.835s
user 0m4.283s
sys 0m0.478s
$ g++ -std=c++11 -O2 rvalue.cpp
$ time ./a.out

real 0m4.062s
user 0m3.665s
sys 0m0.354s
$ g++ -std=c++11 -DPTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.512s
user 0m3.112s
sys 0m0.386s
$ g++ -std=c++11 -DSHARED_PTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.968s
user 0m3.334s
sys 0m0.590s

1番は以前のバージョンC++98で動作させたもの。遅いです。
2番はmain()側は同じですが、NumStrクラスではC++11の新しいムーブコンストラクタを使った状態になります。速くなっています。
以前のバージョンでは速度を速くしよう考えるとnewでメモリを取得して、ポインタを配列に入れる必要がありました。それが3番です。しかしメモリの解放が必要であり、管理が大変です。
そこで、メモリを自動解放するスマートポインタを使ったのが4番です。

2番は原理上もっと速くてもいいはず。そこで、調べてみると・・・

$ g++ -std=c++11 -DPRINT -O2 rvalue.cpp
$ ./a.out | head -n20
move1 -9999999
move1 -9999998
copy1 -9999999
move1 -9999997
copy1 -9999999
copy1 -9999998
move1 -9999996
move1 -9999995
copy1 -9999999
copy1 -9999998
copy1 -9999997
copy1 -9999996
move1 -9999994
move1 -9999993
move1 -9999992
move1 -9999991
copy1 -9999999
copy1 -9999998
copy1 -9999997
copy1 -9999996

どうも配列のメモリサイズを拡張するときに、コピーコンストラクタが動作して遅くなっているようでした。ムーブコンストラクタでも問題ないはずですけど、なぜコピーコンストラクタが動作するのだろう?

そこで、メモリサイズ拡張が一回で済むように、予めメモリ確保をするようにしてみました。

$ g++ -std=c++98 -DRESERVE -O2 rvalue.cpp
$ time ./a.out

real 0m3.198s
user 0m2.977s
sys 0m0.210s
$ g++ -std=c++11 -DRESERVE -O2 rvalue.cpp
$ time ./a.out

real 0m2.581s
user 0m2.369s
sys 0m0.203s
$ g++ -std=c++11 -DRESERVE -DPTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.356s
user 0m3.011s
sys 0m0.335s
$ g++ -std=c++11 -DRESERVE -DSHARED_PTR -O2 rvalue.cpp
$ time ./a.out

real 0m3.591s
user 0m3.072s
sys 0m0.507s

2番のムーブコンストラクタを使ったものが一番速くなりました。

最後のまとめです。
  • ムーブコンストラクタ(右辺値参照)は速い!
  • 無理にnewを使わなくても良くなり、プログラムが作りやすい!
  • しかしstd::vectorライブラリ内でメモリ拡張時にコピーコンストラクタが無駄に起動して遅くなることがある。

2014年1月26日日曜日

プロセスとスレッドの話

1.プロセスとは?


WindowsやLinux等のOSでは、ワープロやブラウザなどのアプリケーションを実行するとプロセスというものを作ってその中でアプリケーションを動かします。

コンピュータの仕組みをざっくり話すと、CPU(処理実行)、メモリ(データ記憶)、I/O(外部入出力)の3つで出来ていますが、 このCPUとメモリの部分を仮想的に作ったものがプロセスです。

なんとなくのプロセスのイメージです

実際のCPUとメモリは、複数の仮想的なCPUとメモリを切り替えながら動作させることになります。この複数の仮想的なCPUとメモリはそれぞれは完全に分離されています。その事からプロセスには以下の利点があります。
  1. 分離された環境でプログラムを動かせば良いのでプログラミングが楽。
  2. メモリが分離されているので、他のアプリケーションから干渉を受けず、セキュリティに強い。
最近はセキュリティが大きく取り上げられることも多く、Chromeなどのブラウザでは1つのアプリケーションに見えても、タブごとに複数のプロセスが作るなどの工夫がされています。

2.WindowsとLinuxのプロセス生成の違い


WindowsとLinux(正確にはUNIX系)ではプロセス生成の仕方が少しだけ違っています。Windows(Win32 API)では以下のようにCreateProcess関数でプロセスを作成します。引数の詳細の説明は省きますが、notepad.exe(メモ帳です)のようにアプリケーションを指定してプロセスを作成します。

#include <windows.h>
#include <tchar.h>

int main()
{
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        BOOL r;

        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        r = CreateProcess(_T("C:¥¥Windows¥¥System32¥¥notepad.exe"), NULL,
                                NULL, NULL,
                                FALSE,
                                0,
                                NULL,
                                NULL,
                                si, &pi);
        if (r) {
                MessageBox(0, _T("CreateProcess Success!"), _T("Test"), MB_OK);
                CloseHandle(pi.hThread);
                CloseHandle(pi.hProcess);
        }
        return 0;
}

これに対してLinux(UNIX系)では以下のようにfork関数とexec関数の2つを使用します。fork関数の時点でプロセスが作られますが、ここでは自分自身のコピーのプロセスを作成します。新しく作成したプロセスかどうかは返り値で判断できます。そして、exec系関数(execl, execlpなど色々とある)で指定されたアプリケーション(ここではgedit、GNOMEでのメモ帳みたいなソフト)に置き換えをします。

#include <unistd.h>
#include <stdio.h>
#include <signal.h>

int main()
{
        pid_t pid;

        pid = fork();
        if (pid == 0) {
                execlp("gedit", "gedit", NULL);
        } else if (pid != -1) {
                struct sigaction act;

                printf("create process success!\n");
                act.sa_handler = SIG_IGN;
                act.sa_flags = 0;
                sigemptyset(&act.sa_mask);
                sigaction(SIGCHLD, &act, NULL);
        }
        return 0;
}

一旦プロセスのコピーをするので無駄な処理を行っているように見えますが、以下のような利点もあります。
  1. 別の実行ファイルを作らなくても複数プロセスが作成できる。
  2. 同じようなプロセスを複数作りたいときにコピーが簡単に作成できる。
また、プロセスのコピーといってもCOW(Copy On Write)という方式を使っており、ほとんどオーバーヘッドはありません。

なかなか利用法がないように思えますが、Androidにおいては、主要なライブラリのみ読み込んだプロセスを作っておいて、そのプロセスをforkすることで、高速に新しいプロセスを作成できるようになっています(通常はプロセスを作ってからライブラリを読み込みます)。そのためJavaであってもアプリケーションの起動が速いです。

3.スレッドとは?


プロセスはCPUとメモリを仮想的に作成したものでしたが、メモリ部分だけは共通にCPU部分だけを分けたい事があります。この場合に使われるのがスレッドです。

例えば、長い処理をウィンドウの処理内で行うと、ウィンドウ管理システムが応答が無いとの警告を出す場合があります。こういうとき、長い処理はスレッドで行い、ウィンドウ処理では「お待ちください」 というメッセージと共にプログレスバーを表示するなどで使われます。

以下のような利点があります。
  1. プロセスだとメモリが分離しているため、データのやりとりのプログラミングが難しいし、データのやりとりの速度が遅い。
  2. プロセス(CPUとメモリ)を切り替えるより、スレッド(CPU)のみ切り替えたほうが速度が早い。

4.WindowsとLinuxでのスレッドの違い


使い方などはほとんど同じですが、WindowsとLinuxでは、実装で少し違いがあります。

Windowsでは、スレッドはプロセスの中に在るものというようなイメージになっています。CreateProcess関数の例でもプロセスを作るとスレッドも同時にできるので、CloseHandle関数でスレッドとプロセスの両方を解放しています。

Linuxでは、スレッドは軽量プロセスというような意味合いになっており、メモリを共有したプロセスのように扱われています。実際プロセスの作成のfork関数もスレッド作成の関数も内部的にはclone関数が呼ばれており、プロセスとスレッドの差が小さいです。

スレッドのイメージ。Windowsが左側、Linuxが右側

5.マルチCPUと並行処理


最近のコンピュータでは、単体のCPUの速度向上が頭打ちになってきました。そこで、複数のCPUを搭載して処理速度をあげようとしています。

そのため、プロセスやスレッドの利用目的として、速度向上の役割ができてきました。1つの事でも複数で同時に並行処理をすることで、処理速度をあげます。しかし1つの事を同時に複数に行うには

並行処理の方法には大きく以下の3つの方法があります。
  1. データ並列化
  2. タスク並列化
  3. パイプライン並列化
 例えば、千羽鶴を多人数で作成することを想定します。折り紙がデータとなります。

データ並列化は1人が何枚ずつ折り紙を折るかに分けて作業する方法です。1人ごとの折り紙の量を間違うと全体として完了は遅くなります。

タスク並列化は、折り紙を一箇所に置いておき、 それを皆が一枚づつ取っていき鶴を折ります。一箇所に折り紙が置いてあるので、取るとき手がぶつかる可能性があり、それを避ける仕組みが必要です。

パイプライン並列化は流れ作業です。1人ずつ半分に折る担当、羽を折る担当などの作業の担当を分け、次の作業へと渡していきます。時間がかかる担当の場所があると、そこで折り紙がたまってしまう事になります。

秀和システムより「マルチコアCPUのための並列プログラミング―並列処理&マルチスレッド入門」が出ていますが、上記の並列についてWindows、Linuxについてのソースコードも含め、書かれているので参考になると思います。

少し内容が古くなっており、WindowsVista以降に入った条件変数のAPIについて書かれていないなどがありますが、異種混合CPUや、OpenMPなどのライブラリについても書かれており、入門には良いのではないかと思います。


6.プロセスとスレッドとメモリの関係と実験


並列で高速化する際に難しいのがメモリの扱い方です。 CPUからメモリに書き込みをする際に同時に書き込みをしないようにする排他制御が必要です。例え、データ並列化の場合にソフトウェア的にソースコードでは排他制御が必要ないとしても、ハードウェア的にはCPUとメモリの間のキャッシュがあり、データをある程度まとまった固まりで扱おうとするため、その事も考慮する必要があると思われます。その点では元々メモリが分かれているプロセスの方がスレッドよりはプログラミングの考慮は少なく済むかもしれません。

スレッドにおいて以下のようなプログラムで実験をしてみました。

#include <stdio .h>
#include <stdlib .h>
#include <memory .h>
#include <pthread .h>

#define MEMSIZE (1024L * 1024L * 1024L)

void mem_init(void *mem)
{
        int *p;
        long i;

        p = (int *)mem;
        for (i = 0; i < MEMSIZE; i++) {
                *p = 0;
                p++;
        }
}

void mem_init1_1(void *mem)
{
        int *p;
        long i;

        p = (int *)mem;
        for (i = 0; i < MEMSIZE / 2; i++) {
                *p = 0;
                p+= 2;
        }
}

void mem_init1_2(void *mem)
{
        int *p;
        long i;

        p = (int *)mem + 1;
        for (i = 0; i < MEMSIZE / 2; i++) {
                *p = 0;
                p += 2;
        }
}

void mem_init2_1(void *mem)
{
        int *p;
        long i;

        p = (int *)mem;
        for (i = 0; i < MEMSIZE / 2; i++) {
                *p = 0;
                p++;
        }
}

void mem_init2_2(void *mem)
{
        int *p;
        long i;

        p = (int *)mem + MEMSIZE / 2;
        for (i = 0; i < MEMSIZE / 2; i++) {
                *p = 0;
                p++;
        }
}

int main(int argc, char *argv[])
{
        int *mem;
        int proc = 0;
        pthread_t pth;

        if (argc > 1) {
                proc = atoi(argv[1]);
        }
        mem = (int *)malloc(MEMSIZE * sizeof(int));
        if (mem == NULL) {
                printf("malloc error\n");
                return 1;
        }
        switch (proc) {
        case 0:
                mem_init(mem);
                break;
        case 1:
                pthread_create(&pth, NULL, (void *)mem_init1_1, mem);
                mem_init1_2(mem);
                pthread_join(pth, NULL);
                break;
        case 2:
                pthread_create(&pth, NULL, (void *)mem_init2_1, mem);
                mem_init2_2(mem);
                pthread_join(pth, NULL);
                break;
        defalut:
                break;
        }
        free(mem);
        return 0;
}

単なる大量のメモリの初期化のプログラムです。引数が0番はスレッドを使わないもの。1番はキャッシュが効かないようにと作ったもの。2番はキャッシュが効くように作ったものです。sched_setaffinity関数でCPU指定をしていませんが、1番と2番はCPUを別に使っていました。

速度比較の結果は、user timeが0番は0.350s程度、1番が0.500s程度、2番が0.375s程度で、速度順は 0 > 2 > 1 でした。初期化程度ではスレッドなど他のオーバーヘッドなどの方が大きく、あまり意味のないテストだったかもしれませんが、1番が一番遅い結果となりました。マルチCPUの処理は思ったように速度をあげるのが難しいのは確かです。

2014年1月19日日曜日

Fedora 20 と Nexus 5 を使用して Andoridアプリ開発準備

Nexus 5は使うだけでも良い端末ですけど、元々はNexusシリーズはリファレンスモデルと呼ばれ、開発用の意味合いが大きい機種です。Androidは誰でも簡単にアプリ開発ができることも利点の1つですし、開発に使わないと勿体無いです。

そこで、開発の準備です。これから書く内容は以下を参考にしています。

Fedora 20でのAndroidアプリ開発環境の準備


まずは関連モジュールのインストールをインストールします。java-1.7.0-openjdkは最初から入っていると思われます。また64bitの場合には以下のように32bitのモジュールをインストールする必要があります。

$ sudo yum install glibc.i686 glibc-devel.i686 libstdc++.i686 
$ sudo yum install zlib-devel.i686 ncurses-devel.i686 
$ sudo yum install libX11-devel.i686 libXrender.i686 libXrandr.i686

次にAndroidの開発環境を以下からダウンロードします。「ADT Bundle」の方が開発環境が英語になると言う問題はあるものの、とりあえず始めるには楽です。



以下の手順を行えばインストールは完了です。
  • 上記の中から、adt-bundle-linux-x86_64-20131030.zipをダウンロードします。
  • ダウンロードしたzipファイルを自分のホームディレクトリに解凍し、~/AndroidSDKに名前を変更します。 
  • 自分のホームディレクトリにある.bash_profileファイルに、パス環境変数として、~/AndroidSDKを追加します。例えば、以下のようにします。
    PATH=$PATH:$HOME/AndroidSDK/sdk/tools
    export PATH
    
    # For SDK version r_08 and higher, also add this for adb:
    PATH=$PATH:$HOME/AndroidSDK/sdk/platform-tools
    export PATH
    
  • ログアウトして再ログインし、パスの変更を適用します。

参考にWindowsでのAndroidアプリ開発環境の準備


実際に私が行っていないのですが、Windowsでの開発準備もJDKをインストールする以外は同様です。ここが参考になると思います。


Eclipseの起動と画面の説明


端末上で、以下のようにして開発環境であるeclipseを起動します。

$ ~/AndroidSDK/eclipse/eclipse

起動をすると、以下のような画面になっています。ツールバーのボタン等を覚えておくと良いです。




Androidプロジェクトの作成


Androidプロジェクトは作成するAndroidアプリのためのソースコードを構成する全てのファイルを含んでいます。デフォルトのプロジェクトのディレクトリやファイルを使って簡単に新しいAndroidプロジェクトを始めることができます。

  1. ツールバー上のNew(一番左)のボタンをクリックします。
  2. 表示されたウィンドウで、Androidフォルダー内のAndroid Application Projectを選択し、Nextをクリックします。
  3. 表示されたフォームに書き込みをします。
    • Application Nameは、ユーザーに表示されるアプリの名前です。このプロジェクトでは"My First App"とします。
    • Project Nameは、プロジェクトのディレクトリの名前でEclipse上で使われる名前です。
    • Packege Nameは、アプリのパッケージの名前空間名です。JAVAプログラミング言語のルールで唯一の名前を名前をつけるための組織名です。このプロジェクトでは、とりあえす"com.example"のネームスペースを使用します。
    • Minimum Required SDKは、アプリがサポートする最も低いAndroidのバージョンを指定します。今回はデフォルトのままとします。
    • Target SDKは、アプリをテストした最も高いAndroidのバージョンを指定します。Nexus5でテストするので4.4で良いです
    • Compile Withは、アプリをコンパイルするバージョンを指定します。SDK Mangerで古いバージョンを追加しなければ、最新のバージョンのみしか入っていません。
    • Themeは、アプリに適用するAndroidのUIスタイルを指定します。そのままで良いです。
  4. 次の画面で、プロジェクトの設定をしますが、そのままの選択でNextをクリックしてください。
  5. 次の画面は、アプリのアイコンの作成を手伝います。画面解像度に合わせて作成します。通常はデザインガイドに合うように作成する必要がありますが、とりあえず最初のままでNextをクリックします。
  6. ここで、作るアプリのアクティビティ(アプリの1つの画面のこと)のテンプレートを選択します。このプロジェクトではBlankActivityを選択してNextを押してください。
  7. アクティビティの詳細は全てデフォルトでFinishをクリックしてください。

いくつかデフォルトファイルからAndroidプロジェクトが作成され、アプリを作る用意が完了します。


エミュレータでアプリの実行をしてみる


PC上のAndroidのエミュレータでアプリの動作を確認することができます。まずは、どのような端末でエミュレートするかAVD(Android Virtual Device)を作成する必要があります。

  1. ツールバーからAndroid Virtual Device Managerを起動し、Device Definitionsのタブを選択します。
  2. 残念ながらNexus 5が無いので、Nexus 4 by Googleを選択して、Create AVDボタンを押します。
  3. OKボタンでNexus4のエミュレータが出来ます。
  4. Android Virtual Device Managerを「Esc」キーを押して終了します。

先ほど作成したAndroidプロジェクトを実行します。

  1. ツールバーのRunボタンからアプリを実行します。
  2. Run As のウィンドウが表示されたら、Android Application を選択してOKをクリックします。

エミュレータが起動して(非常に時間がかかります)、ロックを解除すると、以下のようにアプリケーションが実行されています。



Nexus 5 でアプリの実行をしてみる


Androidのエミュレータは残念ながら非常に遅いです。Windowsであれば、Intel x86 Emulateor Accelerator(HXAM)を使用する方法もあるのですが、Linuxでは使用できません。Neuxs 5等のデバイスを使うのが一番良いです。

まずは、Nexus5側で開発の準備をします。

  1. 設定の端末情報を開き、ビルド番号を7回タップします。
  2. そして設定画面に戻ると開発者向けオプションが表示されるので、タップします。
  3. USBデバッグにチェックを入れます。

後はPCとNexus 5 をUSB接続し、同様にRunボタンで実行します。以下のようにNexus5に表示されます。


これで、Androidアプリを作成するための準備は完了です。後はAndroidプロジェクトを自分が作りたいアプリに変更していきます。