<repo_name>Umar895/SSD_Simulator<file_sep>/die.hh
#ifndef DIE_HH
#define DIE_HH

#include<iostream>

//#include "plane.hh"
//#include "block.hh"
#include "ssd_config.hh"
#include "ssd.hh"

using namespace std;
class Plane;

class Die{

private:
	long id;
	long long t_zero;
	int free_blks;
	int free_planes;
	int erase_count;

	Plane* pln_inuse;

	//vector<Plane*> plane_ptrs;

public:

	Die(const int & planes, const int & blocks, int new_id);
	virtual ~Die(){};

	int get_id();

	bool set_plnInuse(Plane* plane_id);
	Plane* get_plnInuse();

	int get_free_blks();

	bool set_time(long long time_zero);
	long long get_time();

	bool inc_erase_count();
	int get_erase_count();
	bool reset_erase_count();
};

#endif
<file_sep>/page.cpp
#include "page.hh"

Page::Page(){
	id = -1;
	block_id = -1;
	page_in_block = -1;
	page_writes = 0;
	stat = 0;
	lba = 0;
}

Page::Page(uint64_t new_id, int blk_id, int pln_id, int di_id){
	this->id = new_id;
	this->block_id = blk_id;
	this->plane_id = pln_id;
	this->die_id = di_id;

	page_in_block = -1;
	page_writes = 0;
	stat = 0;
	page_written = 0;
}

//bool Page::set_id(long new_id){
//	id = new_id;
//	return true;
//}

uint64_t Page::get_id(){
	return id;
}

//bool Page::set_block_id(long new_id){
//	block_id = new_id;
//	return true;
//}

int Page::get_block_id(){
	return block_id;
}

int Page::get_plane_id(){
	return plane_id;
}

int Page::get_die_id(){
	return die_id;
}

bool Page::inc_page_writes(){
	page_writes++;
	return true;
}

bool Page::set_page_in_block(int seek){
	page_in_block = seek;
	return true;
}

int Page::get_page_writes(){
	return page_writes;
}

uint64_t Page::get_lba(){
	return lba;
}

bool Page::write_page(uint64_t lpn){
	stat = 1;
	page_written++;
	lba = lpn;
	return true;
}

bool Page::invalidate_page(){
	stat = -1;
	return true;
}

bool Page::free_page(){
	stat = 0;
	lba = 0;
	return true;
}

int Page::get_page_stat(){
	return stat;
}

int Page::get_page_written(){
	return page_written;
}

<file_sep>/ssd.cpp
#include "ssd.hh"

//template <class any>
SSD::SSD(const SSD_Config &config){

	Die *new_die;
	Plane *new_plane;
	Block *new_block;
	Page *new_page;

	N_dies = config.N_dies;
	N_planes = config.N_planes;
	N_blocks = config.N_blocks;
	N_pages = config.N_pages;
	
	op_blocks = (N_blocks * config.O_prov)/100;

	//write_delay = config.w_delay;
	//read_delay = config.r_delay;
	//erase_delay = config.e_delay;

	// For uniform distribution of op_blocks across the dies
	if(op_blocks%N_dies!=0){
		op_blocks = ((op_blocks + N_dies/2) / N_dies) * N_dies;
	}

	for(auto i=0; i<N_dies; i++){
		new_die = new Die(N_planes, N_blocks + op_blocks, t_di);
		ssd_die.push_back(new_die);


		for(auto j=0; j<N_planes; j++){
			new_plane = new Plane(N_blocks + op_blocks,t_pln, t_di);
			die_plane[new_die].push_back(new_plane);


			for(auto k=0; k<N_blocks+op_blocks; k++){
				new_block = new Block(N_pages,t_blk, t_pln, t_di);
				//new_plane->set_block(t_blk,new_block);
				plane_blk[new_plane].push_back(new_block);


				for(auto l=0; l<N_pages; l++){
					new_page = new Page(t_page, t_blk, t_pln, t_di);
					block_page[new_block].push_back(new_page);

					t_page++;
				}
				t_blk++;
			}
			t_pln++;
		}
		t_di++;
	}

	// A whole die is used for the parity of rest of dies
	xor_die = ssd_die.back();
	ssd_die.pop_back();
	//N_dies = N_dies-1;

	cout<<"die:"<<config.N_dies<<" plane:"<<config.N_planes<<" blk:"<<config.N_blocks<<" page:"<<config.N_pages<<endl;
	cout<<"die:"<<t_di<<" plane:"<<t_pln<<" blk:"<<t_blk<<" page:"<<t_page<<endl;

	if(t_di!=config.N_dies && 
		   t_pln!=config.N_dies * config.N_planes &&
		   t_blk!=config.N_dies * config.N_planes * (config.N_blocks + op_blocks)&&
		   t_page!=config.N_dies * config.N_planes * (config.N_blocks + op_blocks) * config.N_pages){

		cout<<" Cannot create the required configuration metrics!!"<<endl;
	}else{
		cout<<"Total pages, blocks, planes and dies created are as follows:"<<endl;
		cout<<"t_pages:"<<t_page<<" t_blks:"<<t_blk<<" t_pln:"<<t_pln<<" t_di:"<<t_di<<endl;

	}
	High_water_mark = N_blocks + op_blocks - 4;
	 Low_water_mark = High_water_mark  - op_blocks/4 ;

	//High_water_mark_xor = N_blocks + op_blocks - 16;

	 cout<<"high: "<<High_water_mark<<" low: "<<Low_water_mark<<endl;
}

