2014年12月4日 星期四

作業系統之前的程式 for stm32f4discovery (11) - 找出 stm32f4 simple scheme 記憶體使用量

1st edition: 20090417, only the url link.
2nd edition: 20141204, 計算記憶體用量

我想找出 stm32f4 simple scheme (後文簡稱為 sss) 的記憶體用量, sss 沒有使用類似 malloc 的動態記憶體配置, 我們從三個方面來估算其使用的記憶體。

  1. 執行檔案大小
  2. bss,
  3. stack

stack

怎麼算出使用的 stack 容量有點難倒我, 畢竟 stack 的用量會和程式的執行流程有關, 就算同一支程式, 執行的流程不同, 也會得到不同的 stack 用量。

不記得是怎麼因為 __builtin_return_address 而查到這篇。
http://blog.linux.org.tw/~jserv/archives/001870.html

不過我正好需要這個功能。我打算讓 gcc 在離開 function 前插入一段程式碼, 紀錄 stack reigster, 把穿梭在這些 function 裡頭的 stack register 最小值記下, 而 stack register 初使值是 0x1000fff0, 兩者的差就是答案。說來簡單, 實作上愈到不少問題, 誰叫我要用 c++ 呢? 又多折磨我一點點。

在 void __cyg_profile_func_exit(void *this_func, void *call_site) 讀取 sp 的值。注意: 這兩個 function 要放在 extern "C" 裡頭。

myur.cpp
  1 /*
  2  * simple scheme on stm32F4XX
  3  *
  4  *
  5  */
  6 
  7 
489 extern "C"
490 {
491 
492 #ifdef SP_STATUS
493 
494 
495 u32 sp_val=0xffffffff;
496 u32 tmp_sp; 
497 
498 // ref: http://blog.linux.org.tw/~jserv/archives/001870.html
499 __attribute__((__no_instrument_function__))
500 void __cyg_profile_func_enter(void *this_func, void *call_site)
501 {
502 
503 }
504 
505 __attribute__((__no_instrument_function__))
506 void __cyg_profile_func_exit(void *this_func, void *call_site)
507 {
508 
509   //tmp_sp =  get_stack_reg();
510 
511   __asm__ volatile (
512             "mov %0, sp\n"
513             : "=&r"(tmp_sp)
514             :
515           );
516   if (tmp_sp < sp_val)
517     sp_val = tmp_sp;
518 }
519 #endif
520 }

另外需要 4.9.1 g++ 才能成功編譯, 4.7, 4.8 皆失敗, 4.9.1 來的正是時候。

descent@debianlinux:uart_echo$ arm-none-eabi-g++ --version
arm-none-eabi-g++ (GCC) 4.9.1
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

g++480.err
1 arm-none-eabi-g++ -fno-exceptions -fno-rtti -g -fno-common -O0 -g -mcpu=cortex-m3 -mthumb -I../inc -DSP_STATUS -finstrument-functions   -c -o myur.o myur.cpp
2 myur.cpp:482:6: error: can't set '__no_instrument_function__' attribute after definition
3  void __cyg_profile_func_enter(void *this_func, void *call_site)
4       ^
5 myur.cpp:488:6: error: can't set '__no_instrument_function__' attribute after definition
6  void __cyg_profile_func_exit(void *this_func, void *call_site)
7       ^
8 make: *** [myur.o] Error 1

L6323, L6367 是反組譯之後可以看到被插入的 function。

arm-none-eabi-objdump -C -d myur.elf
   1 
   2 myur.elf:     file format elf32-littlearm
   3 
   4 
   5 Disassembly of section .text:
   6 
