GTK+自作ウィジェットの描画処理を軽くする

グラフィックアクセラレータのない組み込み環境でGTK+を使う場合、描画処理はけっこう負荷の高い処理です。例えば画像を大量に描画すると、その負荷が高くてバックグラウンドで別の処理を進めることができないということも起こりえます。
そこでGtkDrawingやGtkLayoutに自作の描画ハンドラ (exposeイベントのシグナルハンドラ――以下、exposeハンドラ) を作るときに無駄な描画処理をしないためのテクニックを紹介したいと思います。

背景色を正しく設定する

ウィジェットのある部分についてexposeイベント (ひらたく言えば描画イベント) が発生すると、当該部分が背景色で塗り潰されてからexposeハンドラが呼ばれます。ここを別な色で塗り直すのは当然無駄なわけで、ウィジェットの生涯を通じて最も描画面積の大きい色を背景色として設定しておけば、描画処理は軽くなるでしょう。

クリッピングする

ウィジェットの重なりが変更されたり、GtkLabelなどの自分のGdkWindowを持たないウィジェットの内容が変更されたりすると、
下になっているウィジェットの重なっている部分が再描画されます。
exposeハンドラでは、GdkGCを設定して、ウィジェットの必要な部分だけを書き換えるようにしましょう。

GdkRegionを使う方法

この方法が推奨されているようです:

static gboolean
my_widget_expose_event_handler (GtkWidget *widget, GdkEventExpose *event) {
  GdkGC *gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
  gdk_gc_set_clip_region(gc, event->region);
  /* 描画処理 */
  gdk_gc_set_clip_region(gc, NULL);
  /* 他の処理 */
}

GdkRectangleを使う方法

static gboolean
my_widget_expose_event_handler (GtkWidget *widget, GdkEventExpose *event) {
  GdkGC *gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
   gdk_gc_set_clip_rectangle(gc, &event->area);
  /* 描画処理 */
  gdk_gc_set_clip_rectangle(gc, NULL);
  /* 他の処理 */
}

ウィジェット全体を再描画するのはやめよう

クリッピングとも関係のある話ですが、手抜きをしてgtk_widget_queue_redraw_areaを使うのは避けるべきです。gtk_widget_queue_redraw_area を多用している場合は設計を見直した方がいいかも知れません。
特に画像を重ねて描画している場合、効率よく再描画するために重なりを管理する処理を書くことになりがちです。それはGTK+が既に持っている機能なので自分で作るべきではありません。

バグのあるウィジェットは使わない

バグのあるウィジェットとはGtkFixedのことですが、子ウィジェットを動かすとGtkFixed全体が再描画されるというバグがあります。

具体的なことはgtk_fixed_moveとgtk_layout_moveの実装を比較すると分かりますし、直すことも難しくありません。しかしGtkFixedは設計も古く (よく言えば単純で)、あんまりメンテナンスされていないようなので使わない方がいいでしょう。

おしまい

ぶっちゃけGTK+は独学なのであまり偉そうなことは言えません。むしろ教えてください。
Happy hacking!

クラッシュ&移行 ~Cerevo社内開発用サーバ構築記~

まつけんです。

Beagle Boardの記事が好評だったので、そのままなにかBeagleネタで行こうかとおもったのですが、本日、開発マシンが突然死したので、哀しみの開発マシン移行記を今回は書いてみます。

事の発端

土曜日の午前中、結構集中してコーディングをしていました。マシン自体は、快調に動いており、問題なく作業を進めました。ふと、喉が渇いて、お茶を汲んで、トイレに行ってきました。かえってきたら、sshでログインしているターミナルがすべて反応しません。

あれっとおもって、マシンを見ると、CPUファンが回っていません。あれ、電源落ちた?と思い、近づきます。明らかに焦げ臭いにおいが漂ってきました。危険な感じがヒシヒシと伝わってきます。とりあえず、保存してない分のソースは藻屑と消えました、合掌。。。って、この時点でテンション-10です。

とりあえず、原因をさぐるために、マザーボードに顔を近づけます。どうも、臭いのもとはCPU周辺で、かつ、ヒートシンクは触れないくらい熱くなっています。CPUが焦げて再起不能になった感たっぷりです。

