기존 단순 key-value 방식의 SSD 시뮬레이터를 업그레이드한 프로젝트입니다.
-
NAND Flash 물리적 제약 구현
- Page 단위 프로그래밍 (2KB)
- Block 단위 삭제 (128 pages/block)
- No Overwrite: 덮어쓰기 금지 (실제 NAND Flash 동작 재현)
-
FTL (Flash Translation Layer) 구현
- L2P (Logical-to-Physical) 매핑 테이블
- Garbage Collection (GC) with Greedy victim selection
- WAF (Write Amplification Factor) 계산
-
데이터 영속성
- 프로그램 종료 후에도 데이터 보존 (
nand_flash.bin) - 재실행 시 기존 상태 자동 복구
- 프로그램 종료 후에도 데이터 보존 (
SSD-project/
├── nand_flash.c/h # 물리적 NAND Flash 시뮬레이션 (Page/Block 제약)
├── ftl.c/h # Flash Translation Layer (L2P, GC, WAF)
├── ssd_new.c/h # 기존 인터페이스 호환 레이어
├── testshell_new.c # 향상된 테스트 쉘 (기존 + 새 명령어)
├── Makefile # 빌드 시스템
└── README.md # 이 문서
make./ssd_simulatormake test # TestApp1, 2, 3 자동 실행
make stats # 통계 출력W <idx> <data>: 특정 LBA에 쓰기 (예:W 3 0xAAAABBBB)R <idx>: 특정 LBA에서 읽기 (예:R 3)fullwrite <data>: 모든 LBA(0~99)에 동일 데이터 쓰기fullread: 모든 LBA(0~99) 읽기
testapp1: Full Write/Read 검증testapp2: Aging Write 및 Over Write 검증 (WAF 확인)testapp3: [NEW] GC 동작 검증 (반복 덮어쓰기로 invalid page 생성)
stats: FTL 및 NAND 통계 출력 (WAF, GC 횟수 등)l2p: L2P 매핑 테이블 출력gc: 강제 GC 발동help: 모든 명령어 목록exit: 프로그램 종료 (자동 영속성 저장)
$ ./ssd_simulator
========================================
SSD Simulator with FTL & GC
Type 'help' for available commands
========================================
ssd> W 0 0xDEADBEEF
[FTL] Initialization complete (Logical Pages: 100)
[SSD] FTL initialized
[SSD] Write success: LBA 0 <- 0xDEADBEEF
ssd> R 0
[SSD] Read success: LBA 0 -> 0xDEADBEEF
ssd> testapp2
[TestApp2] Aging Write 시작 (LBA 0~5에 30번 반복 쓰기)
...
=== Aging 후 통계 ===
========== FTL Statistics ==========
Total Host Writes: 180
Total NAND Writes: 180
Total GC Count: 0
Write Amplification: 1.00x
Free Pages: 12620 / 12800
====================================
ssd> stats
...
ssd> exit
Shutting down SSD simulator...
[FTL] Shutting down...
Goodbye!문제: 기존 코드는 nand.txt에 직접 덮어쓰기 → 실제 NAND와 동작 방식 다름
해결:
nand_flash.c에서 Page 상태 관리 (FREE/VALID/INVALID)- 덮어쓰기 시도 시 에러 반환 → FTL이 GC로 해결
// CRITICAL: 덮어쓰기 금지 (NAND Flash 제약)
if (page->oob.state != PAGE_FREE) {
fprintf(stderr, "[NAND] Cannot overwrite! Need erase first!\n");
return -1;
}L2P 매핑 테이블:
- 사용자가 보는 논리 주소(LBA)를 물리 주소(PBA)로 변환
- 동일 LBA에 재쓰기 시: 새 PBA에 쓰고 기존 PBA는 INVALID로 마킹
// 기존 페이지 무효화 (덮어쓰기 대신)
ftl_invalidate_old_page(ftl, lba);
// 새 위치에 쓰기
uint32_t pba = ftl_find_free_page(ftl);
nand_write_page(&ftl->nand, pba, data, lba);
// L2P 테이블 업데이트
ftl->l2p_table[lba] = pba;발동 조건: Free pages가 부족할 때 자동 발동
동작 순서:
- Victim 선택: Invalid page가 가장 많은 블록 선택 (Greedy 전략)
- Valid 데이터 이동: 해당 블록의 유효한 페이지들을 새 위치로 복사
- Block 삭제: 전체 블록을 삭제하여 free pages 확보
- L2P 업데이트: 이동된 페이지의 매핑 정보 갱신
// GC 핵심 로직
uint32_t victim = ftl_select_victim_block(ftl); // Invalid page 가장 많은 블록
ftl_gc_one_block(ftl, victim); // Valid 데이터 이동
nand_erase_block(&ftl->nand, victim); // 블록 삭제정의: 실제 NAND에 쓰인 데이터량 / 사용자가 요청한 쓰기량
의미:
- WAF = 1.0x: 이상적 (GC 없음)
- WAF = 3.0x: 사용자가 1GB 쓸 때 실제 NAND는 3GB 쓰기 (GC 때문)
- WAF가 높을수록 SSD 수명 단축
계산:
double waf = (double)total_nand_writes / total_host_writes;- 멀티스레드: pthread로 Foreground I/O와 Background GC 분리
- Lock Contention: mutex로 L2P 테이블 동기화, 대기 시간 측정
- 성능 리포트: GC 전후 Latency 비교
- 언어: C (C99)
- 컴파일러: GCC with
-Wall -Wextra -O2 - 의존성: 없음 (표준 라이브러리만 사용)
- 플랫폼: Linux (Ubuntu 24 테스트 완료)
MIT License (기존 프로젝트 계승)