6316 08003ad8 <init_eval()>:
6317  8003ad8: b5b0       push {r4, r5, r7, lr}
6318  8003ada: af00       add r7, sp, #0
6319  8003adc: 4675       mov r5, lr
6320  8003ade: 462b       mov r3, r5
6321  8003ae0: 481c       ldr r0, [pc, #112] ; (8003b54 <init_eval()+0x7c>)
6322  8003ae2: 4619       mov r1, r3
6323  8003ae4: f7fc ffa8  bl 8000a38 <__cyg_profile_func_enter>
6324  8003ae8: 4b1b       ldr r3, [pc, #108] ; (8003b58 <init_eval()+0x80>)
6325  8003aea: 2206       movs r2, #6
6326  8003aec: 701a       strb r2, [r3, #0]
6327  8003aee: 4b1b       ldr r3, [pc, #108] ; (8003b5c <init_eval()+0x84>)
6328  8003af0: 2205       movs r2, #5
6329  8003af2: 701a       strb r2, [r3, #0]
6330  8003af4: 4b1a       ldr r3, [pc, #104] ; (8003b60 <init_eval()+0x88>)
6331  8003af6: 2201       movs r2, #1
6332  8003af8: 701a       strb r2, [r3, #0]
6333  8003afa: 481a       ldr r0, [pc, #104] ; (8003b64 <init_eval()+0x8c>)
6334  8003afc: 491a       ldr r1, [pc, #104] ; (8003b68 <init_eval()+0x90>)
6335  8003afe: f7fd fb0d  bl 800111c <s_strcpy(char*, char const*)>
6336  8003b02: 4b1a       ldr r3, [pc, #104] ; (8003b6c <init_eval()+0x94>)
6337  8003b04: 2201       movs r2, #1
6338  8003b06: 701a       strb r2, [r3, #0]
6339  8003b08: 4b19       ldr r3, [pc, #100] ; (8003b70 <init_eval()+0x98>)
6340  8003b0a: 2201       movs r2, #1
6341  8003b0c: 701a       strb r2, [r3, #0]
6342  8003b0e: 4819       ldr r0, [pc, #100] ; (8003b74 <init_eval()+0x9c>)
6343  8003b10: 4919       ldr r1, [pc, #100] ; (8003b78 <init_eval()+0xa0>)
6344  8003b12: f7fd fb03  bl 800111c <s_strcpy(char*, char const*)>
6345  8003b16: 4b19       ldr r3, [pc, #100] ; (8003b7c <init_eval()+0xa4>)
6346  8003b18: 2201       movs r2, #1
6347  8003b1a: 701a       strb r2, [r3, #0]
6348  8003b1c: 4818       ldr r0, [pc, #96] ; (8003b80 <init_eval()+0xa8>)
6349  8003b1e: 4919       ldr r1, [pc, #100] ; (8003b84 <init_eval()+0xac>)
6350  8003b20: f7fd fafc  bl 800111c <s_strcpy(char*, char const*)>
6351  8003b24: 4b18       ldr r3, [pc, #96] ; (8003b88 <init_eval()+0xb0>)
6352  8003b26: 2201       movs r2, #1
6353  8003b28: 701a       strb r2, [r3, #0]
6354  8003b2a: 4818       ldr r0, [pc, #96] ; (8003b8c <init_eval()+0xb4>)
6355  8003b2c: 4918       ldr r1, [pc, #96] ; (8003b90 <init_eval()+0xb8>)
6356  8003b2e: f7fd faf5  bl 800111c <s_strcpy(char*, char const*)>
6357  8003b32: 4b18       ldr r3, [pc, #96] ; (8003b94 <init_eval()+0xbc>)
6358  8003b34: 2201       movs r2, #1
6359  8003b36: 701a       strb r2, [r3, #0]
6360  8003b38: 4817       ldr r0, [pc, #92] ; (8003b98 <init_eval()+0xc0>)
6361  8003b3a: 4918       ldr r1, [pc, #96] ; (8003b9c <init_eval()+0xc4>)
6362  8003b3c: f7fd faee  bl 800111c <s_strcpy(char*, char const*)>
6363  8003b40: 2400       movs r4, #0
6364  8003b42: 462b       mov r3, r5
6365  8003b44: 4803       ldr r0, [pc, #12] ; (8003b54 <init_eval()+0x7c>)
6366  8003b46: 4619       mov r1, r3
6367  8003b48: f7fc ff80  bl 8000a4c <__cyg_profile_func_exit>
6368  8003b4c: 4623       mov r3, r4
6369  8003b4e: 4618       mov r0, r3
6370  8003b50: bdb0       pop {r4, r5, r7, pc}
6371  8003b52: bf00       nop

在我隨意的測試下, sp 是 100052A8。
1000fff0 - 100052A8 = ad48 = 44360 bytes

bss

比找出 stack 用量簡單不少, 用 readelf 讀出來就搞定:

[ 5] .bss NOBITS 20000060 010060 01df74 00 WA 0 0 4

0x01df74 = 122740 bytes

程式檔案本身

為什麼要加上程式檔案本身呢? 畢竟程式檔案本身會被載入記憶體, 不計算它好像說不過去, 但其中的 .data section 還要另外再算, 不過因為不是很大 (34 bytes),

[ 3] .data PROGBITS 20000000 010000 000034 00 WA 0 0 4

就忽略不計。

descent@debianlinux:stm32f4_simple_scheme$ ls -l myur.bin
-rwxr-xr-x 1 descent descent 22948 Nov 18 11:38 myur.bin

合計

44360 + 122740 + 22948 = 190048 bytes

若要再加上 .data section 34 byte, 就是 190048 + 34 = 190082 bytes

就算不加上程式本身, 192k 的記憶體被我用的也差不多了。當然這是因為我那些 pool 佔據了大量的記憶體, 改用 malloc 就會有所改善。

以下影片是我隨機跑了幾個 expression 的測試結果。



ref:
How much stack memory do I need for my ARM® Cortex®-M applications?
提到 gcc 的 --protect_stack, --protect_stack_all option。

1 則留言:

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。