참고한 것들
Tip 이전 글
개요
- 어떤 NVMe command 를 날렸을 때, 어떤 함수들이 관여되는지 확인하기 위해 모든 디버그 메세지를 키고 함수 진입 및 탈출마다 커널메세지를 남기도록 설정해 보자.
Debug 로그 출력
- 모든 debugging 로그를 출력해보자.
nvmev.h
에서 아래 메크로를undef
에서define
으로 살리면 된다- 이 상태에서
#undef CONFIG_NVMEV_VERBOSE
#undef CONFIG_NVMEV_DEBUG
#undef CONFIG_NVMEV_DEBUG_VERBOSE
- 요로코롬 바꾸면 된다는 것.
#define CONFIG_NVMEV_VERBOSE
#define CONFIG_NVMEV_DEBUG
#define CONFIG_NVMEV_DEBUG_VERBOSE
Debug 메세지 포맷 변경
- Debug 메세지에 어느 파일의 어느 함수의 어느 줄에서 이 메세지를 출력하는 것인지 formatting 을 바꿔보자.
NVMEV_DEBUG()
, nvmev.h
- 이전
#define NVMEV_DEBUG(string, args...) printk(KERN_INFO "%s: " string, NVMEV_DRV_NAME, ##args)
- 이후
#define NVMEV_DEBUG(string, args...) printk(KERN_INFO "%s{file: '%s', line: %d, func: '%s'}: " string, NVMEV_DRV_NAME, __FILE__, __LINE__, __func__, ##args)
NVMEV_DEBUG_VERBOSE()
, nvmev.h
- 이전
#define NVMEV_DEBUG_VERBOSE(string, args...) printk(KERN_INFO "%s: " string, NVMEV_DRV_NAME, ##args)
- 이후
#define NVMEV_DEBUG_VERBOSE(string, args...) printk(KERN_INFO "%s{file: '%s', line: %d, func: '%s'}: " string, NVMEV_DRV_NAME, __FILE__, __LINE__, __func__, ##args)
함수 진입 / 탈출 문구 출력
- 함수 진입/종료 logging 을 위해서 Instrument Function 을 사용하였다.
- 근데 user mode 에서는 dlfnc.h 를 사용할 수 있지만 kernel mode 에서는 이것을 사용할 수 없기 때문에 고민고민하던중
printk()
의 formatting 중에 function pointer 를 function name 으로 바꿔주는 것 (%ps
) 이 있길래 사용해 보니 잘 돼서 이걸 사용.
- 추가적으로 보기 편하게 하려고 함수 진입/탈출 인덴트도 처리했다.
- …근데 multi-thread 로 돌아가서 좀 이상하게 나오긴 함
debug.c
파일 생성
#include "nvmev.h"
void __cyg_profile_func_enter(void *this_fn, void *call_site) __attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site) __attribute__((no_instrument_function));
int lv = 0;
void __cyg_profile_func_enter(void *this_fn, void *call_site) {
lv++;
char buffer[32];
for (int i = 0; i < lv; i++)
strcat(buffer, " ");
printk(KERN_WARNING "%s: %s +enter{func: '%ps'}", NVMEV_DRV_NAME, buffer, this_fn);
}
void __cyg_profile_func_exit(void *this_fn, void *call_site) {
char buffer[32];
for (int i = 0; i < lv; i++)
strcat(buffer, " ");
printk(KERN_WARNING "%s: %s -exit{func: '%ps'}", NVMEV_DRV_NAME, buffer, this_fn);
lv--;
}
- 그리고 이놈을 사용하기 위해
Kbuild
파일을 좀 수정해 줘야 했다.- 즉, 컴파일 타겟에
debug.c
를 추가하고,-fintrument-functions
옵션을 추가해 줘야 한다.
- 즉, 컴파일 타겟에
ccflags-y += -finstrument-functions
nvmev-y += debug.o
Thread loop
- NVMeVirt 는 하나의 Dispatcher 와 여러 Worker 들이 thread 로 생성돼서 작업을 처리하고
- 각 thread 에서는 무한루프를 돌며 어떤 메세지가 들어왔는지 등을 체크한다.
- 따라서 이 무한루프에 의해 지속적으로 실행되는 함수의 경우에는 logging 을 꺼놔야 한다.
- 제외된 함수들
io.c
:__get_io_worker
io.c
:__get_wallclock
main.c
:nvmev_proc_dbs
pci.c
:nvmev_signal_irq
pci.c
:nvmev_proc_bars
- 이놈들에 대해서는
__attribute__((no_instrument_function))
를 전부 달아 로그를 비활성화하면 된다. - 다만, loop 의 영향을 최소화 하고 최대한 많은 로그를 찍게 하기 위해 제외된 함수들에 대해서는 다음과 같은 처리를 하였다.
- 세 함수(
__get_io_worker
,__get_wallclock
,nvmev_signal_irq
) 들은 Infinite loop 이외에도 사용되고 있어 loop 내에서만 사용할 용도로_muted
wrapper function 을 추가적으로 정의했다. - 두 함수(
nvmev_proc_dbs
,nvmev_proc_bars
) 들은 한번밖에 사용되지 않기 때문에 함수 내부의if
문에 걸리는 부분에만 logging 을 하도록 했다.
- 세 함수(
- 추가적으로… 얘네들도 module init 할때 너무 많은 로그를 찍어서 로깅 비활성화시킴
ssd_init_nand_page
ssd_remove_nand_page
ssd_init_nand_blk
ssd_remove_nand_blk