—ฅ/ᐠ. ̫ .ᐟ\ฅ —

My Laboratory

[NVMeVirt] implementation of DFTL #2 : read

WIFI-Aircat 2025. 9. 10. 15:47
🌟 Memory Computing and Computer Architecture Lab
NVMeVirt Weekly Study

- 이전글

 

[NVMeVirt] implementation of DFTL : init & rm

🌟 Memory Computing and Computer Architecture LabNVMeVirt Weekly Seminar- 논문 리뷰로 알아보는 DFTL(참고) Paper Review : DFTL(Demand-based Flash Translation Layer)⏳ DFTL: A Flash Translation Layer Employing Demand-based Selective Caching of

wifiaircat.tistory.com


쓰라린 실패를 맛보며 모든 코드를 폐기하고 다시 시작했으므로

이번에는 차근차근 한 단계씩 신중하게 넘어가기로...

 

- conv_read의 분석

다시는 서버를 reboot하게 하지 않겠다는 단 하나의 생각으로

완전 공들여서 전체적으로 분석하고 나니까 이후 절차가 많이 편해짐...

 

이것을 세미나에서 (그럴 필요 없는데도) 보고했는데

무언의 칭찬을 많이 받은 것 같다는 생각이...  ദി ᷇ᵕ ᷆ )♡

 

- read 흐름 그리기

본격적인 코드 수정에 앞서 read의 전체 흐름도를 그려본다.

논리적으로 빠진 부분이 없는지 확인도 가능하고 생각 정리하는 데에 도움이 된다.

이거 보고하고 세미나에서 칭찬 많이 받았다. ദി ᷇ᵕ ᷆ )♡


- 1차 구현

`get_cmt_ent`에서 miss의 경우 miss control 없이 `get_maptbl_ent`(mapping table에서 가져오기)와

`insert_cmt_ent`(CMT에 새로 넣기)를 바로 붙여서 구현하기로 했다.

static inline struct ppa get_cmt_ent(struct conv_ftl *conv_ftl, uint64_t lpn) {
	struct ppa new_ppa  = { .g.ch = -1 };

	if (!conv_ftl->cmt){
		NVMEV_DEBUG("[DFTL] get_cmt_ent : conv_ftl is NULL\n");
		dump_stack();
		return new_ppa;
	}

	for (int i = 0; i < CMT_SIZE; i++) {
        if (conv_ftl->cmt[i].valid && conv_ftl->cmt[i].lpn == lpn) {
			/* case of cache hit */
			NVMEV_DEBUG("[DFTL] cache hit: lpn=%llu\n", lpn);
			/* victim policy : LRU */
            conv_ftl->cmt[i].last_access = get_current_time();
            return conv_ftl->cmt[i].ppa;
        }
    }
	
	/* case of cache miss */
	NVMEV_DEBUG("[DFTL] cache miss: lpn=%llu\n", lpn);
	new_ppa = get_maptbl_ent(conv_ftl, lpn);
	insert_cmt_ent(conv_ftl, lpn, &new_ppa);
	//new_ppa = miss_control(conv_ftl, lpn);
	
    return new_ppa;
}

위 기본 함수를 `conv_read`에 삽입할 예정

`conv_read` 내에서 기존 Call sites of `get_maptbl_ent`은 `prev_ppa`와 `cur_ppa` 두 부분이 있다.

해당 부분들을 수정한 `get_cmt_ent` 함수로 대체해본다. make가 잘 되면 test로...

 

테스트

insert module 시에 나오는 dmesg를 보면 miss - insert - hit의 흐름이 보인다. 굿 ദി ᷇ᵕ ᷆ )♡


- 2차 구현

: miss control 부분을 마저 구현해서 read 흐름을 완성한다.

이번에는 miss control 함수를 따로 만들지 않고 `get_cmt_ent`에 함