/* Destructor for the SSD */
SSD::~SSD(){

	cout<<"destructor is called "<<endl;

	ssd_die.push_back(xor_die);

	Die *old_die;
	Plane *old_plane;
	Block *old_block;
	Page *old_page;

	for(auto i=0; i<N_dies; i++){
		old_die = ssd_die.front();

		//for(auto j=0; j<die_plane[old_die].size(); j++){
		for(auto j:die_plane){
			old_plane = die_plane[old_die].front();

			//for(auto k=0; k<plane_blk[old_plane].size(); k++){
			for(auto k:plane_blk){
				old_block = plane_blk[old_plane].front();

				//for(auto l=0; l<block_page[old_block].size(); l++){
				for(auto l:block_page){
					old_page = block_page[old_block].front();
					block_page[old_block].pop_front();
					delete old_page;
				}
				plane_blk[old_plane].pop_front();
				delete old_block;
			}
			die_plane[old_die].pop_front();
			delete old_plane;
		}
		ssd_die.pop_front();
		delete old_die;
	}
	

}


/* The writing strategy is as follows:
 * Die: For each write, die is selected in round robin fashion
 * Plane: For each request inside die, planes are also selected in round robin 
 * Block: The next inuse block in the plane is selected as the block, otherwise next free block of plane
 * ####################################################
 * For Example:
 * we have Die=2, plane=4
 *
 * Assume incoming request is as follows: (1,2,3,4,5,6,7,8,9,10) and are distributed as follows:
 * 
 * 1 - Die-0 => plane-0 => block-0 => page-0
 * 2 - Die-1 => plane-0 => block-0 => page-0
 * 3 - Die-0 => plane-1 => block-0 => page-0
 * 4 - Die-1 => plane-1 => block-0 => page-0
 * 5 - Die-0 => plane-2 => block-0 => page-0
 * 6 - Die-1 => plane-2 => block-0 => page-0
 * 7 - Die-0 => plane-3 => block-0 => page-0
 * 8 - Die-1 => plane-3 => block-0 => page-0
 * 9 - Die-0 => plane-0 => block-0 => page-1
 * 10- Die-1 => plane-0 => block-0 => page-1
 * ####################################################
 * 
 * But in a case when a page is invalidated, then same die is selected to overwrite the invalid page
 */


void SSD::get_write_loc(write_loc *loc, Die* die_inv, Plane* pln_inv){

	Die *next_die=NULL;
	Plane *next_plane=NULL;
	Block *next_block=NULL;
	Page* next_page=NULL;

	// Round Robin for selecting die to write, every die always has a free block available
	next_die = ssd_die.front();
	ssd_die.pop_front();
	ssd_die.push_back(next_die);
	assert(next_die!=0);


	// Initially the plane in use is NULL
	next_plane = die_plane[next_die].front();
	die_plane[next_die].pop_front();
	die_plane[next_die].push_back(next_plane);

	assert(next_plane!=0);

	if(next_plane->get_free_blks()==0){
		cout<<"no block available in plane: "<<next_plane->get_id()<<" die: "<<next_die->get_id()<<endl;
		assert(1<0);
	}

	// Initially no block is written, which gives null
	next_block = next_plane->get_blkInuse();
	if(next_block == NULL){
		next_block = plane_blk[next_plane].front();
	}

	assert(next_block!=0);

	if(next_block->get_free_pgs()==0){
		cout<<"There is no free pages on the block: "<<next_block->get_id()<<" plane:"<<next_plane->get_id()<<" die:"<<next_die->get_id()<<endl;
		assert(1<0);
	}

	next_plane->set_blkInuse(next_block);

	next_page = block_page[next_block].front();

	if(next_page->get_page_stat()!=0){
		cout<<"page is not free"<<endl;
		assert(1<0);
	}

	block_page[next_block].pop_front();
	block_page[next_block].push_back(next_page);

	assert(next_page!=0);

	loc->die = next_die;
	loc->plane = next_plane;
	loc->block = next_block;
	loc->page = next_page;


}

int SSD::random_gen(int min, int max){
	
	return min + rand() % (max - min);
}


bool SSD::external_read(uint64_t lpn, int IOSize, double time){

	Die *die_r=NULL;
/*
	int pos = random_gen(1,lpn_ppn.size());

	auto it = lpn_ppn.begin();
	advance(it,pos);
	lpn = it->first;

	die_r = lpn_ppn[lpn].die;

	if(gc_flag[die_r].write>0){
		gc_flag[die_r].blocked++;
	}else{
		read_bt_gc_flag_zero++;
	}
	ur++;
*/
	auto it = lpn_ppn.find(lpn);
	if(it!=lpn_ppn.end()){
		die_r = lpn_ppn[lpn].die;

		if(gc_flag[die_r].write>0){
			gc_flag[die_r].blocked++;
		}else{
			read_bt_gc_flag_zero++;
		}
	}

	ur++;

	if((uw + ur + gcw)%100000==0 && gcw>0){
		stat();
	}

	return true;
}
/*
void SSD::overwrite_parity(Block* blk){
	Block *blk_x;
	
	//map<int,Block*>::iterator it = block_m.find(blk);

	if(blk->get_die_id()==0){
		
	}

	int offset = block_m.size()/(N_dies*N_planes);

	N_dies - blk->get_die_id();

	blk_x = block_m[blk->get_id() + offset];

}
*/

