ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

C言語とC++言語コミュの省エネプログラミング

  • mixiチェック
  • このエントリーをはてなブックマークに追加
ここ数年のうちにスマホやタブレット端末が爆発的に普及し、とても便利で楽しい時代になりました。
CPUもメモリもどんどん進化し、10数年前には夢物語だった手のひらパソコンが本当に実現してしまいました。

しかしバッテリーの持ちの悪さには常に悩まされます。
特にアンドロイドなんか重いばかりでせっかくのハードの性能を全然生かせておらず、電池を無駄食いしてばかりです。
Windowsは言わずもがな。
ソフト類も最近のものははっきり言ってクソです。大した処理も行わないのになぜこんなに重いのでしょう。
動作が重いということはそれだけ電気を無駄遣いしているということです。

そこで省エネを意識したプログラミングについて議論したいと思ってスレを立てさせて頂きました。
このご時世ですからモバイル系のみならずデスクトップにおいても省エネなソフトを作ることに大きな意味があります。
また、省エネは無駄な処理を行わないということなので動作も速くなります。

まずは私が思いつくものをいくつか挙げておきます。

■開発環境・クラスライブラリ等の選択
・.NET Framew○rkみたいなオーバーヘッドの大きいものを使わない(C#なんかは論外)
・C++ではなくCを使用する(コンストラクタ/デストラクタによるオーバーヘッド軽減)
・ラッパークラスは使わずWinAPIやX Window Systemを直接叩く
・必要に応じてインラインアセンブラが使えるようにそれに対応した処理系を用いる

■コンパイル・リンク
・余計なライブラリをリンクしないようにしてコードを短く抑える
・コンパイルオプションでは速度を最適化する
・必要なければx64ではなくx86向けにする

■メモリ管理
・情報あたりの電荷量が少ないほど有利
・消費電力はメインメモリのDRAMが最も多く、次にキャッシュのSRAM、一番少ないのがレジスタ
・頻繁に書き換える情報はレジスタ変数に格納
・malloc/freeやnew/deleteではなくHeapAlloc/HeapFreeやVirtualAlloc/VirtualFree系を使う
・メモリの確保と呼び出しの頻度はなるべく少なくする(CStringなんかは論外)
・1kBまでの情報なら自動変数を用いる(CPU内部のキャッシュに割り当てられる確率が高い)
・変数のサイズに応じてbyteとwordとlongを使い分ける
・使いもしないメモリ領域をいつまでも占有しない(DRAMはリフレッシュを行うので情報を保持するだけで電力を消費する)

■関数関連
・fastcallは積極的にレジスタを用いるので有利
・過度の関数ネストやスタックを無駄に消費する再帰は避ける
・引数はなるべく少なくする(構造体でまとめると良い)

■演算関連
・ループ内で繰り返し処理を行う場合配列よりポインタのほうが有利
・BOOL型の反転はa^=1;で1ビットだけ動かす(TRUEかFALSEの何れかであることが保証されてる場合のみ)
・浮動小数点はなるべく使わない(当たり前だが64ビット型は32ビット型より不利)
・unsignedはわずかに不利

■制御構文
・ループの条件式に複雑な処理を書かない
・? : で間に合うところはifではなくそれを使う(ifの機械語コードはgotoに似ていて煩雑)
・whileやforの条件式の結果はEAXレジスタに格納されるので必要ならインラインアセンブラで抽出できる

■スレッド・プロセス
・マルチスレッドはなるべく使わない(タイマーよりもスレッドを使ったほうが有利な場合もある)
・スレッドやプロセスの優先順位設定を上手に行う

■インターフェース
・GUIが必要ないものはCUIで
・オーナードロー等を行う場合無駄にカッコいいUIが本当に必要かよく考える(MS OfficeにVC++、お前のことだ)
・メッセージループにGetMessage、TranslateMessage、DispatchMessage以外のものを書かない


これだけのことに気をつけてどの程度省エネに寄与するかわかりませんが、Atom機のような省エネマシンで軽快に動作するようになることは間違いありません。
実用ソフトがみんな省エネプログラミングで作られていたらわざわざオーバースペックのPCを購入する必要がなくなり、一昔前のPCでもLinuxの軽いディストリビューションとWineの組み合わせで2時間以上の連続稼動を実現できそうです。

最近のソフトはみんな開発時の省力化ばかり重視していてパフォーマンスは二の次にされてます。
よくCPUの性能が上がってるから問題ないなどとのたまってる人がいますが、それは裏を返せばPCがどんどん高性能化しているのにエンドユーザーがいつまでもその恩恵を受けられない理由そのものです。

もし現代のソフトやOSがマイコン時代並にパフォーマンスや省エネ性能を重視して作られていたらワードは一瞬で起動し、Android端末は10時間連続でネットに繋ぐことが可能になったのではないでしょうか。

CやC++という高級言語を使う場合でもアセンブラ、デジタル回路、半導体素子、無機化学の知識があれば大いに役立ちます。

コメント(71)

そもそも省エネを考えるなら、Windowsじゃなく、もっと省エネなOSで動かすプログラムを作ることを考えた方がよさそうな気が…。あせあせ
>>[32]

Windows並に高機能でしかも省エネなOSを探すのは難しいです。
UbuntuはLinuxなのでWindowsよりはマシだと思いますが「見ためのカッコ良さ」を重視した結果重さはWindows並になっていると感じました。
きっと消費電力も同じでしょう。
アンドロイドも非効率な実装により電力を無駄食いしています。

高機能でWineが使えて省エネなディストリビューションというとFedoraあたりでしょうかね。
この場合Wineを噛ませることで重くなる点も考慮しなければいけませんが。

アンドロイドが他のディストリビューションと同じくインターフェースがもっと低レベルな位置にあり、開発者にそのレベルへのアクセスを認めていたらもっと省エネなOSになったでしょうし省エネプログラミングもやりやすくなったでしょう。
そもそも所有者を最初からrootとして認めていないところがちょっと引っかかります。
>>[33]
OSについて省電力を追求しないのであれば、上で走るアプリだけ省電力にしたところで、システム全体について節約できる電力の比率として考えると、あえて省電力になる方向へ追求することに意味があるとも思えません。

もちろん、OSから考えて省電力に設計する組み込み系や、それ自体が大きな資源を消費するようなプログラムであれば話は違ってくるでしょうし、日向新太さんが個人的に開発するものにどんな信念を持っていようとそれは自由なのもまた間違いないですが。

あと、通信とかハードディスクとか、そういう外部資源とのアクセスを最適化するほうが、全体の(速度・電力)パフォーマンス向上には効いてきそうな気もします(CPUやメモリより格段に遅いわけですから)。
>>[31]
ワットチェッカーですか。。。
測定機材あるという話だったから、メモリハイコーダでも持ち出してくるのかと思っていました。

ワットチェッカーでは、UPSの容量検討ぐらいにしか使えないのでは?
それを使ってどのような測定結果が出ようとも、そこからどうやってプログラムを最適化するつもりなのですか?
アプリを組んでると、付随する画像をフルカラーから16色にするだけでかなり速くなったりします。付随データの減量は有効におもえます。

なお、Googleによれば、
for(〜;〜;i++){〜;}
よりは
for(〜;〜;++i){〜;}
のほうが速いそうです。
>>[34]

言い方が悪かったですね…
通常使用では一般ユーザー権限でも必要に応じてroot権限でログインできたらいいと思うのです。
でも現存するアンドロイド端末の多くはアップルでいう脱獄みたいなことをしないとrootを取得出来ませんよね。
しかもそれをするとメーカーの保証を受けられなくなったり文鎮化することもあります。
端末の所有者なのに原則rootでログイン出来ないのが納得いかないわけです。
>>[35]

それは確かにそうです。
WindowsもアンドロイドもOS自体が重いためひとつのアプリケーションが省エネを頑張ったところで有意な効果が出るのかというのは疑問符がつきます。
しかし省エネ以外にも多大なメリットがありますし、省エネプログラミングを布教してそのようなアプリケーションやOSが増えることになれば体感できるほどの省エネに繋がります。

私のプログラミングスタイルは結果的に省エネプログラミングに準拠していますが、目的は消費電力の低減ではなくターゲットの幅を広く保つことです。
例えば実行時に「なんとかフレームワークがありません」と出てきたりしたら嫌ですよね。
だから.NETもVBもC#もMFCも大嫌いで、私がプログラミングで使わないだけでなく起動時にランタイムのインストールを強要するソフトは糞だと思ってます。


最近のPCはHDDではなくSSDなのでページングファイルで消費電力が減ることもありそうです。
サイズが大きくてあまり書き換えず長時間保持する必要のあるデータはWriteFile/ReadFileで明示的に不揮発性デバイスに落としたほうがいいかもしれません。
プロセスが強制終了したらゴミファイルが残るとか、書き換え回数有限のフラッシュメモリをこんなことに使うなという批判がありそうですが。
>>[41]
> 私のプログラミングスタイルは結果的に省エネプログラミングに準拠していますが、
> 目的は消費電力の低減ではなくターゲットの幅を広く保つことです。

おいおい、
そんなこと言い出したら、もはや何の話をしているのか分らなくなりますよ。
>>[41]

まあ全否定することもないかなと眺めていたのですが、一つ一つの“省エネスタイル”を“省エネ”の物差しで測って実際どの程度の意味があるのか、或いは“省エネ”という物差し以外を含めて損得勘定を考えた時に、これは一般的にも有効かもしれないというスタイルが、どのくらい残るのか、吟味してみるのは悪いことではないでしょうね。

個人的には、挙げられているスタイルはいずれもシステム全体から見た“省エネ”にはならないと思いますが。どれも誤差の範囲にすらならないただの自己満足だと思います。特に、

> ・使いもしないメモリ領域をいつまでも占有しない(DRAMはリフレッシュを行うので情報を保持するだけで電力を消費する)

ハードウェア的に、アプリが使っていないメモリ領域の電源を部分的に切ることが出来る、なんていう器用なシステムは見たことがありません。

# でももしかすると、これは将来の大容量メモリのシステムでは意味がある省電力技術かもしれませんね 笑)
一石二鳥という言葉がありますが、複数のメリットがあるからこそ少々コストをかけてでもやる意味があるのです。
効率のよいコードが消費電力の低減に繋がるという予測は熱力学第二法則によって裏付けられており確実だと確信してますが、どの程度減るかというのはやってみないとわかりません。
再現性を高めるためバックグラウンドのプロセスを極力止めた上で検証してみますが、なにしろWindowsの正常動作に必要なバックグラウンドプロセスは数が多いので侮れませんね。

やり方は同じ様な処理を延々と繰り返すプログラムを作成し、実行にかかった時間とループ回数を計測しながらワットチェッカーで積算していきます。
20分も掛ければ良いでしょう。
これで20分間に何回繰り返せたか、その間どれだけの電力を消費したか、1回あたり何ワット消費したかがわかります。

順番としてはまずブランクとして何も動かしてない状態で20分測定、その次に非効率20分、省エネ20分を測定してからブランクを差し引きます。
あとはループ回数で割れば処理一回あたりで消費した電力がわかるはずです。
>>[44]

> 熱力学第二法則によって裏付けられており

この法則は例えば、

クラウジウスの法則
低温の熱源から高温の熱源に正の熱を移す際に、他に何の変化もおこさないようにすることはできない。

のように表現されますが(wikipedia)、エントロピー増大則のように言われることもありますし、平たく言えば“永久機関は実現できない”という法則ですが、それと“省エネプログラミング”なるものと、一体どういう関係があって、更にこの法則によって一体何が裏付けられているというのでしょう?

なんだかよく分かりません。
>>[45]

情報はエネルギーの化身で、不可逆的な演算は情報の消去を伴うのでエネルギーを熱の形で捨てることになります。
(論理反転は可逆的ですが戻す処理をしない限りエネルギーを捨てることには変わりありません。)

例えば

mov EAX, 10
add EAX, 5

このアセンブラコードを実行するとEAXには15が格納されますが、add命令が実行される時に情報の消去を伴うので15という結果からは元の数字が10+5だったのか7+8だったかというのはわかりません。
つまり不可逆的な演算だと言えます。
情報量が減ることはエントロピーの減少を意味し、それ以上のエントロピー増大(熱の発生)をもたらします。
これがCPUの排熱の主たる発生源であり、考え事をした時に出る知恵熱も同様の原理で発生します。

これは情報の消去回数を減らせば省エネに繋がるということの裏付けです。
メモリにしてもレジスタにしても書き込んだ情報はいつか消さなければなりません。
無駄な演算をさせればそれだけ情報の消去回数は増えますよね。
>>[46]

それが nop 命令だったとしても、電気は食いますよ。
>>[46]

mov EAX, 10 は発熱しないとでも?

CPUの熱は、電流が流れることによるジュール熱でしょ
CPU→Xeon L5640×2個、メモリ→4GBx8枚のうちのマシンで消費電力を測ってみました。

・通常使用時(CPU利用率2.5〜3%。AAC再生しつつテキスト主体のサイトを見る)
CPU→10〜11W
メモリ→3.38〜3.44W

・YoutubeでH.264な1080/30pの動画再生(CPU利用率7〜10%。GPU支援なし)
CPU→22〜30W、重いシーンだと瞬間的に40Wくらい
メモリ→最大4.37W

M/Bのセンサの値なので誤差はあると思います。
おおよそ一般的な使い方で、最も負荷が高いと思われる動画再生ですらこの程度ですから、低負荷のソフトで“省エネ指向”プログラミングをしたところで効果は殆どないと思います。
”塵積も”という向きもあるでしょうが、省エネ指向で犠牲となった生産性のリカバーに使われるエネルギー、要は開発期間の長期化の分で消費する電力を回収出来るとは到底思えません。

モバイル向けにあらゆる犠牲を払ってでも省エネ化を進めるというなら分からんでもありませんが、それでも犠牲に見あうだけの効果があるとは思えません(自分ならソフトの機能を削り、浮いた資源でより省エネな部品を使ったり電池を増量しますね。結果的にコードは少なくなってるので、究極の省エネプログラミングですかね。)

省エネ指向実証のためPCを1時間ぶん回すのに使った電力を、省エネ指向で節約出来た電力で取り戻すには一体どれだけの時間が掛かるんでしょうか。

# Intelの次期CPUは電力制御の粒度が細かくなるようなので、それで全てが吹き飛んでしまう気もします。
恥ずかしながらリーク電流を忘れてました。

最近のCPUは高密度高集積化が進み、トンネル効果で漏れる電流がかなり大きいです。
なので消去時の発熱を「排熱の主たる発生源」と言ったのは不適切だったかもしれません。

/*
こういうマイコンであればトンネル効果は無視でき、消去が支配的だと考えられる。
http://akizukidenshi.com/catalog/g/gI-00252/
*/
>>[49]

もともとEAXにあった内容を破壊するので当然発熱します。
熱の発生機構はジュール熱ですが、情報理論的に説明すると局所的なエントロピー減少の代償としてそれ以上のエントロピーが発生したと言えます。
>>[52]
そういうことなら、一定時間内に処理する情報量が多ければ多いほど発生する熱量は増えますよね?
つまり、私が最初>>[10]に言ったとおり、「省エネ == 動作が速い」にはならないですよね?
>>[50]

貴重なデータありがとうございます。
メモリの消費電力があまり変化しないあたり、>>43を反映していますね…

これはますます省エネプログラミングの意義が問われる結果だなと感じてます。
しかしそれでもやっぱり副次的なメリットもある以上、意義はあると思ってます。
ちょうどCO2の削減が温暖化防止にほとんど意味がなくても資源の節約に役立つのと同じようなものです。

すべてのアプリケーションはモバイルで使われる可能性があります。
私の専門は化学ですので分子軌道計算みたいな重いものをモバイルで使ったりしてます。
それからモバイル機の多くはCPUやメモリの性能を低くすることでバッテリー持ち時間を伸ばしたり軽量化して可搬性を高めているので、効率の悪いプログラムを走らせると不必要に重くなります。
私としてはやっぱり低性能なモバイルAtom機で使われることを想定してプログラムを書いてほしいです。


まとめると省エネプログラミングには次の2つの効果が期待できることになります。

・基礎代謝の高いPC(Core i7など)での消費電力が僅かに減る
・基礎代謝の低いPC(Atomなど)でも快適に使える

前者はどの程度効果があるかちょっと怪しいですが、後者はかなり意味があると思います。
お金があれば高性能で軽くて電池がよく持つPCを買えるでしょうが、私は学生なのでそんないいものは買えません。
1コアAtomでSSD 40GB、DRAM 2GBの環境でも快適に使えるように工夫してくれると助かります。
同じことを思ってる人は全世界にたくさんいるでしょう。

発展途上国では未だに昔のセレロンが現役だと思われますし、メモリが256MBとかHDDが20GBというのも決して珍しくないと思います。
このことから省エネプログラミングでネットワーク関連アプリケーションを作ることは情報格差を減らし、世界平和にも貢献できるのではないでしょうか。
ソフトによる無駄遣いといえば個人的にはFlashプレイヤーがかなり酷いと思っています。
バージョンアップするごとに見た目に対して明らかにCPUの負荷が増大しています。
同じようなコンテンツでも、古い作品だと動作は軽いですね。
という事は、Flashの開発環境が劣悪になっているのだろうか?
動作効率の最適化と逆行しているFlashプレイヤーのあり方の改善で相当変わりそうですね。

突然の横槍失礼しました;;
なんですかこのトピックは。
冗談か釣りで書いているのですか?
冗談にしては、あまり面白くもないですが。
>>1が長々と書いてあるにしては、有益なことがほとんど見当たらないですね。

あえてネタにマジレスすると、たとえば、

> C++ではなくCを使用する(コンストラクタ/デストラクタによるオーバーヘッド軽減)

これをはじめとした、>>1に書いてあるほとんどのことは、コンパイラが適切に最適化してくれますから、プログラマが気にすることではありません。

たとえば、ソートしたいとき、CのqsortよりC++のstd::sortの方がインライン展開してくれる可能性も期待できるから、C++でテンプレートライブラリを使用した方が、無駄なコードが減らせる可能性もあるでしょう。

省エネプログラミングが有効なのは、組み込み分野くらいでしょう。それこそ、OSから自作する勢いで。私も嫌いじゃないので、ワンチップマイコンのファームウェアをアセンブラで書いたりしますけどね。

リッチなOS用ソフト開発なら、私はむしろ「富豪的プログラミング」を支持しますね。
まあ省エネ目指すことは別に悪くないと思うんで、要はそうするために必要となる手間とのバランスと、そもそも省エネを実現するための手段の実効性をきちんと評価することに尽きると思うわけです。

0で挙げられているようなことは、私を含めて複数の人が(わざわざやってみるまでもなく)まず効果無いだろうと見ているようです。効果が見込めないにも関わらずその方針を適用するには多大な労力を必要とするのが明らかなので、これじゃダメだろうなということになるわけです。

では、どういう方針でのぞめば、無理なく、ある程度の省エネが期待できるのか。
思い込みで方針を決めるのではなく、まずはそれを探ってみる。
進むべき道はそっちじゃありませんかね。

60番のコメントでそらみみさんが書かれているように qsort よりは std::sort の方が速いのは確からしく、一概にC++の方がCより効率が悪いとは言えないのですが、私の経験ではマクロを使って無理矢理手製インライン展開にした方がテンプレートやinline関数にするよりは速いみたいな話もありましたし、stdioに比べるとiostreamは現時点では性能的にはかなり負けているみたい、という話も聞こえてきます。

というわけで、せっかくのトピなので、こうすると速い=とりあえず省エネ、これは遅い=避けた方が良い、みたいなテクニックやノウハウを叩かれ台に載せて、やいのやいの議論する、なんていうの、どうでしょうね。

その方が、トピ主さんにも、読んでる人にも、勉強になるでしょ?
トピ主様。

貴方の作られた開発物はこれから一生貴方が独りで面倒を見て行くのでしょうか?
不具合対応は勿論、バージョンアップ、別プラットフォームへの横展開、、その辺上手く対処して行けるのでしょうか?
すみません。レポートと学会準備に追われてました。

>>62
一人で面倒を見るものもあれば面倒を見切れずオープンソース化するものもあるかもしれません。
何度も初めから書き直しているものもあります。
別プラットフォームへの展開はアンドロイドとiPhoneだけが問題で、それ以外はWineとの相性の良さを保てば問題ありません。

今まで作ったソフトで一番長く続いているのは10年以上なり、最近もバージョンアップを行いました。
配布サイズはたった20kB程度、省エネプログラミングのお手本とも言えるソフトです。
>>[63]
Wineでは省エネ性能が少し落ちるのでは?
少し落ちるでしょうが、私の作ったソフトに限って言えばわざわざ作りなおしてでもLinuxにネイティブで対応させる意味は無いです。
それにWineはエミュレーターやVMのたぐいではなくWinAPIをLinuxに移植したものに過ぎませんので省エネ性能がWindows環境と比べて大きく落ちるとは考えにくいです。

.NETなんかを使わずWinAPIだけで動作する省エネプログラムはWineとの相性も抜群だと思いますよ。
>>[65]
そのソフトはどんな内容のソフトなんですか?
ただ単純に20KBのプログラムを書くのは簡単ですよ。

それと最初>>[0]に、C++のオーバーヘッドすら問題視し、X Window SystemのAPIを直接叩けと言っていたあなたが、なぜWineを許容するんですか?
>>66
画像とMIDIの入ったジョークソフトです。
これらのリソース込で20KBです。(リソースなしだと5KB程度)

他にネットからファイルをダウンロードするソフトも作っていて、これは少々複雑ですが重いリソースはないので40kB程度です。

//ものをここに晒すべきか迷うなぁ

Wineを許容するのは今のところLinuxはメインターゲットではなく、あくまでおまけ的対応としか見ていないからです。
本格的に対応するとなればネイティブにX Windows Systemを叩くことも検討します。
いま,使わないDRAMチップの電源を切ったり,使わないDRAMチップだけリフレッシュをOFFするような仕組みのコンピュータって(滅多に)無いように思います。
そういう意味ではDRA容量を節約してもたいして意味がなさげ。DRAMの読み書き回数削減に起因する省電力は期待できるでしょうけど。
> 画像とMIDIの入ったジョークソフトです

それを起動しないことこそが真の省エネですね
見過ごしてしまっていましたが、[61]に藤田さんが書いたことに尽きる気がしますねえ。
例えば、Javaなんて重くって、、と思っている方は多いと思います。
確かにAndroidでは僅かなメモリしかなくて、GCしまくりです。しかし、それでも無駄にメモリの確保と解放を繰り返さないように、インスタンスを何度も使い回す方法を知っているJavaのプロ(私のことです^_^)が作ると、気にならない程度の性能を出せたりするんです。

安易な結論の出し方はするべきでないと思いますよ。

ログインすると、残り40件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

C言語とC++言語 更新情報

C言語とC++言語のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング