// File: /workspace/github_cpp_makefile_star2_O2/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 $0x2f8, %rsp            # imm = 0x2F8
movq %rcx, 0xa8(%rsp)
movq %rdx, 0xb0(%rsp)
movl $0x1, (%rsi)
movl 0xb0(%rdi), %eax
decl %eax
movw %ax, 0x4(%rsi)
movq %rdi, 0x10(%rsp)
movups 0x68(%rdi), %xmm0
movups %xmm0, 0x130(%rsi)
leaq 0x28(%rsi), %r14
movq %rsi, 0x8(%rsp)
leaq 0x40(%rsi), %r15
movl $0xf4241, %ebp          # imm = 0xF4241
leaq 0xf0(%rsp), %rbx
subl $0x1, %ebp
jb 0x1b676
andq $0x0, 0xf0(%rsp)
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1bfa6
andq $0x0, 0xf0(%rsp)
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1bfa6
jmp 0x1b647
movq 0x8(%rsp), %rax
leaq 0x180(%rax), %r12
leaq 0x198(%rax), %r13
movl $0x401, %ebp            # imm = 0x401
leaq 0xf0(%rsp), %rbx
subl $0x1, %ebp
jb 0x1b6c3
andl $0x0, 0xf0(%rsp)
movq %r12, %rdi
movq %rbx, %rsi
callq 0x1c108
andl $0x0, 0xf0(%rsp)
movq %r13, %rdi
movq %rbx, %rsi
callq 0x1c108
jmp 0x1b696
movq 0x8(%rsp), %rax
andl $0x0, 0x14(%rax)
andl $0x0, 0x68(%rax)
leaq 0xf0(%rsp), %rbx
movq %rbx, %rdi
callq 0x73a0
movq 0x10(%rsp), %rax
leaq 0x478(%rax), %rsi
pushq $0x8
popq %rdx
movq %rbx, %rdi
callq 0x72f0
movq %r13, 0x90(%rsp)
movq %r12, 0x80(%rsp)
movq %r15, 0x98(%rsp)
movq %r14, 0x88(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x70d0
testb %al, %al
je 0x1bbeb
leaq 0xd8(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x30(%rsp), %rax
andq $0x0, 0x10(%rax)
xorps %xmm0, %xmm0
movaps %xmm0, (%rax)
movq 0x8(%rsp), %rax
leaq 0xc0(%rax), %rbp
leaq 0xc8(%rax), %rcx
movq %rcx, 0x78(%rsp)
leaq 0x90(%rax), %r13
leaq 0x98(%rax), %rcx
movq %rcx, 0x70(%rsp)
addq $0xf0, %rax
movq %rax, 0xa0(%rsp)
leaq 0xc0(%rsp), %r15
movq $0x0, 0x50(%rsp)
movq $0x0, 0x58(%rsp)
movq $0x0, 0x18(%rsp)
movq 0x18(%rsp), %rbx
leaq 0xf0(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0x7080
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
testb $0x5, 0x20(%rax,%rcx)
jne 0x1bb0f
leaq 0xc8(%rsp), %rdi
callq 0x1bc76
leaq 0x30(%rsp), %r14
movq %r14, %rdi
callq 0x1bc90
leaq 0xc8(%rsp), %rdi
pushq $0x20
popq %rsi
movq %r14, %rdx
leaq 0xe8(%rsp), %r14
callq 0x1bc98
movq 0x30(%rsp), %rax
movq 0x38(%rsp), %rcx
subq %rax, %rcx
cmpq $0xa0, %rcx
jne 0x1bb0f
movq (%rax), %rdi
movq %r14, %rsi
pushq $0xa
popq %rdx
callq 0x7680
movq %rax, 0x18(%rsp)
subq %rbx, %rax
jb 0x1bb93
movq %rax, 0x28(%rsp)
xorl %edx, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
divq %rcx
movq %rax, 0x68(%rsp)
movq 0x30(%rsp), %rax
movq 0x60(%rax), %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x7668
movq %rax, 0x20(%rsp)
movq 0x30(%rsp), %rax
movq 0x40(%rax), %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x7680
movq %rax, %r12
movq 0x10(%rsp), %rax
movq 0x68(%rax), %rcx
movq 0x70(%rax), %rsi
movq %rsi, %rdi
subq %rcx, %rdi
cmpq %rdi, %r12
jbe 0x1b8a8
movq %r12, %rax
xorl %edx, %edx
divq %rdi
movq %rdx, %r12
addq %rcx, %r12
movq 0x28(%rsp), %rax
addq %rax, 0x58(%rsp)
movl 0x20(%rsp), %edi
addq %rdi, 0x50(%rsp)
leaq (%rdi,%r12), %rax
movq %rdi, 0x60(%rsp)
leaq (%rdi,%r12), %rdx
decq %rdx
movq %rsi, %rdi
notq %rdi
addq %rdi, %rcx
cmpq %rsi, %rdx
movl $0x0, %edx
cmovbeq %rdx, %rcx
addq %rcx, %rax
decq %rax
movq %rax, 0xb8(%rsp)
cmpq 0xb8(%rsp), %r12
ja 0x1ba63
movq %r12, %rdi
callq *0xb0(%rsp)
movq %rax, 0xc0(%rsp)
movq %r12, %rdi
callq *0xa8(%rsp)
movq %rax, %rbx
movq 0x30(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x2ad1b(%rip), %rsi     # 0x46649
callq 0x7120
testl %eax, %eax
je 0x1b98b
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1c1e8
cmpq 0x78(%rsp), %rax
je 0x1b9db
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1bd76
movl (%rax), %r14d
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1bd76
incl %r14d
movl %r14d, (%rax)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1bd76
movq 0x8(%rax), %r14
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1bd76
orq %r14, %rbx
jmp 0x1b9ec
movq %r13, %rdi
movq %r15, %rsi
callq 0x1c1e8
cmpq 0x70(%rsp), %rax
je 0x1ba04
movq %r13, %rdi
movq %r15, %rsi
callq 0x1bd76
movl (%rax), %r14d
movq %r13, %rdi
movq %r15, %rsi
callq 0x1bd76
incl %r14d
movl %r14d, (%rax)
movq %r13, %rdi
movq %r15, %rsi
callq 0x1bd76
movq 0x8(%rax), %r14
movq %r13, %rdi
movq %r15, %rsi
callq 0x1bd76
orq %r14, %rbx
jmp 0x1ba15
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1bd76
movl $0x1, (%rax)
movq %rbx, 0x8(%rax)
movq %r13, %rdi
movq %r15, %rsi
callq 0x1c1e8
cmpq 0x70(%rsp), %rax
jne 0x1ba2b
jmp 0x1ba3b
movq %r13, %rdi
movq %r15, %rsi
callq 0x1bd76
movl $0x1, (%rax)
movq %rbx, 0x8(%rax)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x1c1e8
cmpq 0x78(%rsp), %rax
je 0x1ba3b
movq 0xa0(%rsp), %rdi
movq %r15, %rsi
callq 0x1c49c
movq 0x8(%rsp), %rax
incl 0x68(%rax)
incq %r12
movq 0x10(%rsp), %rax
cmpq 0x70(%rax), %r12
jbe 0x1b8f1
movq 0x10(%rsp), %rax
movq 0x68(%rax), %r12
jmp 0x1b8f1
movq 0x30(%rsp), %rdi
subq $-0x80, %rdi
leaq 0x2abd6(%rip), %rsi     # 0x46649
callq 0x7120
testl %eax, %eax
je 0x1bab0
movq 0x68(%rsp), %rcx
shlq $0x3, %rcx
cmpq $0x3b9aca00, 0x28(%rsp) # imm = 0x3B9ACA00
movl $0x7a1200, %eax         # imm = 0x7A1200
cmovaeq %rax, %rcx
movq 0x98(%rsp), %rax
movq (%rax), %rax
incq (%rax,%rcx)
movq 0x90(%rsp), %rax
jmp 0x1bae2
movq 0x68(%rsp), %rcx
shlq $0x3, %rcx
cmpq $0x3b9aca00, 0x28(%rsp) # imm = 0x3B9ACA00
movl $0x7a1200, %eax         # imm = 0x7A1200
cmovaeq %rax, %rcx
movq 0x88(%rsp), %rax
movq (%rax), %rax
incq (%rax,%rcx)
movq 0x80(%rsp), %rax
movq (%rax), %rax
testl $0xfffffc00, 0x20(%rsp) # imm = 0xFFFFFC00
je 0x1baf7
addq $0x1000, %rax           # imm = 0x1000
jmp 0x1bb00
movq 0x60(%rsp), %rcx
leaq (%rax,%rcx,4), %rax
incl (%rax)
movq 0x8(%rsp), %rax
incl 0x14(%rax)
jmp 0x1b7ac
leaq 0xf0(%rsp), %rdi
callq 0x70a0
movq 0x8(%rsp), %rsi
movl 0x14(%rsi), %ecx
movq 0x50(%rsp), %rax
xorl %edx, %edx
divq %rcx
movl %eax, 0x178(%rsi)
movq 0x58(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rax, 0x168(%rsi)
movq 0x10(%rsp), %rax
movsd 0x40(%rax), %xmm0
movsd %xmm0, 0x8(%rsi)
movl 0x6a0(%rax), %eax
movl %eax, 0x10(%rsi)
leaq 0x30(%rsp), %rdi
callq 0x9c08
leaq 0xc8(%rsp), %rdi
callq 0x7678
leaq 0xf0(%rsp), %rdi
callq 0x7100
addq $0x2f8, %rsp            # imm = 0x2F8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x46456(%rip), %rdi     # 0x61ff0
leaq 0x289e7(%rip), %rsi     # 0x44588
callq 0x7360
movq 0x46443(%rip), %rdi     # 0x61ff0
leaq 0x2a194(%rip), %rsi     # 0x45d48
callq 0x7360
movq %rax, %rdi
movq 0x18(%rsp), %rsi
callq 0x7270
leaq 0x2a259(%rip), %rsi     # 0x45e26
movq %rax, %rdi
callq 0x7360
movq %rax, %rdi
callq 0x71a0
movq 0x463ec(%rip), %rdi     # 0x61fd0
callq 0x73d0
jmp 0x1bc25
movq 0x463fe(%rip), %rdi     # 0x61ff0
leaq 0x2898f(%rip), %rsi     # 0x44588
callq 0x7360
movq 0x463eb(%rip), %rdi     # 0x61ff0
leaq 0x2a1f0(%rip), %rsi     # 0x45dfc
callq 0x7360
movq %rax, %rdi
callq 0x71a0
movq 0x463b0(%rip), %rdi     # 0x61fd0
callq 0x73d0
pushq $0x1
popq %rdi
callq 0x73e0
jmp 0x1bc46
movq %rax, %rbx
jmp 0x1bc60
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
jmp 0x1bc46
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x9c08
leaq 0xc8(%rsp), %rdi
callq 0x7678
leaq 0xf0(%rsp), %rdi
callq 0x7100
movq %rbx, %rdi
callq 0x75d0
nop