bool SSD::external_write(uint64_t lpn, int IOSize, double time){


	Die *die_i=NULL;
	Plane *pln_i = NULL;
	Block *blk_i = NULL;
	Page *page_i = NULL;

	Plane *plane_w;
	Block *blk_w;
	Page *page_w;

	Block *temp_blk = NULL;

	write_loc loc;

	invalid_page = false;

	auto it = lpn_ppn.find(lpn);
	if(it!=lpn_ppn.end()){
		die_i = lpn_ppn[lpn].die;
		pln_i = lpn_ppn[lpn].plane;
		blk_i = lpn_ppn[lpn].block;
		page_i = lpn_ppn[lpn].page;

		lpn_ppn.erase(lpn);
		invalid_page = true;
		iw++;

		blk_i->remove_page(page_i, time);

		//overwrite_parity(blk_i);
	}

	get_write_loc(&loc, die_i, pln_i);

	update_gc_flag();

	if(time==t_page){uw=gcw;}

	page_w = loc.page;
	blk_w = loc.block;
	plane_w = loc.plane;

	blk_w->write_page(lpn,page_w, time);
	
	uw++;

	lpn_ppn[lpn].die = loc.die;
	lpn_ppn[lpn].plane = plane_w;
	lpn_ppn[lpn].block = blk_w;
	lpn_ppn[lpn].page = page_w;


	//cout<<"free pages in the current block "<<write_blk->get_free_pgs()<<endl;
	if(blk_w->get_free_pgs()==0){
		//cout<<"time to push the block into filled block"<<endl;
		temp_blk = plane_blk[plane_w].front();
		plane_w->push_block(temp_blk);

		plane_blk[plane_w].pop_front();
		plane_w->reduce_free_blks();

		xoring_block(blk_w, time);

		plane_w->set_blkInuse(plane_blk[plane_w].front());

		
	}

	int inf_gc = 0;
	if(plane_w->get_block_size()>=High_water_mark){


		while(plane_w->get_block_size() >= Low_water_mark){
			garbage_collect(loc.die,plane_w,time);
			if(inf_gc>1){break;}
			inf_gc++;
			//if(uw==1363585){
/*			if(gcw>4244430){
				cout<<"gcw: "<<gcw<<" blks_in_a_pln: "<<plane_w->get_block_size()<<endl;
				if(gcw>4246430){assert(1<0);}
			}
*/			//if(plane_w->get_block_size()==990){	assert(1<0);}

		}
		gc_flag_set(loc.die);
	}

	if((uw + ur + gcw)%100000==0 && gcw>0){
		stat();
	}

	return true;
}

bool SSD::gc_flag_set(Die* di_id){

	gc_flag[di_id].write = 8;
	gc_flag[di_id].read = 60;

	return true;
}

bool SSD::update_gc_flag(){

	for (map<Die*,iops>::iterator it=gc_flag.begin(); it!=gc_flag.end(); ++it){
		if(it->second.write>0){
			it->second.write--; 
			it->second.read = it->second.read - 8;
		}
	}

	

	return true;
}


bool SSD::check_distance(int dis1, int dis2, int dis3){

	if(dis3-dis2 == dis2-dis1){
		//cout<<"equi distant, xor possible"<<endl;

		return true;
	}else{

		cout<<"xor not possible"<<endl;
		cout<<"ids 1:"<<dis1<<" 2:"<<dis2<<" 3:"<<dis3<<endl;
		return false;
	}
}


// Xor of blocks
bool SSD::xoring_block(Block* blk, double time){

	Plane *x_plane;

	Block *first, *second, *third, *x_blk;
	Page *page, *page1, *page2, *x_page;
	int dis1, dis2, dis3;
	int xo;

//	if(blks.size()!=0){
		
//		assert(1<0);
		tmp_blks.push_back(blk);
		if(tmp_blks.size()==3){
			
			x_plane=die_plane[xor_die].front();

			first = tmp_blks.front();
			dis1 = first->get_id();
			tmp_blks.pop_front();
	
			second = tmp_blks.front();
			dis2 = second->get_id();
			tmp_blks.pop_front();

			third = tmp_blks.front();
			dis3 = third->get_id();
			tmp_blks.pop_front();

			if(!check_distance(dis1,dis2,dis3)){
				cout<<"the blocks are unaligned for xor"<<endl;
				assert(1<0);
			}
			x_blk = plane_blk[x_plane].front();

			//cout<<"dis1:"<<dis1<<" dis2:"<<dis2<<" dis3:"<<dis3<<" dis4:"<<dis3+offset<<endl;
			//assert(1<0);

			for(int i=0; i<N_pages; i++){
				page = first->get_page_at(i);
				page1 = second->get_page_at(i);
				page2 = third->get_page_at(i);

				uint64_t flags[] = {(page->get_lba()),page1->get_lba(),page2->get_lba()};

				xo = accumulate(flags,end(flags),0,bit_xor<int>());
				
				x_page = block_page[x_blk].front();

				if(x_page->get_page_stat()!=0){
					cout<<"page is not free status:"<<x_page->get_page_stat()<<endl;
					cout<<"xblk_id:"<<x_blk->get_die_id()<<endl;
					assert(1<0);
				}

				block_page[x_blk].pop_front();
				block_page[x_blk].push_back(x_page);

				x_blk->write_xor(xo, x_page, i, time);
				xor_w++;
			}

			if(x_plane->get_id()!=x_blk->get_plane_id()){
				cout<<"the planes conflict after the xor"<<endl;
				assert(1<0);
			}

			if(plane_blk[x_plane].front()!=x_blk){
				cout<<"serious problem!!"<<endl;
				assert(1<0);
			}

			plane_blk[x_plane].pop_front();
			x_plane->push_block(x_blk);
			x_plane->reduce_free_blks();
			
			if(x_plane->get_block_size()>=High_water_mark){
				garbage_collect(xor_die,x_plane, time);

			}
			die_plane[xor_die].pop_front();
			die_plane[xor_die].push_back(x_plane);

			tmp_blks.clear();
		}
//	}


	return true;
}