ちょっと余談ですが、自作PC系でオーバークロックとかを趣味にされている方を中心に、なんというかこの臭いを感じた瞬間のテンションの下がりかたは、経験のある人はわかるとおもうのですが、完全に脱力系です。

さて、そうなると、とりあえず、電源ボタン、というか、マザーに直刺ししているスイッチを押しても当然のように反応がありません。これはやばいな、ということで、とりあえず、電源ケーブルを抜きます。ここで、おもむろにヒートシンクを掴むとやけど確実に火傷します。とりあえず、はやる気持ちを抑え、心を落ち着けて、深呼吸しながら冷えるのを待ちます。何故かこの時間の間に自分で自分を無駄に責めます。エアフローダメすぎとか、いや、ていうか根本的にオーバークロックしてる時点で、とかぐるぐるしながら待ちます。

さて、こっからが問題なのですが、結局のところ、起動しない原因がCPUかどうかを確定するのは結構厄介です。わざわざほかのマシンに挿してみるのも面倒ですし、それでなんかショートとかしてて、その検証用マザーを壊した日には泣くに泣けません。

というわけで、とりあえず、もう一度だけ、電源をつないでみて、CPUを刺し直して、起動をためしてみました。やっぱりダメです。ここで、結論をだします。諦めてマシンを新調することにしました。

新旧マシン構成の変化点

事の発端が、むやみと長くなりました。さっきクラッシュして、マシン組み直したばかりなので、まだショックから抜け切れていないせいか、まだ妙にハイテンションです。そのせいもあり、どこかのだれかに共感してほしくて長く書いてしまいました。

さて、本題にもどって、新しいマシンにするなら、どういう構成にするかを決めて、必要なものを買い出しです。うちの会社はアキバのPCパーツ系ショップエリアから徒歩3分くらいなので、買い出しには困りません。この会社の位置は素晴らしいです。

結局、開発マシンで壊れている部分を考えると、CPUは間違いなさそう、マザーはどうだろう、微妙だな、という具合です。一番、やすく済ませるなら、とりあえずCPUだけ買ってきて変えてみるのも手なのですが、これを期に、ウチのほかのサーバ用マシンと構成をあわせるのもついでにやってしまおうということで、思い切ってAMDなPhenomからIntel C2Qに変更することにしました。そうすると、もれなくマザーも買い換えです。

なので、購入したのは以下の部品です。

  • Intel Core2Quad Q9550
  • Intel DQ45CB

なんで、DQ45CBかは、はてなさんのサーバが公開された時も紹介されていましたが、キーワードは消費電力とIntel AMTです。このへんの話題はまた来週のエントリを書く際にご紹介したいとおもいます。

もともとのCPUとマザーボードは、以下のような構成です。

  • Phenom 9950BE 3.0GHz (x15に倍率変更)
  • GIGABYTE GA-MA78GPM-DS2H

まあ、ご覧の通り、OCしてるし、VCoreもちょっと盛ってるので、壊れたのはまさに自業自得です。

それ以外のメモリ、HDD、電源などのパーツはすべて流用です。

Gentooの移行

マシンは昼飯ついでに買ってきて、さくさくっとくみ上げます。ざっと配線などをチェックして電源を入れます。うん、うまく動きました。とりあえず、予想通り、CPUかマザーが壊れているので正解だったようです。電源とかだったら、涙目になるところでした。

とりあえず、BIOSとAMTまわりをざーっと設定します。さて、あとは、OSの移行です。もともと、開発マシンはGentooがインストールされていたので、その環境を再現しましょう。

基本的に、すでに動いていたHDDを挿すので、そのまま起動するはず、と一瞬おもったんですが、よく考えたらCPU変えたけど、大丈夫かいな、とおもいつつ、起動します。まずは、不安的中、カーネルがIOMMUまわりで刺さります。

わーん、となげきつつ、しょうがないのでまずはカーネルを入れ替えるところをやります。とりあえず、USB-HDDから起動できるようにしたGentoo MinimalインストールCDイメージがあったので、そのHDDをつないで、そこから起動します。

