ドナドナされるプログラマのメモ

Windows用アプリのプログラミングメモ

_alloca, _malloca関数について

マイクロソフトのテクニカルノートを読んでいたら、以下のような記述を発見。

各マクロの実装では、_alloca() 関数を使用して、ヒープではなくスタックからメモリを割り当てます。 スタックからメモリを割り当てると、メモリをヒープに割り当てるよりもはるかに高速であり、関数が終了したときにメモリが自動的に解放されます。 」

learn.microsoft.com

具体的にはどのくらい速度が違うんだろう?ということで試しに測ることにした。比較には、malloc()やnew, _alloca()に加え_malloca()を用いた。_malloca()は割り当てようとするメモリ量によってはヒープから確保する(malloc()等と同じ動作をする)らしい。以下、_alloca()および_malloca()のドキュメントへのリンク。

learn.microsoft.com

learn.microsoft.com

_alloca()で確保したメモリは関数から抜ける際に自動開放されるらしいので、メモリを確保するだけの関数を用意し、それを複数回呼び出して所要時間を比べた。CPUクロックのブーストなどの影響を最低限とするため、malloc->new->_alloca->_malloca->malloc->new...と測定対象を順番に切り替える実装とした。ただし、1呼び出しごとに切り替えると時間計測関連の処理時間が無視できない気がしたので、測定対象はloop回ずつ実行してから切り替えるように実装し、測定対象切り替えをtrialセット繰り返すようにした。コードのイメージは文末に記載しているので、イメージの把握はそちらからどうぞ。

こうしてできたソフトがこちら。

github.com

これによる計測結果の例がこちら。

1000バイト確保時。_mallocaはスタックからメモリ確保している。_malloca, _alloca共に速い。

なかなかの速度差である。他の条件も含めて表にまとめたのがこちら。黄色くハッチングしているのは、その前後で値が大きく変化している箇所。例えば、_mallocaについてデータサイズ1008と1009では時間が6倍ほど変化している。同様に16368と16369では3倍ほど変化している。

データサイズ malloc new _alloca _malloca
1008 0.260064 0.268249 0.03295 0.042054
1009 0.253565 0.260804 0.033637 0.267588
16368 0.253919 0.26037 0.033699 0.269342
16369 0.249189 0.258109 0.032459 0.834997
16384 0.252267 0.258637 0.032342 0.824545
16385 0.774677 0.800355 0.03344 0.802161
1024000 0.808438 0.820124 0.032369 0.830337
1025000 - - Stack Overflow -

 

_mallocaの速度が1008バイト付近で変化しているのは、サイズが_ALLOCA_S_THRESHOLDを超えたからだろう。一方で16kBでの変化はよくわからない。16384、すなわち2^14が絡んでいるようには見えるが、なぜだろう?L1データキャッシュサイズ:32kBと絡んでいたりするんだろうか?アルゴリズム上、2^n単位でメモリを確保していて、16384を超えるとL1データキャッシュ全部が必要となってしまい、他のデータのキャッシュと取り合いになってL2データキャッシュに溢れちゃうとか。ちょっとおもしろいデータだった。

 

なおテストコードは概略こんなかんじ。

gist.github.com