bool SSD::internal_write(Die* die, uint64_t lpn, Plane* plane, long long time){

	Block *next_block=NULL;
	Page *next_page=NULL;

	Block *temp_blk;

	assert(lpn!=0);

	plane = die_plane[die].front();
	die_plane[die].pop_front();
	die_plane[die].push_back(plane);

	// Initially no block is written, which gives null
	next_block = plane->get_blkInuse();
	if(next_block == NULL){
		next_block = plane_blk[plane].front();
	}

	assert(next_block!=0);
	if(next_block->get_free_pgs()==0){
		cout<<"There is no free pages on the block: "<<next_block->get_id()<<" plane:"<<next_block->get_plane_id()<<" die:"<<next_block->get_die_id()<<endl;
		assert(1<0);
	}

	next_page = block_page[next_block].front();

	block_page[next_block].pop_front();
	block_page[next_block].push_back(next_page);
	//next_page = block_page[next_block].front();
/*	if(gcw>4244430){
		cout<<"before write"<<endl;
		cout<<"plane blk size: "<<plane_blk[plane].size()<<endl;
		cout<<"pln: "<<plane<<endl;
		for (auto it = plane_blk.begin(); it != plane_blk.end(); it++)
		{
			cout << it->first << ":";
			for (auto lit = it->second.begin(); lit  != it->second.end(); lit++)
		        cout << " " << (*lit)->get_free_pgs();
				cout << "\n";
		}
	}
*/
	next_block->write_page(lpn,next_page, time);
	//next_block->write_page(next_page,time);
	
	if(next_block->get_free_pgs()==0){
		//cout<<"time to push the block into filled block"<<endl;
		temp_blk = plane_blk[plane].front();
		plane->push_block(temp_blk);

		plane_blk[plane].pop_front();
		plane->reduce_free_blks();

		plane->set_blkInuse(plane_blk[plane].front());
/*		if(gcw>4244430){
			cout<<"after write"<<endl;
			cout<<"plane blk size: "<<plane_blk[plane].size()<<endl;
			cout<<"pln: "<<plane<<endl;
			for (auto it = plane_blk.begin(); it != plane_blk.end(); it++)
			{
				cout << it->first << ":";
				for (auto lit = it->second.begin(); lit  != it->second.end(); lit++)
			        cout << " " << (*lit)->get_free_pgs();
					cout << "\n";
			}
		}
*/	}

	lpn_ppn[lpn].die = die;
	lpn_ppn[lpn].plane = plane;
	lpn_ppn[lpn].block = next_block;
	lpn_ppn[lpn].page = next_page;

	return true;
}

void SSD::garbage_collect(Die* die, Plane *plane, long long time){

	Block *victim_block;
	Page* reset_page;

	list<Page*>::iterator it;

	victim_block = plane->get_victim_block(time);
/*	if(victim_block->get_dirty_pgs()==0){
		cout<<"victim blk does not have a dirty page "<<endl;
		debug(plane);
		assert(1<0);
	}
*/
	for(it = block_page[victim_block].begin(); it!=block_page[victim_block].end(); it++){
		reset_page = *it;

		if(reset_page->get_page_stat() == 1){
			// shift the write to active block please
			if(reset_page->get_lba()!=0){
				//internal_write(die,reset_page->get_lba(),plane, time);
				lpn_ppn.erase(reset_page->get_lba());
			}
			gcw++;
		}
		reset_page->free_page();
	}

	victim_block->erase_block(time);
	plane_blk[plane].push_back(victim_block);
	plane->add_free_blks();
	die->inc_erase_count();
}


void SSD::stat(){
	
	cout<<"mp_t:"<<lpn_ppn.size();
	
	cout<<" uw:"<<uw<<" ur(%):"<<100*double(ur)/double(uw+ur)<<" wa:"<<double(uw+xor_w+gcw)/double(uw);
	cout<<"| dies";
	for (map<Die*,iops>::iterator it=gc_flag.begin(); it!=gc_flag.end(); ++it){
			cout<<"|"<<it->second.blocked<<"/"<<(it->first)->get_erase_count();
			//cout<<"|"<<double((it->first)->get_erase_count())/double(it->second.blocked);
			(it->first)->reset_erase_count();
			gc_flag[it->first].blocked=0;
			
	}

	//cout<<" r_m:"<<read_missed<<" : "<<read_bt_gc_flag_zero;
	cout<<'\n';
}


void SSD::debug(Plane* plane){

	Block* victim_block;
	int dirty=0;
	int valid=0;

	int ful_blks = plane->get_block_size();

	for(int i=0; i<ful_blks; i++){
		victim_block = plane->get_victim_block(1);
		if(victim_block->get_dirty_pgs() == 0){
			dirty++;
		}
		if(victim_block->get_valid_pgs()==256){
			valid++;
		}
	}

	cout<<"ful_blk: "<<ful_blks<<" dirty: "<<dirty<<" valid: "<<valid<<endl;
}
<file_sep>/die.cpp
#include "die.hh"

Die::Die(const int & planes, const int & blocks, int new_id){

	/* Set die id */
	id = new_id;

	free_planes = planes;

	//plane_ptrs.resize(planes);

	//for(int i=0; i<planes; i++){
	//	plane_ptrs[i] = NULL;
	//}

	pln_inuse = NULL;

	free_blks = blocks;

	erase_count=0;
}

int Die::get_id(){
	return id;
}

bool Die::set_time(long long time_zero){
	t_zero = time_zero;
	return true;
}

long long Die::get_time(){
	return t_zero;
}

bool Die::set_plnInuse(Plane* plane_id){
	pln_inuse = plane_id;
	return true;
}

Plane* Die::get_plnInuse(){
	return pln_inuse;
}

int Die::get_free_blks(){
	return free_blks;
}