起動できなかったHDDを適当なところにマウントします。まあ、インストール時と同じ、/mnt/gentooがわかりやすい気がします。

# mount /dev/sda1 /mnt/gentoo
# mount /dev/sda2 /mnt/gentoo/var
# mount -t proc none /mnt/gentoo/proc
# mount -o bind /dev /mnt/gentoo/dev

おもむろに、chrootします。うまくいったので、深く考えなかったんですが、ここで実行できるバイナリだったので、よかったです。chrootできないと結構悲惨でしたね。

# chroot /mnt/gentoo /bin/bash
# env-update

さて、カーネルが刺さるので、コンフィグを見直します。とりあえず、同じ構成でうごいているマシンがあるので、その.configをもってきます。バージョンが2.6.30.2->2.6.30.4だったので、

# make oldconfig

します。さて、ここで問題発生。いつになっても、oldconfigがおわりません。そんな時間のかかる処理だったっけ、とあまりよく考えず、3分くらい待ちました。やっぱり終わりません。ここまできて、ようやくtopとかvmstatを眺めます。cc1が100%のまま、ずーっと張り付いています。ここで激しく嫌な予感。もしかして、gccがPhenom向けにコンパイルされててうまく動いてない感じなのか、と気づきます。そういえば、gccのオプションを/etc/make.confで-march=nativeとかにしています。やばげ。

さて、どうにかしないといけません。とりあえず、作戦を変更して、カーネルだけほかのマシンからもってきて、grubを書き換えて起動します。nicとかがudevのせいで、eth1に変わったりしてちょっと変ですが、とりあえず、うまく起動しました。これで、gccもうごくといいなー、とまったく根拠のない希望をもちつつ、make oldconfigと叩きます。はい、やっぱりダメです。

うーん、これはなんとかして、このマシン上でも動くgccを用意するしかありません。これも、結局、他のマシンのgcc, glibcをもってくることにしました。しかし、どのファイルをもってくればいいのか、特定するのはめんどくさいです。

解決策は、Gentooならquickpkgをつかって、バイナリパッケージをtbz2で作成してくれます。

# quickpkg gcc glibc

そうすると、/usr/portage/packages以下にファイルができあがります。これを開発マシンにコピーします。そして、はじめは、淡い希望をもって、emerge経由でインストールできないもんかと試します。

# emerge -avk =sys-devel/gcc-4.3.3-r2

残念。やっぱりcc1が暴走して、永遠に終わりません。となると、バイナリパッケージって所詮、ただのtarで固められたアーカイブなので、思い切って上書きで展開します。なにかおこったら、諦めて最初から構築しなおしの覚悟を決めます。

# tar jxpvf gcc-4.3.3-r2.tbz2 -C /
# tar jxpvf glibc-2.9_p20081201-r2.tbz2 -C /

さて、とりあえず、gcc -vとかためして、入れ替わったか確認します。うん、上書きされたようです。そして、再度、make oldconfigします。やった、うまくいきました。

ここまでいけば、あとは、カーネル再構築して、バイナリを最適化されているものに入れ替えです。Gentooつかってると、emerge -eDN worldとかちょっとわくわくしますよね。とか書いて、そんなわけねーよと思われていたら、悲しいですが。

そして、現在、emerge worldの最中です。問題無く、コンパイルされているようです。あとは、待つのみ。

最後に

これで、なんとか開発マシンがもとの状態にもどるところまでたどり着きました。

今回の教訓。

CPUとか変更するなら、事前にもうちょっといろいろ考えろよ、自分、っていうところにつきますね。まあ、なんとかなったからいいか、とおもって、毎回、こういう行き当たりばったりなことをしている気がします。直そう。

まあ、とりあえず、こういうときにいろいろ手が考えられるところとかも含め、いろいろGentooは楽しいです。みんなUbuntuとか言わずに、Gentooにしようよ、と社内で布教中なのですが、だれも言うことを聞いてくれません。悲しいです。ていうか、Ubuntuを使っていると、このケースならトラブルなく移行できた気がしますね。負けました。

