// File: /workspace/github_cpp_makefile_star2_O3/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 $0x2e8, %rsp            # imm = 0x2E8
movq %rcx, 0xc8(%rsp)
movq %rdx, 0xd0(%rsp)
movq %rsi, %rbx
movl $0x1, (%rsi)
movl 0xb0(%rdi), %eax
decl %eax
movw %ax, 0x4(%rsi)
movq %rdi, 0x18(%rsp)
movups 0x68(%rdi), %xmm0
movups %xmm0, 0x130(%rsi)
leaq 0x28(%rsi), %rax
movq %rax, 0x70(%rsp)
leaq 0x40(%rsi), %rax
movq %rax, 0x80(%rsp)
movl $0xf4241, %ebp          # imm = 0xF4241
leaq 0xe0(%rsp), %r15
movq $0x0, 0xe0(%rsp)
movq 0x30(%rbx), %rsi
cmpq 0x38(%rbx), %rsi
je 0x233f3
movq $0x0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x30(%rbx)
jmp 0x23400
movq 0x70(%rsp), %rdi
movq %r15, %rdx
callq 0x23ff2
movq $0x0, 0xe0(%rsp)
movq 0x48(%rbx), %rsi
cmpq 0x50(%rbx), %rsi
je 0x23427
movq $0x0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x48(%rbx)
jmp 0x23437
movq 0x80(%rsp), %rdi
movq %r15, %rdx
callq 0x23ff2
decl %ebp
jne 0x233cc
leaq 0x180(%rbx), %rax
movq %rax, 0x68(%rsp)
leaq 0x198(%rbx), %rax
movq %rax, 0x78(%rsp)
movl $0x401, %ebp            # imm = 0x401
leaq 0xe0(%rsp), %r15
movl $0x0, 0xe0(%rsp)
movq 0x188(%rbx), %rsi
cmpq 0x190(%rbx), %rsi
je 0x2348e
movl $0x0, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x188(%rbx)
jmp 0x2349b
movq 0x68(%rsp), %rdi
movq %r15, %rdx
callq 0x24128
movl $0x0, 0xe0(%rsp)
movq 0x1a0(%rbx), %rsi
cmpq 0x1a8(%rbx), %rsi
je 0x234c9
movl $0x0, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x1a0(%rbx)
jmp 0x234d6
movq 0x78(%rsp), %rdi
movq %r15, %rdx
callq 0x24128
decl %ebp
jne 0x23460
xorl %eax, %eax
movl %eax, 0x14(%rbx)
movl %eax, 0x68(%rbx)
leaq 0xe0(%rsp), %r15
movq %r15, %rdi
callq 0x73f0
movq 0x18(%rsp), %rax
leaq 0x478(%rax), %rsi
movq %r15, %rdi
movl $0x8, %edx
callq 0x7330
leaq 0x158(%rsp), %rdi
callq 0x70e0
testb %al, %al
je 0x23b32
leaq 0xb0(%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)
leaq 0xc0(%rbx), %rax
movq %rax, 0x10(%rsp)
leaq 0xc8(%rbx), %rax
movq %rax, 0x38(%rsp)
leaq 0x98(%rbx), %rax
movq %rax, 0x30(%rsp)
leaq 0xf0(%rbx), %rax
movq %rax, 0xc0(%rsp)
leaq 0x90(%rbx), %rax
movq %rax, 0x8(%rsp)
movq $0x0, 0x60(%rsp)
movq $0x0, 0x28(%rsp)
xorl %edx, %edx
movq %rdx, %r14
movq 0xe0(%rsp), %rax
movq -0x18(%rax), %rdi
leaq 0xe0(%rsp), %rax
addq %rax, %rdi
movl $0xa, %esi
callq 0x7380
movsbl %al, %edx
leaq 0xe0(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x7660
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
testb $0x5, 0x20(%rax,%rcx)
jne 0x23a3a
movq 0xa0(%rsp), %rax
movq 0xa8(%rsp), %rsi
cmpb $0xd, -0x1(%rax,%rsi)
jne 0x23611
decq %rsi
movl $0x1, %edx
leaq 0xa0(%rsp), %rdi
callq 0x70d0
movq 0x40(%rsp), %r15
movq 0x48(%rsp), %r13
cmpq %r15, %r13
je 0x23643
movq %r15, %r12
movq (%r12), %rdi
addq $0x10, %r12
cmpq %r12, %rdi
je 0x23635
callq 0x7370
addq $0x10, %r12
cmpq %r13, %r12
jne 0x23623
movq %r15, 0x48(%rsp)
leaq 0xa0(%rsp), %rdi
movl $0x20, %esi
leaq 0x40(%rsp), %rdx
callq 0x23c18
leaq 0xd8(%rsp), %r15
movq 0x40(%rsp), %rax
movq 0x48(%rsp), %rcx
subq %rax, %rcx
cmpq $0xa0, %rcx
jne 0x23a3a
movq (%rax), %rdi
movq %r15, %rsi
movl $0xa, %edx
callq 0x74a0
movq %rax, %r12
subq %r14, %rax
jb 0x23ac6
movq %rax, 0x90(%rsp)
shrq $0x3, %rax
movabsq $0x20c49ba5e353f7cf, %rcx # imm = 0x20C49BA5E353F7CF
mulq %rcx
movq %rdx, %rbp
movq 0x40(%rsp), %rax
movq 0x60(%rax), %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x7140
movq %rax, %r14
movq 0x40(%rsp), %rax
movq 0x40(%rax), %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x74a0
movq %rax, %r15
movq 0x18(%rsp), %rax
movq 0x68(%rax), %rcx
movq 0x70(%rax), %rsi
movq %rsi, %rdi
subq %rcx, %rdi
cmpq %rdi, %r15
movq %r12, 0x98(%rsp)
jbe 0x2370b
movq %r15, %rax
xorl %edx, %edx
divq %rdi
movq %rdx, %r15
addq %rcx, %r15
movq %r14, 0x88(%rsp)
movl %r14d, %edi
leaq (%rdi,%r15), %rax
decq %rax
movq %rsi, %rdx
notq %rdx
addq %rdx, %rcx
cmpq %rsi, %rax
movl $0x0, %eax
cmovbeq %rax, %rcx
movq %rdi, 0x20(%rsp)
leaq (%rdi,%r15), %rax
leaq (%rcx,%rax), %r13
decq %r13
cmpq %r13, %r15
jbe 0x237a0
shrq $0x4, %rbp
movq 0x40(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x3501b(%rip), %rsi     # 0x58779
callq 0x7120
shlq $0x3, %rbp
testl %eax, %eax
je 0x239c7
movq 0x90(%rsp), %rsi
cmpq $0x3b9aca00, %rsi       # imm = 0x3B9ACA00
movl $0x7a1200, %eax         # imm = 0x7A1200
cmovaeq %rax, %rbp
movq 0x80(%rsp), %rax
movq (%rax), %rax
incq (%rax,%rbp)
movq 0x78(%rsp), %rax
jmp 0x239f0
movq %r15, %rdi
callq *0xd0(%rsp)
movq %rbp, %r14
movq %rax, (%rsp)
movq %r15, %rdi
callq *0xc8(%rsp)
movq %rax, %r12
movq 0x40(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x34fab(%rip), %rsi     # 0x58779
callq 0x7120
testl %eax, %eax
je 0x23871
movq 0xd0(%rbx), %rcx
testq %rcx, %rcx
je 0x23819
movq (%rsp), %rax
movq 0x38(%rsp), %rdx
xorl %esi, %esi
cmpq %rax, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rdx
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x237f0
cmpq 0x38(%rsp), %rdx
je 0x23819
cmpq 0x20(%rdx), %rax
jae 0x2393b
movq 0x10(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
movl $0x1, (%rax)
movq %r12, 0x8(%rax)
movq 0xa0(%rbx), %rcx
testq %rcx, %rcx
je 0x23910
movq (%rsp), %rax
movq 0x30(%rsp), %rdx
xorl %esi, %esi
cmpq %rax, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rdx
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x23849
cmpq 0x30(%rsp), %rdx
jne 0x238fa
jmp 0x23910
movq 0xa0(%rbx), %rcx
testq %rcx, %rcx
je 0x238af
movq (%rsp), %rax
movq 0x30(%rsp), %rdx
xorl %esi, %esi
cmpq %rax, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rdx
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x23886
cmpq 0x30(%rsp), %rdx
je 0x238af
cmpq 0x20(%rdx), %rax
jae 0x23981
movq 0x8(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
movl $0x1, (%rax)
movq %r12, 0x8(%rax)
movq 0xd0(%rbx), %rcx
testq %rcx, %rcx
je 0x23910
movq (%rsp), %rax
movq 0x38(%rsp), %rdx
xorl %esi, %esi
cmpq %rax, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rdx
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x238db
cmpq 0x38(%rsp), %rdx
je 0x23910
cmpq 0x20(%rdx), %rax
jb 0x23910
movq 0xc0(%rsp), %rdi
movq %rsp, %rsi
callq 0x24406
incl 0x68(%rbx)
incq %r15
movq 0x18(%rsp), %rax
cmpq 0x70(%rax), %r15
jbe 0x2392a
movq 0x18(%rsp), %rax
movq 0x68(%rax), %r15
cmpq %r13, %r15
movq %r14, %rbp
jbe 0x237a0
jmp 0x2374a
movq 0x10(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
movl (%rax), %ebp
movq 0x10(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
incl %ebp
movl %ebp, (%rax)
movq 0x10(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
movq 0x8(%rax), %rbp
movq 0x10(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
orq %rbp, %r12
jmp 0x2382c
movq 0x8(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
movl (%rax), %ebp
movq 0x8(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
incl %ebp
movl %ebp, (%rax)
movq 0x8(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
movq 0x8(%rax), %rbp
movq 0x8(%rsp), %rdi
movq %rsp, %rsi
callq 0x23d2a
orq %rbp, %r12
jmp 0x238c2
movq 0x90(%rsp), %rsi
cmpq $0x3b9aca00, %rsi       # imm = 0x3B9ACA00
movl $0x7a1200, %eax         # imm = 0x7A1200
cmovaeq %rax, %rbp
movq 0x70(%rsp), %rax
movq (%rax), %rax
incq (%rax,%rbp)
movq 0x68(%rsp), %rax
movq (%rax), %rax
testl $0xfffffc00, 0x88(%rsp) # imm = 0xFFFFFC00
movq 0x28(%rsp), %rcx
movq 0x98(%rsp), %rdx
je 0x23a1a
addq $0x1000, %rax           # imm = 0x1000
movq 0x20(%rsp), %rdi
jmp 0x23a23
movq 0x20(%rsp), %rdi
leaq (%rax,%rdi,4), %rax
addq %rsi, %rcx
movq %rcx, 0x28(%rsp)
incl (%rax)
addq %rdi, 0x60(%rsp)
incl 0x14(%rbx)
jmp 0x23597
leaq 0xe0(%rsp), %rdi
callq 0x70b0
movl 0x14(%rbx), %ecx
movq 0x60(%rsp), %rax
xorl %edx, %edx
divq %rcx
movl %eax, 0x178(%rbx)
movq 0x28(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rax, 0x168(%rbx)
movq 0x18(%rsp), %rax
movsd 0x40(%rax), %xmm0
movsd %xmm0, 0x8(%rbx)
movl 0x6a0(%rax), %eax
movl %eax, 0x10(%rbx)
leaq 0x40(%rsp), %rdi
callq 0xae1a
movq 0xa0(%rsp), %rdi
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x23aa7
callq 0x7370
leaq 0xe0(%rsp), %rdi
callq 0x7100
addq $0x2e8, %rsp            # imm = 0x2E8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x4b523(%rip), %rdi     # 0x6eff0
leaq 0x32ad4(%rip), %rsi     # 0x565a8
movl $0x6, %edx
callq 0x7400
movq 0x4b50b(%rip), %rdi     # 0x6eff0
leaq 0x3434c(%rip), %rsi     # 0x57e38
movl $0x21, %edx
callq 0x7400
movq 0x4b4f3(%rip), %rdi     # 0x6eff0
movq %r12, %rsi
callq 0x7280
movq %rax, %rbx
leaq 0x34407(%rip), %rsi     # 0x57f16
movl $0x53, %edx
movq %rax, %rdi
callq 0x7400
movq %rbx, %rdi
callq 0x71c0
movq 0x4b4a5(%rip), %rdi     # 0x6efd0
callq 0x7430
jmp 0x23b7a
movq 0x4b4b7(%rip), %rdi     # 0x6eff0
leaq 0x32a68(%rip), %rsi     # 0x565a8
movl $0x6, %edx
callq 0x7400
movq 0x4b49f(%rip), %rdi     # 0x6eff0
leaq 0x34394(%rip), %rsi     # 0x57eec
movl $0x29, %edx
callq 0x7400
movq 0x4b487(%rip), %rdi     # 0x6eff0
callq 0x71c0
movq 0x4b45b(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440
jmp 0x23b95
movq %rax, %rbx
jmp 0x23bbc
jmp 0x23b95
jmp 0x23b95
jmp 0x23b95
jmp 0x23b95
jmp 0x23b95
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0xae1a
movq 0xa0(%rsp), %rdi
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x23bbc
callq 0x7370
leaq 0xe0(%rsp), %rdi
callq 0x7100
movq %rbx, %rdi
callq 0x7620
nop