bool Die::inc_erase_count(){
	erase_count++;
	return true;
}

int Die::get_erase_count(){
	return erase_count;
}

bool Die::reset_erase_count(){
	erase_count = 0;
	return true;
}
<file_sep>/block.hh
#ifndef BLOCK_H
#define BLOCK_H

#include<map>
#include<iostream>

//#include "page.hh"
//#include "ssd.hh"
#include "ssd_config.hh"
#include "plane.hh"

class SSD_Config;
class Page;

class Block{

private:
	int id;
	int plane_id;
	int die_id;

	int valid_pgs;
	int dirty_pgs;
	int free_pgs;

	long erase_cnt;

	int seek;

	long waccess;

	long t_zero;

	int N_pages;

	map<int,Page*> page_ptrs;


public:


	Block(const int & Np, int new_id, int pln_id, int di_id);
	virtual ~Block(){};

	virtual bool erase_block(long long time);

	bool write_page(Page *page, long long time);
	bool write_page(uint64_t lba, Page *page, long long time);
	bool write_xor(uint64_t lba, Page *page, int seek, long long time);

	virtual bool remove_page(Page *page, long long time);

	//bool set_id(long new_id);

	int get_id();
	int get_plane_id();
	int get_die_id();

	int get_free_pgs();
	int get_dirty_pgs();
	int get_valid_pgs();

	long long get_waccess();
	//bool set_t_zero();

	Page* get_page_at(int pos);
	long get_erase_cnt();

};
#endif
<file_sep>/ssd_config.hh
#ifndef SSD_CONFIG_H
#define SSD_CONFIG_H

#include<iostream>
#include<fstream>
#include<string>

#include<sys/stat.h>
#include<sys/types.h>
//#include<fnctl>

#include<unistd.h>
#include "ssd.hh"

using namespace std;


class SSD_Config{

private:
	void copyConfigFile(std::string configFile, std::string logFolder);

public:

	uint64_t Nlp = 0;
	int N_dies = 0;			// Dies per SSD
	int N_planes = 0;		// Planes per Die or channel
	int N_blocks = 0;		// blocks per plane
	int N_pages = 0;		// pages per block
	int Capacity = 0;		// TODO:Not used yet

	double w_delay = 0;		// Write delay for a single page
	double r_delay = 0;		// Read delay for a single page
	double e_delay = 0;		// erase delay for a block

	double ctor_delay = 0;	// controller to register delay or vice versa for a single page
	double O_prov = 0;		// percentage of over-provisioing
	int seed = 0;

	//std::vector<std::string> ignoredKeywords;

	bool printConfig = true;

	std::string logFolder = "";

	std::string traceFile = "";

	SSD_Config(string configFile);

	//SSD * init_SSD(string configFile) const;

	virtual ~SSD_Config(){ }
	virtual bool checkConfig()const;
};

#endif
<file_sep>/plane.hh
#ifndef PLANE_HH
#define PLANE_HH

#include<iostream>
#include<vector>
#include<list>
#include<limits>

//#include "block.hh"
//#include "page.hh"
#include "ssd_config.hh"
#include "die.hh"

using namespace std;
class Block;

class Plane{

private:
	int id;
	int die_id;
	//int Nb;

	int free_blks;
	int written_blk;
	Block* blk_inuse;

	map<int,Block*> blk_ptrs;

	list<Block*> full_blk;

public:
	Plane(const int & Nb, int new_id, int di_id);

	bool set_id(int new_id);
	int get_id();

	bool set_dieId(int die_Id);
	int get_dieId();

	bool set_block(int b_id, Block* new_blk);

	bool reduce_free_blks();
	int get_free_blks();
	bool add_free_blks();

	bool set_blkInuse(Block* blk_inuse);
	Block* get_blkInuse();

	bool push_block(Block* temp_blk);

	int get_block_size();

	Block* get_full_blk();

	Block* get_victim_block(long long time);
};
#endif
<file_sep>/plane.cpp
#include "plane.hh"

Plane::Plane(const int & Nb, int new_id, int di_id){
	
	id = new_id;
	die_id = di_id;

	free_blks = Nb;
	written_blk = 0;

	for(int i=0; i<Nb; i++){
		blk_ptrs[i] = NULL;
	}

	blk_inuse = NULL;
	
}

bool Plane::set_id(int new_id){
	id = new_id;
	return true;
}

int Plane::get_id(){
	return id;
}

bool Plane::set_dieId(int die_Id){
	die_id = die_Id;
	return true;
}

int Plane::get_dieId(){
	return die_id;
}

bool Plane::set_block(int b_id, Block* new_blk){
	blk_ptrs[b_id] = new_blk;
	return true;
}

bool Plane::reduce_free_blks(){
	free_blks--;
	written_blk++;
	return true;
}

int Plane::get_free_blks(){
	return free_blks;
}

bool Plane::add_free_blks(){
	free_blks++;
	written_blk--;
	return true;
}

bool Plane::set_blkInuse(Block* bl_inuse){
	blk_inuse = bl_inuse;
	return true;
}

Block* Plane::get_blkInuse(){
	return blk_inuse;
}

// Returns the block sequentially for xor operations
Block* Plane::get_full_blk(){
	Block *next_blk;
	next_blk = full_blk.front();
	full_blk.pop_front();
	full_blk.push_back(next_blk);
	return next_blk;
}

bool Plane::push_block(Block* temp_blk){
	full_blk.push_back(temp_blk);
	return true;
}

int Plane::get_block_size(){

	return full_blk.size();

}

