// File: /workspace/github_cpp_makefile_star2_O1/CMU-SAFARI[P]MQSim/src/host/IO_Flow_Trace_Based.cpp
// Function: Host_Components::IO_Flow_Trace_Based::Get_statistics(Utils::Workload_Statistics&, unsigned long (*)(unsigned long), unsigned long (*)(unsigned long))
void IO_Flow_Trace_Based::Get_statistics(Utils::Workload_Statistics &stats, LPA_type (*Convert_host_logical_address_to_device_address)(LHA_type lha),
										 page_status_type (*Find_NVM_subunit_access_bitmap)(LHA_type lha))
{
	stats.Type = Utils::Workload_Type::TRACE_BASED;
	stats.Stream_id = io_queue_id - 1; //In MQSim, there is a simple relation between stream id and the io_queue_id of NVMe
	stats.Min_LHA = start_lsa_on_device;
	stats.Max_LHA = end_lsa_on_device;
	for (int i = 0; i < MAX_ARRIVAL_TIME_HISTOGRAM + 1; i++)
	{
		stats.Write_arrival_time.push_back(0);
		stats.Read_arrival_time.push_back(0);
	}
	for (int i = 0; i < MAX_REQSIZE_HISTOGRAM_ITEMS + 1; i++)
	{
		stats.Write_size_histogram.push_back(0);
		stats.Read_size_histogram.push_back(0);
	}
	stats.Total_generated_requests = 0;
	stats.Total_accessed_lbas = 0;

	std::ifstream trace_file_temp;
	trace_file_temp.open(trace_file_path, std::ios::in);
	if (!trace_file_temp.is_open())
	{
		PRINT_ERROR("Error while opening the input trace file!")
	}

	std::string trace_line;
	char *pEnd;
	sim_time_type last_request_arrival_time = 0;
	sim_time_type sum_inter_arrival = 0;
	uint64_t sum_request_size = 0;
	std::vector<std::string> line_splitted;
	while (std::getline(trace_file_temp, trace_line))
	{
		Utils::Helper_Functions::Remove_cr(trace_line);
		line_splitted.clear();
		Utils::Helper_Functions::Tokenize(trace_line, ASCIILineDelimiter, line_splitted);
		if (line_splitted.size() != ASCIIItemsPerLine)
		{
			break;
		}
		sim_time_type prev_time = last_request_arrival_time;
		last_request_arrival_time = std::strtoull(line_splitted[ASCIITraceTimeColumn].c_str(), &pEnd, 10);
		if (last_request_arrival_time < prev_time)
		{
			PRINT_ERROR("Unexpected request arrival time: " << last_request_arrival_time << "\nMQSim expects request arrival times to be monotonic increasing in the input trace!")
		}
		sim_time_type diff = (last_request_arrival_time - prev_time) / 1000; //The arrival rate histogram is stored in the microsecond unit
		sum_inter_arrival += last_request_arrival_time - prev_time;

		unsigned int LBA_count = std::strtoul(line_splitted[ASCIITraceSizeColumn].c_str(), &pEnd, 0);
		sum_request_size += LBA_count;
		LHA_type start_LBA = std::strtoull(line_splitted[ASCIITraceAddressColumn].c_str(), &pEnd, 0);
		if (start_LBA <= (end_lsa_on_device - start_lsa_on_device))
		{
			start_LBA += start_lsa_on_device;
		}
		else
		{
			start_LBA = start_lsa_on_device + start_LBA % (end_lsa_on_device - start_lsa_on_device);
		}
		LHA_type end_LBA = start_LBA + LBA_count - 1;
		if (end_LBA > end_lsa_on_device)
		{
			end_LBA = start_lsa_on_device + (end_LBA - end_lsa_on_device) - 1;
		}

		//Address access pattern statistics
		while (start_LBA <= end_LBA)
		{
			LPA_type device_address = Convert_host_logical_address_to_device_address(start_LBA);
			page_status_type access_status_bitmap = Find_NVM_subunit_access_bitmap(start_LBA);
			if (line_splitted[ASCIITraceTypeColumn].compare(ASCIITraceWriteCode) == 0)
			{
				if (stats.Write_address_access_pattern.find(device_address) == stats.Write_address_access_pattern.end())
				{
					Utils::Address_Histogram_Unit hist;
					hist.Access_count = 1;
					hist.Accessed_sub_units = access_status_bitmap;
					stats.Write_address_access_pattern[device_address] = hist;
				}
				else
				{
					stats.Write_address_access_pattern[device_address].Access_count = stats.Write_address_access_pattern[device_address].Access_count + 1;
					stats.Write_address_access_pattern[device_address].Accessed_sub_units = stats.Write_address_access_pattern[device_address].Accessed_sub_units | access_status_bitmap;
				}

				if (stats.Read_address_access_pattern.find(device_address) != stats.Read_address_access_pattern.end())
				{
					stats.Write_read_shared_addresses.insert(device_address);
				}
			}
			else
			{
				if (stats.Read_address_access_pattern.find(device_address) == stats.Read_address_access_pattern.end())
				{
					Utils::Address_Histogram_Unit hist;
					hist.Access_count = 1;
					hist.Accessed_sub_units = access_status_bitmap;
					stats.Read_address_access_pattern[device_address] = hist;
				}
				else
				{
					stats.Read_address_access_pattern[device_address].Access_count = stats.Read_address_access_pattern[device_address].Access_count + 1;
					stats.Read_address_access_pattern[device_address].Accessed_sub_units = stats.Read_address_access_pattern[device_address].Accessed_sub_units | access_status_bitmap;
				}

				if (stats.Write_address_access_pattern.find(device_address) != stats.Write_address_access_pattern.end())
				{
					stats.Write_read_shared_addresses.insert(device_address);
				}
			}
			stats.Total_accessed_lbas++;
			start_LBA++;
			if (start_LBA > end_lsa_on_device)
			{
				start_LBA = start_lsa_on_device;
			}
		}

		//Request size statistics
		if (line_splitted[ASCIITraceTypeColumn].compare(ASCIITraceWriteCode) == 0)
		{
			if (diff < MAX_ARRIVAL_TIME_HISTOGRAM)
			{
				stats.Write_arrival_time[diff]++;
			}
			else
			{
				stats.Write_arrival_time[MAX_ARRIVAL_TIME_HISTOGRAM]++;
			}

			if (LBA_count < MAX_REQSIZE_HISTOGRAM_ITEMS)
			{
				stats.Write_size_histogram[LBA_count]++;
			}
			else
			{
				stats.Write_size_histogram[MAX_REQSIZE_HISTOGRAM_ITEMS]++;
			}
		}
		else
		{
			if (diff < MAX_ARRIVAL_TIME_HISTOGRAM)
			{
				stats.Read_arrival_time[diff]++;
			}
			else
			{
				stats.Read_arrival_time[MAX_ARRIVAL_TIME_HISTOGRAM]++;
			}

			if (LBA_count < MAX_REQSIZE_HISTOGRAM_ITEMS)
			{
				stats.Read_size_histogram[LBA_count]++;
			}
			else
			{
				stats.Read_size_histogram[(unsigned int)MAX_REQSIZE_HISTOGRAM_ITEMS]++;
			}
		}
		stats.Total_generated_requests++;
	}
	trace_file_temp.close();
	stats.Average_request_size_sector = (unsigned int)(sum_request_size / stats.Total_generated_requests);
	stats.Average_inter_arrival_time_nano_sec = sum_inter_arrival / stats.Total_generated_requests;

	stats.Initial_occupancy_ratio = initial_occupancy_ratio;
	stats.Replay_no = total_replay_no;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2c8, %rsp            # imm = 0x2C8
movq %rcx, 0xa8(%rsp)
movq %rdx, 0xb0(%rsp)
movq %rsi, %rbx
movl $0x1, (%rsi)
movl 0xb0(%rdi), %eax
decl %eax
movw %ax, 0x4(%rsi)
movq %rdi, 0x20(%rsp)
movups 0x68(%rdi), %xmm0
movups %xmm0, 0x130(%rsi)
leaq 0x28(%rsi), %r15
leaq 0x40(%rsi), %r12
movl $0xf4241, %ebp          # imm = 0xF4241
leaq 0xc0(%rsp), %r13
movq $0x0, 0xc0(%rsp)
movq 0x30(%rbx), %rsi
cmpq 0x38(%rbx), %rsi
je 0x23506
movq $0x0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x30(%rbx)
jmp 0x23511
movq %r15, %rdi
movq %r13, %rdx
callq 0x2418c
movq $0x0, 0xc0(%rsp)
movq 0x48(%rbx), %rsi
cmpq 0x50(%rbx), %rsi
je 0x23538
movq $0x0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x48(%rbx)
jmp 0x23543
movq %r12, %rdi
movq %r13, %rdx
callq 0x2418c
decl %ebp
jne 0x234df
leaq 0x180(%rbx), %r15
leaq 0x198(%rbx), %r12
movl $0x401, %ebp            # imm = 0x401
leaq 0xc0(%rsp), %r13
movl $0x0, 0xc0(%rsp)
movq 0x188(%rbx), %rsi
cmpq 0x190(%rbx), %rsi
je 0x23590
movl $0x0, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x188(%rbx)
jmp 0x2359b
movq %r15, %rdi
movq %r13, %rdx
callq 0x242c2
movl $0x0, 0xc0(%rsp)
movq 0x1a0(%rbx), %rsi
cmpq 0x1a8(%rbx), %rsi
je 0x235c9
movl $0x0, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x1a0(%rbx)
jmp 0x235d4
movq %r12, %rdi
movq %r13, %rdx
callq 0x242c2
decl %ebp
jne 0x23562
xorl %eax, %eax
movl %eax, 0x14(%rbx)
movq %rbx, 0x10(%rsp)
movl %eax, 0x68(%rbx)
leaq 0xc0(%rsp), %r14
movq %r14, %rdi
callq 0x73f0
movq 0x20(%rsp), %rax
leaq 0x478(%rax), %rsi
movq %r14, %rdi
movl $0x8, %edx
callq 0x7330
leaq 0x138(%rsp), %rdi
callq 0x70e0
testb %al, %al
je 0x23cd1
leaq 0x90(%rsp), %rax
movq %rax, -0x10(%rax)
xorl %ecx, %ecx
movq %rcx, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x40(%rsp), %rax
movq %rcx, 0x10(%rax)
xorps %xmm0, %xmm0
movaps %xmm0, (%rax)
movq 0x10(%rsp), %rcx
leaq 0xc0(%rcx), %rax
movq %rax, 0x28(%rsp)
leaq 0xc8(%rcx), %r14
leaq 0x98(%rcx), %r15
leaq 0x90(%rcx), %rax
movq %rax, 0x18(%rsp)
leaq 0xf0(%rcx), %rax
movq %rax, 0xa0(%rsp)
leaq 0x78(%rsp), %r13
movq $0x0, 0x68(%rsp)
movq $0x0, 0x38(%rsp)
movq $0x0, 0x58(%rsp)
movq 0x58(%rsp), %rbx
movq 0xc0(%rsp), %rax
movq -0x18(%rax), %rdi
leaq 0xc0(%rsp), %rax
addq %rax, %rdi
movl $0xa, %esi
callq 0x7380
movsbl %al, %edx
leaq 0xc0(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x7660
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
testb $0x5, 0x20(%rax,%rcx)
jne 0x23bd2
movq 0x80(%rsp), %rax
movq 0x88(%rsp), %rsi
cmpb $0xd, -0x1(%rax,%rsi)
jne 0x2371d
decq %rsi
movl $0x1, %edx
leaq 0x80(%rsp), %rdi
callq 0x70d0
movq 0x40(%rsp), %r12
movq 0x48(%rsp), %rbp
cmpq %r12, %rbp
je 0x23754
movq %r12, %r13
movq (%r13), %rdi
addq $0x10, %r13
cmpq %r13, %rdi
je 0x23741
callq 0x7370
addq $0x10, %r13
cmpq %rbp, %r13
jne 0x2372f
movq %r12, 0x48(%rsp)
leaq 0x78(%rsp), %r13
leaq 0x80(%rsp), %rdi
movl $0x20, %esi
leaq 0x40(%rsp), %rdx
callq 0x23db6
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
subq %rax, %rcx
cmpq $0xa0, %rcx
jne 0x23bd2
movq (%rax), %rdi
movq %r13, %rsi
movl $0xa, %edx
callq 0x74a0
movq %rax, 0x58(%rsp)
subq %rbx, %rax
jb 0x23c63
movq %rax, 0x70(%rsp)
shrq $0x3, %rax
movabsq $0x20c49ba5e353f7cf, %rcx # imm = 0x20C49BA5E353F7CF
mulq %rcx
movq %rdx, %rbx
movq 0x40(%rsp), %rax
movq 0x60(%rax), %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x7140
movq %rax, 0x60(%rsp)
movq 0x40(%rsp), %rax
movq 0x40(%rax), %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x74a0
movq %rax, %r12
movq 0x20(%rsp), %rax
movq 0x68(%rax), %rcx
movq 0x70(%rax), %rsi
movq %rsi, %rdi
subq %rcx, %rdi
cmpq %rdi, %r12
jbe 0x2380d
movq %r12, %rax
xorl %edx, %edx
divq %rdi
movq %rdx, %r12
addq %rcx, %r12
movl 0x60(%rsp), %edi
leaq (%rdi,%r12), %rax
decq %rax
movq %rsi, %rdx
notq %rdx
addq %rdx, %rcx
cmpq %rsi, %rax
movl $0x0, %eax
cmovbeq %rax, %rcx
movq %rdi, 0x30(%rsp)
leaq (%rdi,%r12), %rax
addq %rcx, %rax
decq %rax
movq %rax, 0xb8(%rsp)
cmpq %rax, %r12
ja 0x23aef
movq %r12, %rdi
callq *0xb0(%rsp)
movq %rax, 0x8(%rsp)
movq %r12, %rdi
callq *0xa8(%rsp)
movq %rax, %rbp
movq 0x40(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x34efd(%rip), %rsi     # 0x58779
callq 0x7120
testl %eax, %eax
je 0x2392f
movq 0x10(%rsp), %rax
movq 0xd0(%rax), %rcx
movq %r14, %rax
testq %rcx, %rcx
je 0x238bd
movq 0x8(%rsp), %rdx
movq %r14, %rax
xorl %esi, %esi
cmpq %rdx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x238a5
movq %r14, %rcx
cmpq %r14, %rax
je 0x238d5
movq 0x8(%rsp), %rcx
cmpq 0x20(%rax), %rcx
cmovbq %r14, %rax
movq %rax, %rcx
cmpq %r14, %rcx
je 0x239d5
movq 0x28(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
movl (%rax), %r13d
movq 0x28(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
incl %r13d
movl %r13d, (%rax)
movq 0x28(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
movq 0x8(%rax), %r13
movq 0x28(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
orq %r13, %rbp
jmp 0x239ea
movq 0x10(%rsp), %rax
movq 0xa0(%rax), %rcx
movq %r15, %rax
testq %rcx, %rcx
je 0x23963
movq 0x8(%rsp), %rdx
movq %r15, %rax
xorl %esi, %esi
cmpq %rdx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x2394b
movq %r15, %rcx
cmpq %r15, %rax
je 0x2397b
movq 0x8(%rsp), %rcx
cmpq 0x20(%rax), %rcx
cmovbq %r15, %rax
movq %rax, %rcx
cmpq %r15, %rcx
je 0x23a41
movq 0x18(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
movl (%rax), %r13d
movq 0x18(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
incl %r13d
movl %r13d, (%rax)
movq 0x18(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
movq 0x8(%rax), %r13
movq 0x18(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
orq %r13, %rbp
jmp 0x23a56
movq 0x28(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
movl $0x1, (%rax)
movq %rbp, 0x8(%rax)
movq 0x10(%rsp), %rax
movq 0xa0(%rax), %rcx
movq %r15, %rax
testq %rcx, %rcx
je 0x23a22
movq 0x8(%rsp), %rdx
movq %r15, %rax
xorl %esi, %esi
cmpq %rdx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x23a0a
movq %r15, %rcx
cmpq %r15, %rax
je 0x23a3a
movq 0x8(%rsp), %rcx
cmpq 0x20(%rax), %rcx
cmovbq %r15, %rax
movq %rax, %rcx
cmpq %r15, %rcx
jne 0x23aab
jmp 0x23abd
movq 0x18(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x23ec4
movl $0x1, (%rax)
movq %rbp, 0x8(%rax)
movq 0x10(%rsp), %rax
movq 0xd0(%rax), %rcx
movq %r14, %rax
testq %rcx, %rcx
je 0x23a8e
movq 0x8(%rsp), %rdx
movq %r14, %rax
xorl %esi, %esi
cmpq %rdx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x23a76
movq %r14, %rcx
cmpq %r14, %rax
je 0x23aa6
movq 0x8(%rsp), %rcx
cmpq 0x20(%rax), %rcx
cmovbq %r14, %rax
movq %rax, %rcx
cmpq %r14, %rcx
je 0x23abd
movq 0xa0(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x245a0
movq 0x10(%rsp), %rax
incl 0x68(%rax)
incq %r12
movq 0x20(%rsp), %rax
cmpq 0x70(%rax), %r12
jbe 0x23adc
movq 0x20(%rsp), %rax
movq 0x68(%rax), %r12
cmpq 0xb8(%rsp), %r12
leaq 0x78(%rsp), %r13
jbe 0x23850
shrq $0x4, %rbx
movq 0x40(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x34c76(%rip), %rsi     # 0x58779
callq 0x7120
shlq $0x3, %rbx
testl %eax, %eax
je 0x23b4a
movq 0x70(%rsp), %rsi
cmpq $0x3b9aca00, %rsi       # imm = 0x3B9ACA00
movq 0x10(%rsp), %rdi
movq 0x40(%rdi), %rax
movl $0x7a1200, %ecx         # imm = 0x7A1200
cmovaeq %rcx, %rbx
incq (%rax,%rbx)
testl $0xfffffc00, 0x60(%rsp) # imm = 0xFFFFFC00
movq 0x38(%rsp), %rcx
je 0x23b91
movq 0x198(%rdi), %rax
jmp 0x23b82
movq 0x70(%rsp), %rsi
cmpq $0x3b9aca00, %rsi       # imm = 0x3B9ACA00
movq 0x10(%rsp), %rdi
movq 0x28(%rdi), %rax
movl $0x7a1200, %ecx         # imm = 0x7A1200
cmovaeq %rcx, %rbx
incq (%rax,%rbx)
testl $0xfffffc00, 0x60(%rsp) # imm = 0xFFFFFC00
movq 0x38(%rsp), %rcx
je 0x23ba7
movq 0x180(%rdi), %rax
movl $0x1000, %edx           # imm = 0x1000
addq %rdx, %rax
movq 0x30(%rsp), %rdx
jmp 0x23bbb
movq 0x30(%rsp), %rdx
leaq (,%rdx,4), %rax
addq 0x198(%rdi), %rax
jmp 0x23bbb
movq 0x30(%rsp), %rdx
leaq (,%rdx,4), %rax
addq 0x180(%rdi), %rax
addq %rsi, %rcx
movq %rcx, 0x38(%rsp)
incl (%rax)
addq %rdx, 0x68(%rsp)
incl 0x14(%rdi)
jmp 0x236a1
leaq 0xc0(%rsp), %rdi
callq 0x70b0
movq 0x10(%rsp), %rsi
movl 0x14(%rsi), %ecx
movq 0x68(%rsp), %rax
xorl %edx, %edx
divq %rcx
movl %eax, 0x178(%rsi)
movq 0x38(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rax, 0x168(%rsi)
movq 0x20(%rsp), %rax
movsd 0x40(%rax), %xmm0
movsd %xmm0, 0x8(%rsi)
movl 0x6a0(%rax), %eax
movl %eax, 0x10(%rsi)
leaq 0x40(%rsp), %rdi
callq 0xaf22
movq 0x80(%rsp), %rdi
leaq 0x90(%rsp), %rax
cmpq %rax, %rdi
je 0x23c44
callq 0x7370
leaq 0xc0(%rsp), %rdi
callq 0x7100
addq $0x2c8, %rsp            # imm = 0x2C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x4b386(%rip), %rdi     # 0x6eff0
leaq 0x32937(%rip), %rsi     # 0x565a8
movl $0x6, %edx
callq 0x7400
movq 0x4b36e(%rip), %rdi     # 0x6eff0
leaq 0x341af(%rip), %rsi     # 0x57e38
movl $0x21, %edx
callq 0x7400
movq 0x4b356(%rip), %rdi     # 0x6eff0
movq 0x58(%rsp), %rsi
callq 0x7280
movq %rax, %rbx
leaq 0x34268(%rip), %rsi     # 0x57f16
movl $0x53, %edx
movq %rax, %rdi
callq 0x7400
movq %rbx, %rdi
callq 0x71c0
movq 0x4b306(%rip), %rdi     # 0x6efd0
callq 0x7430
jmp 0x23d19
movq 0x4b318(%rip), %rdi     # 0x6eff0
leaq 0x328c9(%rip), %rsi     # 0x565a8
movl $0x6, %edx
callq 0x7400
movq 0x4b300(%rip), %rdi     # 0x6eff0
leaq 0x341f5(%rip), %rsi     # 0x57eec
movl $0x29, %edx
callq 0x7400
movq 0x4b2e8(%rip), %rdi     # 0x6eff0
callq 0x71c0
movq 0x4b2bc(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440
jmp 0x23d34
movq %rax, %rbx
jmp 0x23d5b
jmp 0x23d34
jmp 0x23d34
jmp 0x23d34
jmp 0x23d34
jmp 0x23d34
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0xaf22
movq 0x80(%rsp), %rdi
leaq 0x90(%rsp), %rax
cmpq %rax, %rdi
je 0x23d5b
callq 0x7370
leaq 0xc0(%rsp), %rdi
callq 0x7100
movq %rbx, %rdi
callq 0x7620