ソフトウェアエンジニア現役続行

雑多なことを綴ります

関数のスタック使用量を計算する方法

POSIXが使える環境でC言語のプログラムを書いていて、特定の関数が使用するスタックの量を調べる必要がありました。

別スレッドを生成してその特定の関数を実行させることで、スタックの使用量を調べることができます。あらかじめ別スレッドのためのスタック領域用に明示的にメモリを確保しておき、マジックナンバーで充たしておきます。そしてpthread_setstack()によって別スレッドがそのスタック領域を使用するようにして、別スレッドで関数を実行させます。実行後にスタック領域のマジックナンバーを見ることで、関数が使用したスタックの量が分かります。

ソースを読んだほうが分かりやすいかも知れません。以下では function() という関数が使用したスタックの量を標準出力しています。


// コンパイル方法:gcc -Wall -Werror -std=gnu99 -o check_used_stack check_used_stack.c -lpthread

#include
#include
#include
#include

#define STACK_SIZE (1024 * 1024 * 10) // 10 MB
#define MAGIC_NUMBER 'Z'

static void *function(void *arg);
static void check_stack(char *adr);

int main(void)
{
 // 子スレッド用にスタック領域を確保して、MAGIC_NUMBERで塗りつぶす
 char *stack_adr = (char *) malloc(STACK_SIZE);
 for (int i = 0; i < STACK_SIZE; i++) {
  stack_adr[i] = MAGIC_NUMBER;
 }

 // 子スレッドに確保したスタック領域を使用させる
 pthread_attr_t thread_attr;
 pthread_attr_init(&thread_attr);
 pthread_attr_setstack(&thread_attr, (void *) stack_adr, STACK_SIZE);

 // 子スレッドを生成
 pthread_t thread;
 pthread_create(&thread, &thread_attr, &function, NULL);

 // 子スレッドが終了するのを待つ
 pthread_join(thread, NULL);

 // 子スレッドが消費したスタックサイズを出力
 check_stack(stack_adr);

 // mallocしたスタック領域を返却
 free(stack_adr);

 return 0;
}

static void *function(void *arg)
{
 char buff[1024 * 100]; // 100KB
 memset(buff, MAGIC_NUMBER + 1, sizeof buff);
 return NULL;
}

static void check_stack(char *adr)
{
 int i;
 for (i = 0; i < STACK_SIZE; i++) {
  if (adr[i] != MAGIC_NUMBER) {
   break;
  }
 }
 printf("Used %d byte\n", STACK_SIZE - i);
}

僕の環境で実行すると「Used 106128 byte」となりました。buffに100KB割り当てたのが効いてます。