Block* Plane::get_victim_block(long long time){

	Block* victim_block;
	Block* block;

	int min_valid = numeric_limits<int>::max();
	list<Block*>::iterator it, it_erase;

	//cout<<"size blks: "<<full_blk.size()<<endl;

    for (it=full_blk.begin();it!=full_blk.end();it++){
        block = *it;

		//cout<<"valid_pgs "<<block->get_valid_pgs()<<endl;

		if(block->get_valid_pgs() < min_valid){
			min_valid = block->get_valid_pgs();
			victim_block = *it;
			it_erase = it;
		}
		
	}
	//cout<<"victim valid_pgs "<<victim_block->get_valid_pgs()<<endl;
	full_blk.erase(it_erase);
	//cout<<"size blks: "<<full_blk.size()<<endl;

	return victim_block;
	
}



<file_sep>/Makefile
# SSD Simulator
# 2017 <NAME>. All Rights Reserved

CC = g++

#compiler flags:
# -g adds debugging information to the executable file
# -Wall turns on most, but not all. compiler warnings
CFLAGS = -g -std=c++11 -Wall -D_REENTRANT

#include libs
LDLIB = -g

DEP = ssd_config.hh
SRC = main.cpp ssd_config.cpp ssd.cpp page.cpp block.o plane.o die.o
OBJ = main.o ssd_config.o ssd.o page.o block.o plane.o die.o

main: main.o ssd_config.o ssd.o page.o block.o
	$(CC) $(LDFLAGS) $(LDLIBS) -o main $(OBJ)

main.o: $(SRC)
	$(CC) $(CFLAGS) -c main.cpp

ssd_config.o: ssd_config.hh ssd_config.cpp
	$(CC) $(CFLAGS) -c ssd_config.cpp

ssd.o: ssd.hh ssd.cpp
	$(CC) $(CFLAGS) -c ssd.cpp

die.o: die.hh die.cpp
	$(CC) $(CFLAGS) -c die.cpp

plane.o: plane.hh plane.cpp
	$(CC) $(CFLAGS) -c plane.cpp

block.o: block.hh block.cpp
	$(CC) $(CFLAGS) -c block.cpp

page.o: page.hh page.cpp
	$(CC) $(CFLAGS) -c page.cpp

clean:
	rm *.o
	rm main
<file_sep>/main.cpp
#include<iostream>
#include<string>
#include<fstream>
#include<random>
#include<assert.h>
#include<ctime>

#include "ssd_config.hh"
//#include "tracegen/trace.hh"
#include "ssd.hh"

using namespace std;

SSD_Config * config = NULL;
SSD *ssd = NULL;

int random_gen(int min, int max){

	static bool first = true;

	if(first){
		srand(42);
		first = false;
	}
	return min + rand() % (max - min);
}

int main(int argc, char ** argv){

	if(argc != 2){
		cout<<"\033[1;31mCorrect call <config file> \033[0m "<<endl;
		exit(-1);
	}

	std::string configFile = argv[1];

	long long inc_time = 1;
	config = new SSD_Config(configFile);

	ssd = new SSD(*config);

	//ssd->init_SSD(config);
	bool validConfig = config->checkConfig();
	if(!validConfig){
		cout<<"\t################################"<<endl;
		cout<<"\tWARNING: config file is not valid !!"<<endl;
		cout<<"\t################################"<<endl;
		cout<<endl;
	}

	std::string FileName = config->traceFile;

	std::mt19937 gen(config->seed);
	std::uniform_int_distribution<>dis(0,config->Nlp-1);

	time_t start_time = time(0);
	// Sequential Writes
	cout<<"Sequential Writes "<<endl;
	for(int i=0; i<1; i++){
		for(uint64_t z=0; z<config->Nlp; z++){
			ssd->external_write(z,1,inc_time);
			inc_time++;
		}
	}

	int req_size = 0;
	uint64_t req = 0;
	int r_w;
	// Random Writes
	cout<<"Random Writes "<<endl;
	for(int j=0; j<2; j++){
		for(uint64_t i=0; i<config->Nlp; i++){
			//break;
			//cout<<"rand:"<<random_gen(0, config->Nlp)<<endl;
			req_size = random_gen(1,2);
			r_w = random_gen(0,20);
			req = random_gen(1, config->Nlp);

			for(int x=0; x < req_size; x++){
				
					ssd->external_write(req+x, req_size , inc_time);

					inc_time++;
			}

			if(r_w%3==0){
				for(int y=0; y<req_size; y++){
					ssd->external_read(req+y, req_size, inc_time);
					inc_time++;
				}
			}
		}
	}

	time_t end_time = time(0);
	uint64_t duration = (uint64_t)difftime(end_time, start_time);
	cout<<"Total Simulation time: "<<duration/3600<<":"<<(duration%3600)/60<<":"<<((duration%3600)%60)<<endl;

	delete config;
	delete ssd;

	return 0;
}
<file_sep>/README.md

Simulate:
---------

Type make and run the main file by specifying the configuration file.

	./main <config file>	(ssd.conf is the config file which needs to be mentioned)

All other information is available in configuration file.


<file_sep>/page.hh
#ifndef PAGE_HH
#define PAGE_HH

#include<iostream>
#include "block.hh"
#include "ssd.hh"

using namespace std;

class Page{

private:
	uint64_t id;
	int block_id;
	int plane_id;
	int die_id;
	int page_in_block;
	int page_writes;

	/* there will be three states of a page as follows:
		free = 0;
		write = 1;
		invalidate = -1;
	*/
	int stat;

	int page_written;

	uint64_t lba;

public:

	Page();

	//template <class id>
	Page(uint64_t new_id, int blk_id, int pln_id, int di_id);

	//template <class A>
	//bool set_id(uint64_t new_id, int blk_id, int pln_id, int di_id);

	uint64_t get_id();