さて、次回のエントリは、Intel AMTで快適リモート操作〜IPMIなんてなくても頑張れる子 DQ45CB〜をご紹介したいと思います。

では、長々と書きましたが、ここまで読んでくれた方、大変ありがとうございました。

最後に新旧開発マシンはこんな感じ。

Introduction of UBIFS

はじめまして、Cerevoの中河です。
ソフトウェア担当で主にLinuxカーネル/ドライバ回りを担当しています。
今回はUBIFSとういうLinuxで使用できるファイルシステムについて書きたいと思います。

UBIFSって?

UBIFSとはNANDフラッシュメモリ向けに開発されたファイルシステムです。
フラッシュメモリと言うと、一般的にはUSBメモリやSSDが連想されるかもしれませんが、それらのデバイスはハードディスクと同じような扱いが出きるようハードウェア的な仕組みが入っている為、ここでは該当しません。
UBIFSが対象としているのは、あくまでもCPUのNANDフラッシュメモリ・コントローラに直接接続されたNANDフラッシュメモリです。

何故UBIFS?

フラッシュメモリ上では、JFFS2というファイルシステムが広く使用されてきました。
しかし、JFFS2にはフラッシュメモリの容量に比例して、マウント時間やメモリ使用量が大きくなってしまうという設計上の問題があり、昨今の大容量NANDフラッシュメモリには対応できなくなってきました。
そういった問題を解決するために設計・開発されたのがUBIFSです。

JFFS2と比較すると、UBIFSには以下のような特徴があります。
– 高速マウント
JFFS2の様にマウント時にパーティション全体をスキャンする必要が無く、高速にマウントできる。
– 省メモリ
JFFS2はファイルシステムのインデックスをメモリ上に置いていたため、容量に比例して大量のメモリを消費していましたが、UBIFSではインデックスをフラッシュメモリ上に置いているため、メモリ消費量が少ない。
– Write-Backサポート
Write-Backをサポートしているため高速に書き込み処理が出来る。
– UBI
JFFS2はMTDと呼ばれるフラッシュメモリ・デバイスドライバを抽象化したサブシステム上で動作しますが、UBIFSはMTD上にさらにUBIという、ウェアレベリング※1と論理ボリュームを実現するレイヤをのせ、その上で動作します。

UBIFSを使用してみる

– まずホスト環境で、UBIツールをクロスビルドします。
$ git clone git://git.infradead.org/mtd-utils.git
$ cd mtd-utils/
$ CROSS=arm-uclinuxeabi- make

– ビルドしたflash_eraseallとubimkvolコマンドをターゲットにコピーしてください。
$ cp arm-uclinuxeabi/flash_eraseall [ターゲットのroot]/usr/bin
$ cp arm-uclinuxeabi/ubi-utils/ubimkvol [ターゲットのroot]/usr/bin

– 続いてターゲット環境上でUBIFSで使用するmtdパーティションを初期化します。
$ flash_eraseall /dev/mtd1

– 以下のブートパラメータを追加します。
ubi.mtd=1

– 最後にUBI論理ボリュームを作成 & マウントします。
$ ubimkvol /dev/ubi0 -n 0 -N ubifs -m
$ mount -t ubifs ubi0_0 /mnt

まとめ

駆け足でしたが、UBIFSを紹介してみました。
UBIFSは製品レベルで十分使用できるものと考えていますので、大容量NANDフラッシュメモリを使用する場合は、是非UBIFSの採用を検討してみてください。
またそのうち、UBIFSやUBIの内部構造もご紹介できればと思います。

参考
UBIFS – http://www.linux-mtd.infradead.org/doc/ubifs.html
UBI – http://www.linux-mtd.infradead.org/doc/ubi.html

※1 http://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%AC%E3%83%99%E3%83%AA%E3%83%B3%E3%82%B0

モバイル機器開発Tips ~パワーマネージメント その1~

こんにちは、Cerevoの鈴木です。
今回はモバイル機器では必須のパワーマネージメントについて扱ってみます。

なぜパワーをマネージメントするのか?