static inline struct ppa get_cmt_ent(struct conv_ftl *conv_ftl, uint64_t lpn) {
	struct ppa new_ppa  = { .g.ch = -1 };
	struct cmt_entry *victim = NULL;
	int victim_index = -1;

	if (!conv_ftl->cmt){
		NVMEV_DEBUG("[DFTL] get_cmt_ent : conv_ftl->cmt is NULL\n");
		dump_stack();
		return new_ppa;
	}

	/* cache hit path */
	for (int i = 0; i < CMT_SIZE; i++) {
        if (conv_ftl->cmt[i].valid && conv_ftl->cmt[i].lpn == lpn) {
			/* case of cache hit */
			NVMEV_DEBUG("[DFTL] cache hit: lpn=%llu\n", lpn);
			/* victim policy : LRU */
            conv_ftl->cmt[i].last_access = get_current_time();
            return conv_ftl->cmt[i].ppa;
        }
    }
	
	/* cache miss path */
	NVMEV_DEBUG("[DFTL] cache miss: lpn=%llu\n", lpn);

	/* site of miss control function*/
	/* is cmt full? */
	if (conv_ftl->cmtsize == CMT_SIZE){
		NVMEV_DEBUG("[DFTL] select_victim_cmt_ent\n");
		victim_index = select_victim_cmt_ent(conv_ftl);
		NVMEV_ASSERT(victim_index >= 0 && victim_index < CMT_SIZE);

		victim = &conv_ftl->cmt[victim_index];

		/* write-back if dirty */
		if (victim->dirty){
			NVMEV_DEBUG("[DFTL] write-back victim: lpn=%llu\n", victim->lpn);
			set_maptbl_ent(conv_ftl, victim->lpn, &victim->ppa);
		}

		/* eviction */
		victim->ppa.ppa = UNMAPPED_PPA;
		victim->dirty = false;
		victim->valid = false;
		conv_ftl->cmtsize--;
	}

	new_ppa = get_maptbl_ent(conv_ftl, lpn);
	insert_cmt_ent(conv_ftl, lpn, &new_ppa);
	
    return new_ppa;
}

 

테스트

insert module 시에 나온 dmesg 흐름은 괜찮아 보인다.

rmmod에서 계속 kernel thread가 -1로 남던 문제도 없다!

 

이후 마운트 없이 진행하는 fio read에서도 괜찮게 나왔다. ၄(cʸ„òᴗóリ၃

`select_victim_cmt_ent`에서 중복되는 커널 로그 부분 삭제하고 끝!


- 기타 체크 포인트

insert module 시 : `conv_write`는 호출되지 않는다. `conv_read`는 호출된다.

mount 시 : `conv_write`가 호출된다. File system meta data 를 쓰기 때문이다.

아직 `conv_write`는 연결하지 않았으므로 DFTL이 안 나오는 게 맞다.


진짜 하나도 순조롭지 않았던 고졸의 DFTL read 경로 구현...

나 정말 신났었군아... *⋆꒰ঌ(⁎ᴗ͈ˬᴗ͈⁎)໒꒱⋆*

 

(부가설명)

함수 이름이 conv_*인 이유는 파일 이름이 conv_ftl이기 때문.

사실 dftl_ftl로 바꿨기 때문에 dftl_*로 바꾸는 게 좋겠지만 그건...


- 3차 구현 : 추가 수정

evaluation 중 발견한 문제로 추가수정 : eval of DFTL에서 후술

	for (i = 0; (i < nr_parts) && (start_lpn <= end_lpn); i++, start_lpn++) {
		conv_ftl = &conv_ftls[start_lpn % nr_parts];
		xfer_size = 0;

		//prev_ppa = get_maptbl_ent(conv_ftl, start_lpn / nr_parts);

		/* normal IO read path */
		for (lpn = start_lpn; lpn <= end_lpn; lpn += nr_parts) {
			uint64_t local_lpn;
			struct ppa cur_ppa;

			local_lpn = lpn / nr_parts;
			if (start_lpn == local_lpn){
				prev_ppa = get_cmt_ent(conv_ftl, start_lpn / nr_parts);
				cur_ppa = prev_ppa;
			} else {
				cur_ppa =get_cmt_ent(conv_ftl, local_lpn)
			}
			//cur_ppa = get_cmt_ent(conv_ftl, local_lpn);
			//cur_ppa = get_maptbl_ent(conv_ftl, local_lpn);

 


 

반응형