	//bool set_block_id(long new_id);
	int get_block_id();
	int get_plane_id();
	int get_die_id();

	bool set_page_in_block(int seek);
	long get_page_in_block(){return page_in_block;}

	bool inc_page_writes();
	int get_page_writes();

	uint64_t get_lba();
	bool write_page(uint64_t lpn);
	bool invalidate_page();
	bool free_page();

	int get_page_stat();

	int get_page_written();
};

#endif
<file_sep>/block.cpp
#include "block.hh"

Block::Block(const int & Np, int new_id, int pln_id, int di_id){

	N_pages = Np;

	/* set block, plane, and die id */
	id = new_id;
	plane_id = pln_id;
	die_id = di_id;
 
	//page_ptrs.resize(Np);

	/* initially all pages in a block are invalid */
	for(int i=0; i<Np; i++){
		page_ptrs[i] = NULL;
	}

	/* There are only free pages directly after init */
	free_pgs = Np;
	valid_pgs = 0;
	dirty_pgs = 0;
	erase_cnt = 0;
	t_zero = 0;

	/* Start writing from the beginning of the block */
	seek = 0;

	/* The block has not yet been accessed */
	waccess = 0;
}

int Block::get_id(){
	return id;
}

int Block::get_plane_id(){
	return plane_id;
}

int Block::get_die_id(){
	return die_id;
}

int Block::get_free_pgs(){
	return free_pgs;
}

int Block::get_dirty_pgs(){
	return dirty_pgs;
}

int Block::get_valid_pgs(){
	return valid_pgs;
}

long Block::get_erase_cnt(){
	return erase_cnt;
}

Page* Block::get_page_at(int pos){
	
	return page_ptrs[pos];
}


bool Block::remove_page(Page* page, long long time){

	if(page->get_page_stat()==0 || page->get_page_stat()==-1){
		cout<<"page is not written or already invalidated, how it can be invalidated?"<<endl;
		cout<<"page status: "<<page->get_page_stat()<<endl;
		assert(1<0);
	}
	
	page->invalidate_page();
	valid_pgs--;
	dirty_pgs++;
	waccess = time;

	return true;
}

bool Block::erase_block(long long time){

	erase_cnt++;

	for(int i=0; i<N_pages; i++){
		page_ptrs[i] = NULL;
	}

	free_pgs = N_pages;
	valid_pgs = 0;
	dirty_pgs = 0;
	t_zero = time;

	seek = 0;

	waccess = 0;

	return true;
}

bool Block::write_page(Page* page, long long time){

	if(free_pgs == 0){
		return false;
	}

	page_ptrs[seek] = page;
	page->set_page_in_block(seek);

	free_pgs--;
	valid_pgs++;
	seek++;

	if(time!=-1){
		waccess = time;
	}

	//page->write_page();
	
	return true;
}


bool Block::write_xor(uint64_t lba, Page* page, int seek, long long time){

	if(free_pgs == 0){
		return false;
	}

	page_ptrs[seek] = page;
	page->set_page_in_block(seek);

	free_pgs--;
	valid_pgs++;

	if(time!=-1){
		waccess = time;
	}

	page->write_page(lba);
	
	return true;
}


bool Block::write_page(uint64_t lba, Page* page, long long time){

	if(free_pgs == 0){
		return false;
	}

	page_ptrs[seek] = page;

	page->set_page_in_block(seek);

	free_pgs--;
	valid_pgs++;
	seek++;

	if(time!=-1){
		waccess = time;
	}

	page->write_page(lba);
	
	return true;
}

<file_sep>/ssd_config.cpp
#include "ssd_config.hh"

SSD_Config::SSD_Config(std::string configFile){

	std::ifstream in(configFile);
	if(! in.is_open()){
		std::cerr<<"ERROR: Config file "<<configFile<<" cannot be opened "<<std::endl;
		exit(1);
	}

	std::string keyword;

	while(in >> keyword){

		if(keyword == "#"){
			std::getline(in,keyword);
			continue;
		}

		if(keyword == "logFolder"){
			in >> logFolder;
			
			if(logFolder.back() != '/'){
				logFolder = logFolder + "/";
			}
			continue;
		}

		if(keyword == "traceFile"){
			in >> traceFile;
			continue;
		}

		if(keyword == "printConfig"){
			in >> printConfig;
			continue;
		}

		if(keyword == "NUM_DIES"){
			in >> N_dies;
			continue;
		}

		if(keyword == "NUM_PLANES"){
			in >> N_planes;
			continue;
		}

		if(keyword == "NUM_BLOCKS"){
			in >> N_blocks;
			continue;	
		}

		if(keyword == "NUM_PAGES"){
			in >> N_pages;
			continue;
		}

		if(keyword == "OVER_PROV"){
			in >> O_prov;
			continue;
		}

		if(keyword == "CAPACITY"){
			in >> Capacity;
			continue;
		}

		if(keyword == "PAGE_WRITE_DELAY"){
			in >> w_delay;
			continue;
		}

		if(keyword == "PAGE_READ_DELAY"){
			in >> r_delay;
			continue;
		}

		if(keyword == "BLOCK_ERASE_DELAY"){
			in >> e_delay;
			continue;
		}

		if(keyword == "DELAY_CONTROLLER_TO_REGISTER"){
			in >> ctor_delay;
			continue;
		}

		if(keyword == "RANDOM_SEED"){
			in >> seed;
			continue;
		}

		std::getline(in,keyword);
	}

	Nlp = N_pages * N_blocks * N_planes * N_dies;

	//std::cout<<logFolder<<std::endl;
	mkdir(logFolder.c_str(),0777);		

	//init_SSD(configFile);
	if(printConfig){
		cout<<"*****************************"<<endl;
		cout<<"Using trace file:"<<traceFile<<endl;
		cout<<"Using log folder:"<<logFolder<<endl;
		cout<<"die per ssd:"<<N_dies<<endl;
		cout<<"planes per die:"<<N_planes<<endl;
		cout<<"blocks per plane:"<<N_blocks<<endl;
		cout<<"pages per block:"<<N_pages<<endl;
		cout<<"Over Provisioning:"<<O_prov<<"%"<<endl;
		cout<<"Spare Factor: "<<float(1-float(N_blocks)/(float(N_blocks * O_prov/100) + N_blocks))<<endl;
		cout<<"SSD Size: "<<(long long)(Nlp * 4096)/(long long)(1024*1024*1024)<<"GB"<<endl;
		cout<<"*****************************"<<endl;
		cout<<endl;

	}

	in.close();

	copyConfigFile(configFile, logFolder);

}

