// File: narges64[P]SIMBA/ssd.cpp
// Function: print_statistics(ssd_info*, int)
void print_statistics(ssd_info *ssd, int app){

	fprintf(ssd->statisticfile, "======== Application %d , time %lld ============ \n", app, ssd->total_execution_time);

	fprintf(ssd->statisticfile, "request read RT avg %lld us , var %lld ms2 , count %lld , max %lld us\n", 
									ssd->stats->read_RT.get_average(), ssd->stats->read_RT.get_variance(), 
									ssd->stats->read_RT.get_count() , ssd->stats->read_RT.get_max());

	fprintf(ssd->statisticfile, "request write RT avg %lld us , var %lld ms2, count %lld , max %lld us \n", 
									ssd->stats->write_RT.get_average(), ssd->stats->write_RT.get_variance(), 
									ssd->stats->write_RT.get_count() , ssd->stats->write_RT.get_max());
	
	fprintf(ssd->statisticfile, "read IOPS and BW [%d]: %f , %f  \n", app, ssd->stats->read_throughput.get_IOPS() , ssd->stats->read_throughput.get_BW());
	fprintf(ssd->statisticfile, "write IOPS and BW [%d]: %f , %f  \n", app, ssd->stats->write_throughput.get_IOPS() , ssd->stats->write_throughput.get_BW());

	fprintf(ssd->statisticfile,"erase: ( %lld )\n", ssd->stats->total_flash_erase_count);
	fprintf(ssd->statisticfile,"total gc move count: %d \n", ssd->stats->gc_moved_page);
	fprintf(ssd->statisticfile, "buffer read hit %d , write hit %d , gc buffer read hit %d , write hit %d \n ", 
								ssd->dram->buffer->read_hit , ssd->dram->buffer->write_hit , 
								ssd->dram->gc_buffer->read_hit , ssd->dram->gc_buffer->write_hit); 

	fprintf(ssd->statisticfile, "flash program count %d , WAF %f\n" , ssd->stats->flash_prog_count , (ssd->stats->flash_prog_count)/(double)(ssd->stats->flash_prog_count - ssd->stats->gc_moved_page));  

	fprintf(ssd->statisticfile, "========================\n");

	ssd->stats->flash_erase_count = 0;

	// Print lun statistic output
	int chan,lun = 0;
	/*


	fprintf(ssd->statisticfile, "\nlun IOPS \n");
	for (chan = 0; chan < ssd->parameter->channel_number; chan++){
		for (lun = 0; lun < ssd->channel_head[chan]->lun_num; lun++){
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_read_throughput.get_IOPS());
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_write_throughput.get_IOPS());
			fprintf(ssd->statisticfile, "%d\t", (int)ssd->channel_head[chan]->lun_head[lun]->stat_rw_throughput.get_IOPS());
		}
		fprintf(ssd->statisticfile, "\n");
	}

	fprintf(ssd->statisticfile, "\nlun BW  (MB/s) \n");
	for (chan = 0; chan < ssd->parameter->channel_number; chan++){
		for (lun = 0; lun < ssd->channel_head[chan]->lun_num; lun++){
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_read_throughput.get_BW());
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_write_throughput.get_BW());
			fprintf(ssd->statisticfile, "%d\t", (int)ssd->channel_head[chan]->lun_head[lun]->stat_rw_throughput.get_BW());
		}
		fprintf(ssd->statisticfile, "\n");
	}

	fprintf(ssd->statisticfile, "\nlun noop IOPS \n");
	for (chan = 0; chan < ssd->parameter->channel_number; chan++){
		for (lun = 0; lun < ssd->channel_head[chan]->lun_num; lun++){
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_read_throughput.get_noop_IOPS());
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_write_throughput.get_noop_IOPS());
			fprintf(ssd->statisticfile, "%d\t", (int)ssd->channel_head[chan]->lun_head[lun]->stat_rw_throughput.get_noop_IOPS());
		}
		fprintf(ssd->statisticfile, "\n");
	}


	fprintf(ssd->statisticfile, "\nlun noop BW (MB/s) \n");
	for (chan = 0; chan < ssd->parameter->channel_number; chan++){
		for (lun = 0; lun < ssd->channel_head[chan]->lun_num; lun++){
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_read_throughput.get_noop_BW());
			fprintf(ssd->statisticfile, "%d,", (int)ssd->channel_head[chan]->lun_head[lun]->stat_write_throughput.get_noop_BW());
			fprintf(ssd->statisticfile, "%d\t", (int)ssd->channel_head[chan]->lun_head[lun]->stat_rw_throughput.get_noop_BW());
		}
		fprintf(ssd->statisticfile, "\n");
	}
	*/

	fprintf(ssd->statisticfile, "\nlun erase count \n");
	for (chan = 0; chan < ssd->parameter->channel_number; chan++){
		for (lun = 0; lun < ssd->channel_head[chan]->lun_num; lun++){
			fprintf(ssd->statisticfile, "%d\t", ssd->channel_head[chan]->lun_head[lun]->erase_count);
		}
		fprintf(ssd->statisticfile, "\n");
	}

	fprintf(ssd->statisticfile, "\nplanes erase number: \n");
	for(int i=0;i<ssd->parameter->channel_number;i++){
		for (int j = 0; j < ssd->parameter->lun_channel[i]; j++){
			for(int l=0;l<ssd->parameter->plane_lun;l++)
			{
				int plane_erase = ssd->channel_head[i]->lun_head[j]->plane_head[l]->erase_count;
				fprintf(ssd->statisticfile,"(%d,%d)",l, plane_erase);
			}
			fprintf(ssd->statisticfile, "\t");
		}
		fprintf(ssd->statisticfile, "\n");
	}

}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movl -0xc(%rbp), %edx
movq -0x8(%rbp), %rax
movq 0x28(%rax), %rcx
leaq 0x37d8(%rip), %rsi      # 0xfe44
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rax
movq %rax, -0x98(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x8, %rdi
callq 0xe540
movq %rax, -0x90(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x8, %rdi
callq 0xe580
movq %rax, -0x88(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x8, %rdi
callq 0xe600
movl %eax, -0x7c(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x8, %rdi
callq 0xe610
movq -0x98(%rbp), %rdi
movq -0x90(%rbp), %rdx
movq -0x88(%rbp), %rcx
movl -0x7c(%rbp), %r8d
movq %rax, %r9
leaq 0x3771(%rip), %rsi      # 0xfe77
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rax
movq %rax, -0x78(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x30, %rdi
callq 0xe540
movq %rax, -0x70(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x30, %rdi
callq 0xe580
movq %rax, -0x68(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x30, %rdi
callq 0xe600
movl %eax, -0x5c(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x30, %rdi
callq 0xe610
movq -0x78(%rbp), %rdi
movq -0x70(%rbp), %rdx
movq -0x68(%rbp), %rcx
movl -0x5c(%rbp), %r8d
movq %rax, %r9
leaq 0x3730(%rip), %rsi      # 0xfebe
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rax
movq %rax, -0x58(%rbp)
movl -0xc(%rbp), %eax
movl %eax, -0x4c(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x190, %rdi            # imm = 0x190
callq 0xe630
movsd %xmm0, -0x48(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x190, %rdi            # imm = 0x190
callq 0xe680
movq -0x58(%rbp), %rdi
movl -0x4c(%rbp), %edx
movaps %xmm0, %xmm1
movsd -0x48(%rbp), %xmm0
leaq 0x3716(%rip), %rsi      # 0xff06
movb $0x2, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rax
movq %rax, -0x40(%rbp)
movl -0xc(%rbp), %eax
movl %eax, -0x34(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
callq 0xe630
movsd %xmm0, -0x30(%rbp)
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
callq 0xe680
movq -0x40(%rbp), %rdi
movl -0x34(%rbp), %edx
movaps %xmm0, %xmm1
movsd -0x30(%rbp), %xmm0
leaq 0x36d6(%rip), %rsi      # 0xff28
movb $0x2, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rax
movq 0xa0(%rax), %rdx
leaq 0x36d1(%rip), %rsi      # 0xff4b
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rax
movl 0xc8(%rax), %edx
leaq 0x36bb(%rip), %rsi      # 0xff5c
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movq -0x8(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x18(%rax), %rax
movl (%rax), %edx
movq -0x8(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x18(%rax), %rax
movl 0x4(%rax), %ecx
movq -0x8(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x20(%rax), %rax
movl (%rax), %r8d
movq -0x8(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x20(%rax), %rax
movl 0x4(%rax), %r9d
leaq 0x3683(%rip), %rsi      # 0xff76
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rax
movq 0x88(%rax), %rdx
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rax
cvtsi2sdq 0x88(%rax), %xmm0
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rax
movq 0x88(%rax), %rax
movq -0x8(%rbp), %rcx
movq 0x98(%rcx), %rcx
movslq 0xc8(%rcx), %rcx
subq %rcx, %rax
cvtsi2sd %rax, %xmm1
divsd %xmm1, %xmm0
leaq 0x3663(%rip), %rsi      # 0xffc2
movb $0x1, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
leaq 0x366e(%rip), %rsi      # 0xffe3
movb $0x0, %al
callq 0x21f0
movq -0x8(%rbp), %rax
movq 0x98(%rax), %rax
movq $0x0, 0x98(%rax)
movl $0x0, -0x14(%rbp)
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
leaq 0x3655(%rip), %rsi      # 0xfffd
movb $0x0, %al
callq 0x21f0
movl $0x0, -0x10(%rbp)
movl -0x10(%rbp), %eax
movq -0x8(%rbp), %rcx
movq 0x58(%rcx), %rcx
cmpl 0x98(%rcx), %eax
jae 0xca55
movl $0x0, -0x14(%rbp)
movl -0x14(%rbp), %eax
movq -0x8(%rbp), %rcx
movq 0x90(%rcx), %rcx
movslq -0x10(%rbp), %rdx
movq (%rcx,%rdx,8), %rcx
cmpl (%rcx), %eax
jge 0xca31
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movq -0x8(%rbp), %rax
movq 0x90(%rax), %rax
movslq -0x10(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x50(%rax), %rax
movslq -0x14(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movl 0x8(%rax), %edx
leaq 0x35f1(%rip), %rsi      # 0x10010
movb $0x0, %al
callq 0x21f0
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0xc9d4
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
leaq 0x34e6(%rip), %rsi      # 0xff26
movb $0x0, %al
callq 0x21f0
movl -0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x10(%rbp)
jmp 0xc9b6
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
leaq 0x35b0(%rip), %rsi      # 0x10014
movb $0x0, %al
callq 0x21f0
movl $0x0, -0x18(%rbp)
movl -0x18(%rbp), %eax
movq -0x8(%rbp), %rcx
movq 0x58(%rcx), %rcx
cmpl 0x98(%rcx), %eax
jae 0xcb66
movl $0x0, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
movq -0x8(%rbp), %rcx
movq 0x58(%rcx), %rcx
movslq -0x18(%rbp), %rdx
cmpl 0x9c(%rcx,%rdx,4), %eax
jae 0xcb42
movl $0x0, -0x20(%rbp)
movl -0x20(%rbp), %eax
movq -0x8(%rbp), %rcx
movq 0x58(%rcx), %rcx
cmpl 0x22c(%rcx), %eax
jae 0xcb1e
movq -0x8(%rbp), %rax
movq 0x90(%rax), %rax
movslq -0x18(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x50(%rax), %rax
movslq -0x1c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq (%rax), %rax
movslq -0x20(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x30(%rax), %rax
movl %eax, -0x24(%rbp)
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
movl -0x20(%rbp), %edx
movl -0x24(%rbp), %ecx
leaq 0x3520(%rip), %rsi      # 0x1002c
movb $0x0, %al
callq 0x21f0
movl -0x20(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x20(%rbp)
jmp 0xcab3
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
leaq 0x32a9(%rip), %rsi      # 0xfdd6
movb $0x0, %al
callq 0x21f0
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0xca90
movq -0x8(%rbp), %rax
movq 0x50(%rax), %rdi
leaq 0x33d5(%rip), %rsi      # 0xff26
movb $0x0, %al
callq 0x21f0
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
jmp 0xca72
addq $0xa0, %rsp
popq %rbp
retq
nop