ノートパソコンや携帯、デジカメなどのモバイル機器には電源としてバッテリが実装されています。
バッテリの容量というのは大小色々ありますが、有限です。
その限られた電力で出来るだけ長時間動作させたい、というのが目的になります。
(もっと大容量、もっと小型のバッテリが使えるようになると話は変わるのかも知れませんが)

良く使われるパワーマネージメント方法

出来るだけ電力消費を抑えるのが目的になるので、実際には機器内部のハードウェア・デバイスを色々と制御することになります。
いくつかの手法がありますが、世の中の常でプロコンがあります。

ソフトウェアスタンバイ

まずはデバイスの省電力機能を使うことが上げられます。
最近のデバイスはレジスタにアクセスすることで省電力モードになるものがあります。
「ソフトウェアスタンバイ」なんて言葉でこの機能が説明されている場合が多いです。
この手法はお手軽で通常の状態に復帰するのも早いですが、一方でそれほど消費電力が下がらないということがあります。

ハードウェアスタンバイ

次にデバイスのピンの電圧を変化させることで省電力状態にする手法があります。
これは上の例とは異なり、外部からターゲットとなるデバイスのピンに対してHigh or Lowをハード的に出力する手法になります。
「ハードウェアスタンバイ」なんて言葉で説明されている場合が多いです。
この手法はHigh or Lowを出力する仕組みが別途必要になるのでお手軽ではないのですが、大体の場合は消費電力が大幅に低下します。

電源制御

最後はターゲットとなるデバイスの電源をOFFにしてしまう手法です。
これは分かりやすいですね。消費電力は0になります。
ただし、電源ラインをON/OFFできるスイッチ(古くはリレー、最近はFETなんかで構成できます)とそのスイッチを制御する仕組みが別途必要になるのでハードウェア的には一番複雑になります。
しかも電源をOFFにしてしまうので、通常状態に復帰させるためには電源をONにして初期設定をし直さないといけません。
・・・でも、でも、「消費電力ゼロ」は魅力的なわけです。また、起動に1分かかるPCとは違って、起動して初期設定完了まで1~2秒程度、なんてのが一般的なので、意外に使えちゃったりするわけです。ケータイのカメラなんかは良い例ですね。

まとめ

概要は以上なのですが、実際には機器内部には多くのデバイスがあって、動作仕様によって今回の3つの手法を織り交ぜて使います。
パワーマネージメントはハードとソフトが協調して動かないといけないので、ちゃんと設計しないといけない雰囲気は伝わったかと思います。
次回は少し具体的な例を紹介しようと思います。

コンクリート壁への内装品固定方法

こんばんわ、岩佐です。
私は会社でコードを書いていないので、”Tech”はテックでもコードにまで落ちない、商品企画レベルでのテクノロジー系ネタを扱っていくことにします。あと、オフィス設営なんかに関する日曜大工的なTechTopicsなどなど。

というわけで第一弾はいきなり日曜大工系で「コンクリート壁への重量物取り付け」。具体的にはライティングレールなど(※配線には要電気工事2種資格)。

用意するのは電気ドリルとコンクリート用ドリル刃、コンクリートアンカープラグ、タッピングビス。コンクリート壁に通常のタッピングビスを打ってもすぐに抜け落ちてきてしまいますので、ドリルで下穴をあけてからアンカーを指し込み、タッピングビスを打ち込むことでコンクリート内でアンカーが広がり、固定されます。

ポイントはコンクリート専用ドリル刃というのが売っていますので、これを使うこと。柔らかいところであれば鉄鋼用の刃でも太刀打ちできますが、刃がすぐにダメになってしまいます。また、アンカープラグの長さよりも少し長いビスを使うこともポイント。プラグを貫通してプラグが大きく広がることで、がっちりと固定されます。

秋葉原で1本単位で購入するなら、西川電子部品のネジ部がおすすめです。
http://nishikawa.or.tv/map/index.htm

西川電子部品では1本単位のビスに値段が書いていませんが、店員さんに聞けばちゃんと教えてくれます。ちなみに鉛製オールプラグ(サンコーテクノ製)と、それに適合するM3のタッピングビスはそれぞれ10円でした。