ちょっとTea Time!? switch文 vs if文 ? 2020.5.27
Integration Unitを検討している中で、小容量のPICも接続できるようにプログラムを作成しているが、
一番問題なのは、やはり容量です。18Pinの小さいPICのPIC16F1827では4kWしかありません。それでも、
最初の頃につかっていたPIC16F819(2kW)に比べれば倍はあるわけですが、28PinのPIC16F1938(16kW)や
PIC18F26K20(32kW)に比べるとかなり小さいです。
容量に余裕のあるPICだと、プログラムをさほど気にせず(いや、気にしろよ!)、だらだらとまでは行きませんが(笑、
書くことができます。反面、小容量のものだとできるだけ短くなるように、冗長な部分があったら1つのサブルーチンにまとめたり
と気を使います。でも、コードを短くすることに気を使いすぎて、処理時間があまりにも長くなるようだと困ります。
そこで、前から気になっていたのですがswitch文とif文ではどちらが早いのか?というのを調べてみることに。
以前、どこかの本ではswitchの方が処理が長いと見たことがあるのですが、自分のつかっているコンパイラ(CCS社)
で調べてみることにしました。
比較してみたのは、下記のような例です。
まず生成されるコードについては若干switch文の方が長いです。でも、あまり大きな差ではありません。
反面、実行速度はswitch文の方が予想に反して早いです。
この原因はアセンブラをみたら明らかでした。
if文では1つの文を淡々とこなしていますが(当然のことながら、そのように書いている)、switch文では
最初に条件分岐のルーチンがあり、サブルーチンコールは別に分けられています。すなわち、一文をすべて
終わるまで次にいけないif文にくらべると、分岐処理だけをちゃっちゃとこなすswitchの方が早いということです。
なるほど、これならSwitch文はプログラムとしても見やすいですから、どんどん使えばいいですね。
switch文の例 | if文の例 |
sub(int i){} test(int i){ switch(i){ case 0:sub(i);break; case 1:sub(i);break; case 2:sub(i);break; case 3:sub(i);break; case 4:sub(i);break; case 5:sub(i);break; case 6:sub(i);break; case 7:sub(i);break; case 8:sub(i);break; case 9:sub(i);break; case 10:sub(i);break; default:break; } } main() { test(10); } |
sub(int i){} test(int i){ if(i==0) sub(i); if(i==1) sub(i); if(i==2) sub(i); if(i==3) sub(i); if(i==4) sub(i); if(i==5) sub(i); if(i==6) sub(i); if(i==7) sub(i); if(i==8) sub(i); if(i==9) sub(i); if(i==10) sub(i); } main() { test(10); } |
コード(test関数のみ) 83バイト |
コード(test関数のみ) 78バイト |
実行時間(64MHz) 約2.6us |
実行時間(64MHz) 約3.5us |
むしろwrite_eeprom() が問題だった
パラメータを変更したら、それをEEPROMに記憶する関数としてCCSにはwrite_eeprom(int
adrs, data) が準備されています。
最初は、単なるサブルーチンコールで実体はライブラリにあるかと思っていましたが、実際にはそうではなく、色々な処理が
インラインに展開されていることがわかりました。そのため、write_eepromの関数を使うと1回あたり42バイト(PIC18Fの場合)も
消費することが判明。こりゃデカイ!実際にアセンブラをみてみると、なにやら色々な処理がインライン展開されています。
中身まではよくわかりませんが・・・
write_eeprom(int adrs,data) | test(int adrs,data) | |
コード長 (PIC18F) |
42バイト | 10バイト |
といことがわかったので、write_eeprom関数については別の名前のサブルーチンで置き換えて、そこから_write_eepromを
呼び出すようにすればwrite_eeprom関数の記述はプログラムの中で1個だけになりますから、相当のコードの節約になります。
なんせ、いまままでwrite_eeprom関数はいたるところにありますから。同様にread_eeprom関数も22バイト消費することが
わかりました。この関数はあまり多くつかいませんが、それでもwrite_eepromと同様の処理をすればプログラムの節約に
なりそうです。
昔のプログラムは凄かったんだな〜と回顧。
その昔、CP/M-80をつかっていたことに大学の演習課題もあり、FORTRANを使ったこともありますが、
当時のコンパイラとかってものすごくコンパクトだったな〜と感慨深くなります。なんせコンパイラが
28kバイトしかありません。もちろん、アセンブラやリンカー、ライブラリーは別ですが、それでも総計100kバイト程度
です。いまWINDOWSでつかっているCCS社のCコンパイラはコマンドラインの軽いものですが、それでも15Mバイトあります。
昔のコンパイラに比べると約500倍の容量です。まあ、今と昔ではPCのメモリー容量やCPU速度も1000倍以上の差はあるでしょうから
いいのかもしれません・・・・。コンピュータの資源の無駄遣いのような気もしますが、人間という資源を節約する(開発を効率化する)
という点では合理的なのでしょう。
CP/M-80のコンパイラは軽かったです。
(おしまい)