bool SSD_Config::checkConfig() const{

	bool check = true;

	if(logFolder == ""){
		cout<<"WARNING: logFolder was not set! "<<endl;
		check = false;
	}

	if(traceFile == ""){
		cout<<"WARNING: tracefile was not set! "<<endl;
		check = false;
	}

	if(N_dies == 0){
		cout<<"ERROR: Number of dies is not set or is set to 0"<<endl;
		check = false;
	}

	if(N_planes == 0){
		cout<<"ERROR: Number of planes is not set or equals to 0"<<endl;
		check = false;
	}

	if(N_blocks == 0){
		cout<<"ERROR: Number of blocks per plane is not set or equals to 0!"<<endl;
		check = false;	
	}

	if(N_pages == 0){
		cout<<"ERROR: Number of pages per block is not set or equals to 0"<<endl;
		check = false;
	}

	if(O_prov == 0){
		cout<<"ERROR: Over-provisioning is not set or equals to 0"<<endl;
		check = false;
	}

	if(Capacity == 0){
		cout<<"ERROR: capacity of the ssd is not set! or equals to 0 "<<endl;
		check = false;
	}

	if(w_delay == 0){
		cout<<"ERROR: write delay is not set!"<<endl;
		check = false;
	}

	if(r_delay == 0){
		cout<<"ERROR: read delay is not set!"<<endl;
		check = false;
	}

	if(e_delay == 0){
		cout<<"ERROR: erase delay is not set!"<<endl;
		check = false;
	}

	if(ctor_delay == 0){
		cout<<"ERROR: channel to register delay is not set! "<<endl;
		check = false;
	}

	if(seed == 0){
		cout<<"ERROR: Random Seed is not set! "<<endl;
		check = false;
	}


	if(!check){
		cout<<endl;
	}

	return check;
}

//SSD * SSD_Config::init_SSD(string configFile) const{

//	SSD *ssd = NULL;

//	ssd = new SSD();

//	return ssd;
//}


void SSD_Config::copyConfigFile(std::string configFile, std::string logFolder){

	std::ifstream src(configFile, std::ios::binary);

	std::ofstream dst(logFolder + "run.conf",std::ios::binary);

	dst << src.rdbuf();

	src.close();
	dst.close();

}

<file_sep>/ssd.hh
#ifndef SSD_H
#define SSD_H

#include<iostream>
#include<vector>
#include<map>
#include<assert.h>
#include<list>
#include<bitset>
#include<functional>
#include<algorithm>

#include "ssd_config.hh"
#include "die.hh"
#include "plane.hh"
#include "block.hh"
#include "page.hh"

using namespace std;
class SSD_Config;
class Die;
class Page;

class SSD{

private:

	int N_pages=0;
	int N_blocks=0;
	int N_planes=0;
	int N_dies=0;

	int uw=0;
	int ur=0;
	int gcw=0;
	int iw=0;
	int xor_w=0;
	int reads_blocked=0;

	int t_di = 0;
	int t_pln = 0;
	int t_blk = 0;

	int read_missed=0;
	int read_bt_gc_flag_zero = 0;

	uint64_t t_page = 0;

	int op_blocks = 0;
	// For GC operation
	int High_water_mark = 0;
	int Low_water_mark = 0;

	bool invalid_page;

	Die *xor_die=NULL;

	// Data Structures for the corresponding SSD architecture
	list<Die*>ssd_die;
	map<Die*, list<Plane*> >die_plane;
	map<Plane*, list<Block*> >plane_blk;
	map<Block*, list<Page*> >block_page;

	struct iops{
		int write;
		int read;
		int blocked;
	};

	map<Die*, iops> gc_flag;
	list<Block*>tmp_blks;

public:


	struct reverse_ptr{
		Die *die;
		Plane *plane;
		Block *block;
		Page *page;
	};

	map<uint64_t, reverse_ptr>lpn_ppn;

	struct write_loc{
		Die *die;
		Plane *plane;
		Block *block;
		Page *page;
	};

	//template <class any>
	SSD(const SSD_Config &config);
	virtual ~SSD();			// Destructor to clean the Data Structure
	bool external_write(uint64_t lpn, int IOSize, double time);
	bool external_read(uint64_t lpn, int IOSize, double time);
	bool gc_flag_set(Die* di_id);
	bool update_gc_flag();
	void get_write_loc(write_loc *loc, Die* die_inv, Plane* pln_inv);

	int random_gen(int min, int max);
	bool xoring_block(Block* blk, double time);
	bool check_distance(int dis1, int dis2, int dis3);

	void garbage_collect(Die* die,Plane* plane, long long time);
	virtual bool internal_write(Die* die,uint64_t lpn, Plane* plane, long long time);
	void stat();
	void debug(Plane* plane);
};

#endif
