Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add zone reset function and plane-level parallelism in ZNS SSD #155

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 84 additions & 51 deletions hw/femu/zns/zftl.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,22 @@ static inline void check_addr(int a, int max)
static void zns_advance_write_pointer(struct zns_ssd *zns)
{
struct write_pointer *wpp = &zns->wp;

check_addr(wpp->ch, zns->num_ch);
//Misao: the ch-lun-pl pair iterates as "0-0-0","1-0-0","0-1-0","1-1-0","0-0-1","1-0-1",...
check_addr(wpp->ch, zns->num_chs);
wpp->ch++;
if (wpp->ch == zns->num_ch) {
if (wpp->ch == zns->num_chs) {
wpp->ch = 0;
check_addr(wpp->lun, zns->num_lun);
check_addr(wpp->lun, zns->luns_per_ch);
wpp->lun++;
/* in this case, we should go to next lun */
if (wpp->lun == zns->num_lun) {
if (wpp->lun == zns->luns_per_ch) {
wpp->lun = 0;
check_addr(wpp->pl, zns->planes_per_lun);
wpp->pl++;
//Misao: new loop
if(wpp->pl == zns->planes_per_lun)
{
wpp->pl = 0;
}
}
}
}
Expand Down Expand Up @@ -125,8 +131,8 @@ static inline bool valid_ppa(struct zns_ssd *zns, struct ppa *ppa)
int pg = ppa->g.pg;
int sub_pg = ppa->g.spg;

if (ch >= 0 && ch < zns->num_ch && lun >= 0 && lun < zns->num_lun && pl >=
0 && pl < zns->num_plane && blk >= 0 && blk < zns->num_blk && pg>=0 && pg < zns->num_page && sub_pg >= 0 && sub_pg < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE)
if (ch >= 0 && ch < zns->num_chs && lun >= 0 && lun < zns->luns_per_ch && pl >=
0 && pl < zns->planes_per_lun && blk >= 0 && blk < zns->blks_per_plane && pg>=0 && pg < zns->flashpages_per_blk && sub_pg >= 0 && sub_pg < zns->pages_per_flashpage)
return true;

return false;
Expand All @@ -144,6 +150,7 @@ static struct ppa get_new_page(struct zns_ssd *zns)
ppa.ppa = 0;
ppa.g.ch = wpp->ch;
ppa.g.fc = wpp->lun;
ppa.g.pl = wpp->pl;
ppa.g.blk = zns->active_zone;
ppa.g.V = 1; //not padding page
if(!valid_ppa(zns,&ppa))
Expand Down Expand Up @@ -186,22 +193,25 @@ static uint64_t zns_read(struct zns_ssd *zns, NvmeRequest *req)
continue;
}

struct nand_cmd srd;
srd.type = USER_IO;
srd.cmd = NAND_READ;
srd.stime = req->stime;
if(lpn == end_lpn || lpn%zns->pages_per_flashpage == zns->pages_per_flashpage-1)
{
struct nand_cmd srd;
srd.type = USER_IO;
srd.cmd = NAND_READ;
srd.stime = req->stime;

sublat = zns_advance_status(zns, &ppa, &srd);
femu_log("[R] lpn:\t%lu\t<--ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat);
maxlat = (sublat > maxlat) ? sublat : maxlat;
sublat = zns_advance_status(zns, &ppa, &srd);
femu_log("[R] lpn:\t%lu\t<--ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat);
maxlat = (sublat > maxlat) ? sublat : maxlat;
}
}

return maxlat;
}

static uint64_t zns_wc_flush(struct zns_ssd* zns, int wcidx, int type,uint64_t stime)
{
int i,j,p,subpage;
int i,j,subpage;
struct ppa ppa;
struct ppa oldppa;
uint64_t lpn;
Expand All @@ -211,44 +221,41 @@ static uint64_t zns_wc_flush(struct zns_ssd* zns, int wcidx, int type,uint64_t s
i = 0;
while(i < zns->cache.write_cache[wcidx].used)
{
for(p = 0;p<zns->num_plane;p++){
/* new write */
ppa = get_new_page(zns);
ppa.g.pl = p;
for(j = 0; j < flash_type ;j++)
/* new write */
ppa = get_new_page(zns);
for(j = 0; j < flash_type ;j++)
{
ppa.g.pg = get_blk(zns,&ppa)->page_wp;
get_blk(zns,&ppa)->page_wp++;
for(subpage = 0;subpage < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;subpage++)
{
ppa.g.pg = get_blk(zns,&ppa)->page_wp;
get_blk(zns,&ppa)->page_wp++;
for(subpage = 0;subpage < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;subpage++)
if(i+subpage >= zns->cache.write_cache[wcidx].used)
{
if(i+subpage >= zns->cache.write_cache[wcidx].used)
{
//No need to write an invalid page
break;
}
lpn = zns->cache.write_cache[wcidx].lpns[i+subpage];
oldppa = get_maptbl_ent(zns, lpn);
if (mapped_ppa(&oldppa)) {
/* FIXME: Misao: update old page information*/
}
ppa.g.spg = subpage;
/* update maptbl */
set_maptbl_ent(zns, lpn, &ppa);
//femu_log("[F] lpn:\t%lu\t-->ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat);
break;
}
i+=ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;
}
//FIXME Misao: identify padding page
if(ppa.g.V)
{
struct nand_cmd swr;
swr.type = type;
swr.cmd = NAND_WRITE;
swr.stime = stime;
/* get latency statistics */
sublat = zns_advance_status(zns, &ppa, &swr);
maxlat = (sublat > maxlat) ? sublat : maxlat;
lpn = zns->cache.write_cache[wcidx].lpns[i+subpage];
oldppa = get_maptbl_ent(zns, lpn);
if (mapped_ppa(&oldppa)) {
femu_err("%s: in-place update in zns??\n",__func__);
assert(0);
}
ppa.g.spg = subpage;
/* update maptbl */
set_maptbl_ent(zns, lpn, &ppa);
//femu_log("[F] lpn:\t%lu\t-->ch:\t%u\tlun:\t%u\tpl:\t%u\tblk:\t%u\tpg:\t%u\tsubpg:\t%u\tlat\t%lu\n",lpn,ppa.g.ch,ppa.g.fc,ppa.g.pl,ppa.g.blk,ppa.g.pg,ppa.g.spg,sublat);
}
i+=ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;
}
//FIXME Misao: identify padding page
if(ppa.g.V)
{
struct nand_cmd swr;
swr.type = type;
swr.cmd = NAND_WRITE;
swr.stime = stime;
/* get latency statistics */
sublat = zns_advance_status(zns, &ppa, &swr);
maxlat = (sublat > maxlat) ? sublat : maxlat;
}
/* need to advance the write pointer here */
zns_advance_write_pointer(zns);
Expand All @@ -271,7 +278,7 @@ static uint64_t zns_write(struct zns_ssd *zns, NvmeRequest *req)

if(wcidx==-1)
{
//need flush
//Misao: Select the empty write cache or the write cache that aggregated the most valid data to flush
wcidx = 0;
uint64_t t_used = zns->cache.write_cache[wcidx].used;
for(i = 1;i < zns->cache.num_wc;i++)
Expand Down Expand Up @@ -309,6 +316,32 @@ static uint64_t zns_write(struct zns_ssd *zns, NvmeRequest *req)
return maxlat;
}

void zns_reset(struct zns_ssd *zns, uint32_t zid, uint64_t slba, uint64_t elba)
{
int lpn;
struct ppa ppa;
struct zns_blk *blk;
uint64_t secs_per_pg = LOGICAL_PAGE_SIZE/zns->lbasz;
uint64_t slpn = slba / secs_per_pg;
uint64_t elpn = elba / secs_per_pg;

for(lpn = slpn; lpn <= elpn; lpn++){
ppa = get_maptbl_ent(zns,lpn);
blk = get_blk(zns,&ppa);
blk->ipc++;
if(blk->ipc == zns->pages_per_flashpage*zns->flashpages_per_blk)
{
struct nand_cmd erase;
erase.cmd = NAND_ERASE;
erase.stime = 0;
zns_advance_status(zns,&ppa,&erase);
blk->ipc = 0;
}
ppa.ppa = UNMAPPED_PPA;
set_maptbl_ent(zns,lpn,&ppa);
}
}

static void *ftl_thread(void *arg)
{
FemuCtrl *n = (FemuCtrl *)arg;
Expand Down
1 change: 1 addition & 0 deletions hw/femu/zns/zftl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define UNMAPPED_PPA (~(0ULL))

void zftl_init(FemuCtrl *n);
void zns_reset(struct zns_ssd *zns, uint32_t zid, uint64_t slba, uint64_t elba);

#ifdef FEMU_DEBUG_ZFTL
#define ftl_debug(fmt, ...) \
Expand Down
53 changes: 19 additions & 34 deletions hw/femu/zns/zns.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static int zns_init_zone_geometry(NvmeNamespace *ns, Error **errp)
n->zone_size = zone_size / lbasz;
n->zone_capacity = zone_cap / lbasz;
n->num_zones = ns->size / lbasz / n->zone_size;
femu_log("zone size(# of sectors): %ld, zone capacity %ld, num zons %d\n",n->zone_size,n->zone_capacity,n->num_zones);

if (n->max_open_zones > n->num_zones) {
femu_err("max_open_zones value %u exceeds the number of zones %u",
Expand Down Expand Up @@ -524,23 +525,7 @@ static void zns_aio_zone_reset_cb(NvmeRequest *req, NvmeZone *zone)
break;
}

#if 0
FemuCtrl *n = ns->ctrl;
int ch, lun;
struct zns_ssd *zns = n->zns;
uint64_t num_ch = zns->num_ch;
uint64_t num_lun = zns->num_lun;

struct ppa ppa;
for (ch = 0; ch < num_ch; ch++) {
for (lun = 0; lun < num_lun; lun++) {
ppa.g.ch = ch;
ppa.g.fc = lun;
ppa.g.blk = zns_zone_idx(ns, zone->d.zslba);
//FIXME: no erase
}
}
#endif
zns_reset(ns->ctrl->zns, zns_zone_idx(ns, zone->d.zslba), zone->d.zslba, zns_zone_rd_boundary(ns,zone));
}

typedef uint16_t (*op_handler_t)(NvmeNamespace *, NvmeZone *, NvmeZoneState,
Expand Down Expand Up @@ -1244,17 +1229,18 @@ static void zns_init_params(FemuCtrl *n)
int i;

id_zns = g_malloc0(sizeof(struct zns_ssd));
id_zns->num_ch = n->zns_params.zns_num_ch;
id_zns->num_lun = n->zns_params.zns_num_lun;
id_zns->num_plane = n->zns_params.zns_num_plane;
id_zns->num_blk = n->zns_params.zns_num_blk;
id_zns->num_page = n->ns_size/ZNS_PAGE_SIZE/(id_zns->num_ch*id_zns->num_lun*id_zns->num_blk);
id_zns->num_chs = n->zns_params.zns_num_ch;
id_zns->luns_per_ch = n->zns_params.zns_num_lun;
id_zns->planes_per_lun = n->zns_params.zns_num_plane;
id_zns->blks_per_plane = n->zns_params.zns_num_blk;
id_zns->flashpages_per_blk = n->ns_size/ZNS_PAGE_SIZE/(id_zns->num_chs*id_zns->luns_per_ch*id_zns->planes_per_lun*id_zns->blks_per_plane);
id_zns->pages_per_flashpage = ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;
id_zns->lbasz = 1 << zns_ns_lbads(&n->namespaces[0]);
id_zns->flash_type = n->zns_params.zns_flash_type;

id_zns->ch = g_malloc0(sizeof(struct zns_ch) * id_zns->num_ch);
for (i =0; i < id_zns->num_ch; i++) {
zns_init_ch(&id_zns->ch[i], id_zns->num_lun,id_zns->num_plane,id_zns->num_blk,id_zns->flash_type);
id_zns->ch = g_malloc0(sizeof(struct zns_ch) * id_zns->num_chs);
for (i =0; i < id_zns->num_chs; i++) {
zns_init_ch(&id_zns->ch[i], id_zns->luns_per_ch,id_zns->planes_per_lun,id_zns->blks_per_plane,id_zns->flash_type);
}

id_zns->wp.ch = 0;
Expand All @@ -1267,9 +1253,9 @@ static void zns_init_params(FemuCtrl *n)
id_zns->maptbl[i].ppa = UNMAPPED_PPA;
}

//Misao: init sram
id_zns->program_unit = ZNS_PAGE_SIZE*id_zns->flash_type*2; //PAGE_SIZE*flash_type*2 planes
id_zns->stripe_uint = id_zns->program_unit*id_zns->num_ch*id_zns->num_lun;
//Misao: init buffer
id_zns->program_unit = ZNS_PAGE_SIZE*id_zns->flash_type*id_zns->planes_per_lun;
id_zns->stripe_uint = id_zns->program_unit*id_zns->num_chs*id_zns->luns_per_ch;
id_zns->cache.num_wc = ZNS_DEFAULT_NUM_WRITE_CACHE;
id_zns->cache.write_cache = g_malloc0(sizeof(struct zns_write_cache) * id_zns->cache.num_wc);
for(i =0; i < id_zns->cache.num_wc; i++)
Expand All @@ -1281,19 +1267,17 @@ static void zns_init_params(FemuCtrl *n)
}

femu_log("===========================================\n");
femu_log("| ZMS HW Configuration() |\n");
femu_log("| ZNS HW Configuration() |\n");
femu_log("===========================================\n");
femu_log("|\tnchnl\t: %lu\t|\tchips per chnl\t: %lu\t|\tplanes per chip\t: %lu\t|\tblks per plane\t: %lu\t|\tpages per blk\t: %lu\t|\n",id_zns->num_ch,id_zns->num_lun,id_zns->num_plane,id_zns->num_blk,id_zns->num_page);
femu_log("|\tnchnl\t: %lu\t|\tchips per chnl\t: %lu\t|\tplanes per chip\t: %lu\t|\tblks per plane\t: %lu\t|\tflashpages per blk\t: %lu\t|\n",id_zns->num_chs,id_zns->luns_per_ch,id_zns->planes_per_lun,id_zns->blks_per_plane,id_zns->flashpages_per_blk);
//femu_log("|\tl2p sz\t: %lu\t|\tl2p cache sz\t: %u\t|\n",id_zns->l2p_sz,id_zns->cache.num_l2p_ent);
femu_log("|\tprogram unit\t: %lu KiB\t|\tstripe unit\t: %lu KiB\t|\t# of write caches\t: %u\t|\t size of write caches (4KiB)\t: %lu\t|\n",id_zns->program_unit/(KiB),id_zns->stripe_uint/(KiB),id_zns->cache.num_wc,(id_zns->stripe_uint/LOGICAL_PAGE_SIZE));
femu_log("===========================================\n");

//Misao: use average read latency
id_zns->timing.pg_rd_lat[SLC] = SLC_READ_LATENCY_NS;
id_zns->timing.pg_rd_lat[TLC] = TLC_READ_LATENCY_NS;
id_zns->timing.pg_rd_lat[QLC] = QLC_READ_LATENCY_NS;

//Misao: do not suppirt partial programing
id_zns->timing.pg_wr_lat[SLC] = SLC_PROGRAM_LATENCY_NS;
id_zns->timing.pg_wr_lat[TLC] = TLC_PROGRAM_LATENCY_NS;
id_zns->timing.pg_wr_lat[QLC] = QLC_PROGRAM_LATENCY_NS;
Expand All @@ -1307,7 +1291,6 @@ static void zns_init_params(FemuCtrl *n)

n->zns = id_zns;

//Misao: init ftl
zftl_init(n);
}

Expand All @@ -1317,7 +1300,8 @@ static int zns_init_zone_cap(FemuCtrl *n)
struct zns_ssd* zns = n->zns;
n->zoned = true;
n->zasl_bs = NVME_DEFAULT_MAX_AZ_SIZE;
n->zone_size_bs = zns->num_ch*zns->num_lun*zns->num_plane*zns->num_page*ZNS_PAGE_SIZE;
//Misao: we always assume that a zone is the same size as a superblock.
n->zone_size_bs = zns->num_chs*zns->luns_per_ch*zns->planes_per_lun*zns->flashpages_per_blk*ZNS_PAGE_SIZE;
n->zone_cap_bs = 0;
n->cross_zone_read = false;
n->max_active_zones = 0;
Expand All @@ -1329,6 +1313,7 @@ static int zns_init_zone_cap(FemuCtrl *n)

static int zns_start_ctrl(FemuCtrl *n)
{
femu_debug("%s, n->page_size = %d\n",__func__,n->page_size);
/* Coperd: let's fail early before anything crazy happens */
assert(n->page_size == 4096);

Expand Down
17 changes: 10 additions & 7 deletions hw/femu/zns/zns.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct ppa {
struct write_pointer {
uint64_t ch;
uint64_t lun;
uint64_t pl;
};

struct nand_cmd {
Expand All @@ -97,6 +98,7 @@ struct zns_blk {
int nand_type;
uint64_t next_blk_avail_time;
uint64_t page_wp; //next free page
uint64_t ipc; //invalid page count
};

struct zns_plane{
Expand Down Expand Up @@ -128,17 +130,18 @@ struct zns_write_cache{
uint64_t* lpns; //identify the cached data
};

struct zns_sram{
struct zns_buffer{
int num_wc;
struct zns_write_cache* write_cache;
};

struct zns_ssd {
uint64_t num_ch;
uint64_t num_lun;
uint64_t num_plane;
uint64_t num_blk;
uint64_t num_page;
uint64_t num_chs;
uint64_t luns_per_ch;
uint64_t planes_per_lun;
uint64_t blks_per_plane;
uint64_t flashpages_per_blk;
uint64_t pages_per_flashpage;

struct zns_ch *ch;
struct write_pointer wp;
Expand All @@ -147,7 +150,7 @@ struct zns_ssd {
int flash_type;
uint64_t program_unit;
uint64_t stripe_uint;
struct zns_sram cache;
struct zns_buffer cache;

/*Misao: we still need a ftl in consumer devices*/
uint64_t l2p_sz; /* = # of 4KiB pages*/
Expand Down