// File: chahk0129[P]hash_bench/./bench/benchmark.hpp
// Function: benchmark_t<unsigned long>::ycsb_exec(int, int, Pair<unsigned long>*, int, Pair<unsigned long>*, int, int, int*, bool)
inline void benchmark_t<Key_t>::ycsb_exec(int workload_type, int index_type, Pair<Key_t>* init_kv, int init_num, Pair<Key_t>* run_kv, int run_num, int num_threads, int* ops, bool pcm_enabled){
    /*
    if(memory_bandwidth){
	if(geteuid() != 0){
	    fprintf(stderr, "Must be root user to measure memory bandwidth\n");
	    exit(0);
	}
	PCM_memory::InitMemoryMonitor();
    }

    if(numa){
	if(geteuid() != 0){
	    fprintf(stderr, "Must be root user to measure NUMA operations\n");
	    exit(0);
	}
	PCM_NUMA::InitNumaMonitor();
    }*/

    Hash<Key_t>* hashtable = getInstance<Key_t>(index_type);
    //init_num = 100;
    //run_num = 100;

    auto load_func = [&hashtable, &init_kv, init_num, num_threads](uint64_t thread_id, bool){
	size_t total_num = init_num;
	size_t chunk_size = total_num / num_threads;
	size_t from = chunk_size * thread_id;
	size_t to = chunk_size * (thread_id+1);

	for(size_t i=from; i<to; i++){
	    hashtable->Insert(init_kv[i].key, init_kv[i].value);
	}
	return;
    };

    /*
    if(memory_bandwidth)
	PCM_memory::StartMemoryMonitor();

    if(numa)
	PCM_NUMA::StartNUMAMonitor();
	*/
    std::unique_ptr<SystemCounterState> before;
    if(pcm_enabled){
	before = std::make_unique<SystemCounterState>();
	*before = getSystemCounterState();
    }
    clear_cache();
    double start_time = get_now();
    start_threads(hashtable, num_threads, load_func, false);
    double end_time = get_now();

    std::unique_ptr<SystemCounterState> after;
    if(pcm_enabled){
	after = std::make_unique<SystemCounterState>();
	*after = getSystemCounterState();
    }
    /*
    if(memory_bandwidth)
	PCM_memory::EndMemoryMonitor();

    if(numa)
	PCM_NUMA::EndNUMAMonitor();
	*/
    double throughput = init_num / (end_time - start_time) / 1000000; // MOps/sec
    std::cout << "\033[1;32m";
    std::cout << "Insert " << throughput << "\033[0m" << std::endl;

    if(pcm_enabled){
	std::cout << "PCM Metrics:\n"
	    	  << "\tL3 misses: " << getL3CacheMisses(*before, *after) << "\n"
		  << "\tReads(bytes): " << getBytesReadFromMC(*before, *after) << "\n"
		  << "\tWrites(byes): " << getBytesWrittenToMC(*before, *after) << std::endl;
    }

    auto exec_func = [&hashtable, &run_kv, run_num, &ops, num_threads](uint64_t thread_id, bool){
	size_t total_num = run_num;
	size_t chunk_size = total_num / num_threads;
	size_t from = chunk_size * thread_id;
	size_t to = chunk_size * (thread_id+1);

	for(size_t i=from; i<to; i++){
	    if(ops[i] == OP_INSERT){
		hashtable->Insert(run_kv[i].key, run_kv[i].value);
	    }
	    else if(ops[i] == OP_READ){
		auto ret = hashtable->Get(run_kv[i].key);
		if((uint64_t)ret == 0)
		    std::cout << "not found" << std::endl;
	    }
	    else if(ops[i] == OP_UPDATE){
		auto ret = hashtable->Update(run_kv[i].key, run_kv[i].value);
	    }
	}
	return;
    };

    /*
    if(memory_bandwidth)
	PCM_memory::StartMemoryMonitor();

    if(numa)
	PCM_NUMA::StartNUMAMonitor();
    */
    if(pcm_enabled){
	*before = getSystemCounterState();
    }

    clear_cache();
    start_time = get_now();
    start_threads(hashtable, num_threads, exec_func, false);
    end_time = get_now();

    if(pcm_enabled){
	*after = getSystemCounterState();
    }

    /*
    if(memory_bandwidth)
	PCM_memory::EndMemoryMonitor();

    if(numa)
	PCM_NUMA::EndNUMAMonitor();
    */
    throughput = run_num / (end_time - start_time) / 1000000; // MOps/sec
    std::cout << "\033[1;31m";
    if(workload_type == WORKLOAD_A)
	std::cout << "Read/Update " << throughput << "\033[0m" << std::endl;
    else if(workload_type == WORKLOAD_B)
	std::cout << "Read/Update " << throughput << "\033[0m" << std::endl;
    else if(workload_type == WORKLOAD_C)
	std::cout << "Read " << throughput << "\033[0m" << std::endl;
    else if(workload_type == WORKLOAD_D)
	std::cout << "Read/Update " << throughput << "\033[0m" << std::endl;

    if(pcm_enabled){
	std::cout << "PCM Metrics:\n"
	    	  << "\tL3 misses: " << getL3CacheMisses(*before, *after) << "\n"
		  << "\tReads(bytes): " << getBytesReadFromMC(*before, *after) << "\n"
		  << "\tWrites(byes): " << getBytesWrittenToMC(*before, *after) << std::endl;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x980, %rsp            # imm = 0x980
movb 0x28(%rbp), %al
movq 0x20(%rbp), %r10
movl 0x18(%rbp), %r10d
movl 0x10(%rbp), %r10d
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movl %edx, -0x10(%rbp)
movq %rcx, -0x18(%rbp)
movl %r8d, -0x1c(%rbp)
movq %r9, -0x28(%rbp)
andb $0x1, %al
movb %al, -0x29(%rbp)
movl -0x10(%rbp), %edi
callq 0x1be30
movq %rax, -0x38(%rbp)
leaq -0x38(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq -0x18(%rbp), %rax
movq %rax, -0x48(%rbp)
movl -0x1c(%rbp), %eax
movl %eax, -0x40(%rbp)
movl 0x18(%rbp), %eax
movl %eax, -0x3c(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x1bf70
testb $0x1, -0x29(%rbp)
je 0x1592a
leaq -0x60(%rbp), %rdi
callq 0x1bfa0
jmp 0x1589b
leaq -0x58(%rbp), %rdi
leaq -0x60(%rbp), %rsi
movq %rsi, -0x798(%rbp)
callq 0x1c010
movq -0x798(%rbp), %rdi
callq 0x1c040
leaq -0x220(%rbp), %rdi
callq 0x3bfd0
jmp 0x158c9
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x7a0(%rbp)
jmp 0x158db
movq -0x7a0(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x1c0c0
leaq -0x220(%rbp), %rdi
callq 0x1c170
jmp 0x1592a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x16273
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x220(%rbp), %rdi
callq 0x1c170
jmp 0x16273
callq 0x1c1f0
jmp 0x15931
callq 0x1c200
movsd %xmm0, -0x7a8(%rbp)
jmp 0x15940
movsd -0x7a8(%rbp), %xmm0
movsd %xmm0, -0x228(%rbp)
movq -0x38(%rbp), %rdi
movslq 0x18(%rbp), %rsi
movb $0x0, -0x229(%rbp)
leaq -0x50(%rbp), %rdx
leaq -0x229(%rbp), %rcx
callq 0x1c240
jmp 0x15971
callq 0x1c200
movsd %xmm0, -0x7b0(%rbp)
jmp 0x15980
movsd -0x7b0(%rbp), %xmm0
movsd %xmm0, -0x238(%rbp)
leaq -0x240(%rbp), %rdi
callq 0x1bf70
testb $0x1, -0x29(%rbp)
je 0x15a4c
leaq -0x248(%rbp), %rdi
callq 0x1bfa0
jmp 0x159b4
leaq -0x240(%rbp), %rdi
leaq -0x248(%rbp), %rsi
movq %rsi, -0x7b8(%rbp)
callq 0x1c010
movq -0x7b8(%rbp), %rdi
callq 0x1c040
leaq -0x3f8(%rbp), %rdi
callq 0x3bfd0
jmp 0x159e8
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x7c0(%rbp)
jmp 0x159fd
movq -0x7c0(%rbp), %rdi
leaq -0x3f8(%rbp), %rsi
callq 0x1c0c0
leaq -0x3f8(%rbp), %rdi
callq 0x1c170
jmp 0x15a4c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x16267
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x3f8(%rbp), %rdi
callq 0x1c170
jmp 0x16267
cvtsi2sdl -0x1c(%rbp), %xmm0
movsd -0x238(%rbp), %xmm1
movsd -0x228(%rbp), %xmm2
subsd %xmm2, %xmm1
divsd %xmm1, %xmm0
movsd 0x30597(%rip), %xmm1    # 0x46008
divsd %xmm1, %xmm0
movsd %xmm0, -0x400(%rbp)
movq 0x4a534(%rip), %rdi     # 0x5ffb8
leaq 0x30aa9(%rip), %rsi     # 0x46534
callq 0x6410
jmp 0x15a92
movq 0x4a51f(%rip), %rdi     # 0x5ffb8
leaq 0x30a9c(%rip), %rsi     # 0x4653c
callq 0x6410
movq %rax, -0x7c8(%rbp)
jmp 0x15aae
movq -0x7c8(%rbp), %rdi
movsd -0x400(%rbp), %xmm0
callq 0x68a0
movq %rax, -0x7d0(%rbp)
jmp 0x15acb
movq -0x7d0(%rbp), %rdi
leaq 0x30a6b(%rip), %rsi     # 0x46544
callq 0x6410
movq %rax, -0x7d8(%rbp)
jmp 0x15ae7
movq -0x7d8(%rbp), %rdi
movq 0x4a4ab(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x15afc
testb $0x1, -0x29(%rbp)
je 0x15ce2
movq 0x4a4ab(%rip), %rdi     # 0x5ffb8
leaq 0x30a35(%rip), %rsi     # 0x46549
callq 0x6410
movq %rax, -0x7e0(%rbp)
jmp 0x15b22
movq -0x7e0(%rbp), %rdi
leaq 0x30a27(%rip), %rsi     # 0x46557
callq 0x6410
movq %rax, -0x7e8(%rbp)
jmp 0x15b3e
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x7f0(%rbp)
jmp 0x15b50
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x7f8(%rbp)
jmp 0x15b65
movq -0x7f8(%rbp), %rsi
movq -0x7f0(%rbp), %rdi
callq 0x1c360
movq %rax, -0x800(%rbp)
jmp 0x15b81
movq -0x800(%rbp), %rsi
movq -0x7e8(%rbp), %rdi
callq 0x63f0
movq %rax, -0x808(%rbp)
jmp 0x15b9d
movq -0x808(%rbp), %rdi
leaq 0x309aa(%rip), %rsi     # 0x46555
callq 0x6410
movq %rax, -0x810(%rbp)
jmp 0x15bb9
movq -0x810(%rbp), %rdi
leaq 0x3099d(%rip), %rsi     # 0x46564
callq 0x6410
movq %rax, -0x818(%rbp)
jmp 0x15bd5
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x820(%rbp)
jmp 0x15be7
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x828(%rbp)
jmp 0x15bfc
movq -0x828(%rbp), %rsi
movq -0x820(%rbp), %rdi
callq 0x1c3c0
movq %rax, -0x830(%rbp)
jmp 0x15c18
movq -0x830(%rbp), %rsi
movq -0x818(%rbp), %rdi
callq 0x63f0
movq %rax, -0x838(%rbp)
jmp 0x15c34
movq -0x838(%rbp), %rdi
leaq 0x30913(%rip), %rsi     # 0x46555
callq 0x6410
movq %rax, -0x840(%rbp)
jmp 0x15c50
movq -0x840(%rbp), %rdi
leaq 0x30916(%rip), %rsi     # 0x46574
callq 0x6410
movq %rax, -0x848(%rbp)
jmp 0x15c6c
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x850(%rbp)
jmp 0x15c7e
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x858(%rbp)
jmp 0x15c93
movq -0x858(%rbp), %rsi
movq -0x850(%rbp), %rdi
callq 0x1c3f0
movq %rax, -0x860(%rbp)
jmp 0x15caf
movq -0x860(%rbp), %rsi
movq -0x848(%rbp), %rdi
callq 0x63f0
movq %rax, -0x868(%rbp)
jmp 0x15ccb
movq -0x868(%rbp), %rdi
movq 0x4a2c7(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x15ce0
jmp 0x15ce2
leaq -0x38(%rbp), %rax
movq %rax, -0x428(%rbp)
leaq -0x28(%rbp), %rax
movq %rax, -0x420(%rbp)
movl 0x10(%rbp), %eax
movl %eax, -0x418(%rbp)
leaq 0x20(%rbp), %rax
movq %rax, -0x410(%rbp)
movl 0x18(%rbp), %eax
movl %eax, -0x408(%rbp)
testb $0x1, -0x29(%rbp)
je 0x15d79
leaq -0x5d8(%rbp), %rdi
callq 0x3bfd0
jmp 0x15d29
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x870(%rbp)
jmp 0x15d3b
movq -0x870(%rbp), %rdi
leaq -0x5d8(%rbp), %rsi
callq 0x1c0c0
leaq -0x5d8(%rbp), %rdi
callq 0x1c170
jmp 0x15d79
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x5d8(%rbp), %rdi
callq 0x1c170
jmp 0x16267
callq 0x1c1f0
jmp 0x15d80
callq 0x1c200
movsd %xmm0, -0x878(%rbp)
jmp 0x15d8f
movsd -0x878(%rbp), %xmm0
movsd %xmm0, -0x228(%rbp)
movq -0x38(%rbp), %rdi
movslq 0x18(%rbp), %rsi
movb $0x0, -0x5d9(%rbp)
leaq -0x428(%rbp), %rdx
leaq -0x5d9(%rbp), %rcx
callq 0x1c420
jmp 0x15dc3
callq 0x1c200
movsd %xmm0, -0x880(%rbp)
jmp 0x15dd2
movsd -0x880(%rbp), %xmm0
movsd %xmm0, -0x238(%rbp)
testb $0x1, -0x29(%rbp)
je 0x15e49
leaq -0x790(%rbp), %rdi
callq 0x3bfd0
jmp 0x15df6
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x888(%rbp)
jmp 0x15e0b
movq -0x888(%rbp), %rdi
leaq -0x790(%rbp), %rsi
callq 0x1c0c0
leaq -0x790(%rbp), %rdi
callq 0x1c170
jmp 0x15e49
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x790(%rbp), %rdi
callq 0x1c170
jmp 0x16267
cvtsi2sdl 0x10(%rbp), %xmm0
movsd -0x238(%rbp), %xmm1
movsd -0x228(%rbp), %xmm2
subsd %xmm2, %xmm1
divsd %xmm1, %xmm0
movsd 0x3019a(%rip), %xmm1    # 0x46008
divsd %xmm1, %xmm0
movsd %xmm0, -0x400(%rbp)
movq 0x4a137(%rip), %rdi     # 0x5ffb8
leaq 0x306fc(%rip), %rsi     # 0x46584
callq 0x6410
jmp 0x15e8f
cmpl $0x0, -0xc(%rbp)
jne 0x15f04
movq 0x4a11c(%rip), %rdi     # 0x5ffb8
leaq 0x306e9(%rip), %rsi     # 0x4658c
callq 0x6410
movq %rax, -0x890(%rbp)
jmp 0x15eb1
movq -0x890(%rbp), %rdi
movsd -0x400(%rbp), %xmm0
callq 0x68a0
movq %rax, -0x898(%rbp)
jmp 0x15ece
movq -0x898(%rbp), %rdi
leaq 0x30668(%rip), %rsi     # 0x46544
callq 0x6410
movq %rax, -0x8a0(%rbp)
jmp 0x15eea
movq -0x8a0(%rbp), %rdi
movq 0x4a0a8(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x15eff
jmp 0x16063
cmpl $0x1, -0xc(%rbp)
jne 0x15f79
movq 0x4a0a7(%rip), %rdi     # 0x5ffb8
leaq 0x30674(%rip), %rsi     # 0x4658c
callq 0x6410
movq %rax, -0x8a8(%rbp)
jmp 0x15f26
movq -0x8a8(%rbp), %rdi
movsd -0x400(%rbp), %xmm0
callq 0x68a0
movq %rax, -0x8b0(%rbp)
jmp 0x15f43
movq -0x8b0(%rbp), %rdi
leaq 0x305f3(%rip), %rsi     # 0x46544
callq 0x6410
movq %rax, -0x8b8(%rbp)
jmp 0x15f5f
movq -0x8b8(%rbp), %rdi
movq 0x4a033(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x15f74
jmp 0x16061
cmpl $0x2, -0xc(%rbp)
jne 0x15feb
movq 0x4a032(%rip), %rdi     # 0x5ffb8
leaq 0x3060c(%rip), %rsi     # 0x46599
callq 0x6410
movq %rax, -0x8c0(%rbp)
jmp 0x15f9b
movq -0x8c0(%rbp), %rdi
movsd -0x400(%rbp), %xmm0
callq 0x68a0
movq %rax, -0x8c8(%rbp)
jmp 0x15fb8
movq -0x8c8(%rbp), %rdi
leaq 0x3057e(%rip), %rsi     # 0x46544
callq 0x6410
movq %rax, -0x8d0(%rbp)
jmp 0x15fd4
movq -0x8d0(%rbp), %rdi
movq 0x49fbe(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x15fe9
jmp 0x1605f
cmpl $0x3, -0xc(%rbp)
jne 0x1605d
movq 0x49fc0(%rip), %rdi     # 0x5ffb8
leaq 0x3058d(%rip), %rsi     # 0x4658c
callq 0x6410
movq %rax, -0x8d8(%rbp)
jmp 0x1600d
movq -0x8d8(%rbp), %rdi
movsd -0x400(%rbp), %xmm0
callq 0x68a0
movq %rax, -0x8e0(%rbp)
jmp 0x1602a
movq -0x8e0(%rbp), %rdi
leaq 0x3050c(%rip), %rsi     # 0x46544
callq 0x6410
movq %rax, -0x8e8(%rbp)
jmp 0x16046
movq -0x8e8(%rbp), %rdi
movq 0x49f4c(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x1605b
jmp 0x1605d
jmp 0x1605f
jmp 0x16061
jmp 0x16063
testb $0x1, -0x29(%rbp)
je 0x16249
movq 0x49f44(%rip), %rdi     # 0x5ffb8
leaq 0x304ce(%rip), %rsi     # 0x46549
callq 0x6410
movq %rax, -0x8f0(%rbp)
jmp 0x16089
movq -0x8f0(%rbp), %rdi
leaq 0x304c0(%rip), %rsi     # 0x46557
callq 0x6410
movq %rax, -0x8f8(%rbp)
jmp 0x160a5
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x900(%rbp)
jmp 0x160b7
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x908(%rbp)
jmp 0x160cc
movq -0x908(%rbp), %rsi
movq -0x900(%rbp), %rdi
callq 0x1c360
movq %rax, -0x910(%rbp)
jmp 0x160e8
movq -0x910(%rbp), %rsi
movq -0x8f8(%rbp), %rdi
callq 0x63f0
movq %rax, -0x918(%rbp)
jmp 0x16104
movq -0x918(%rbp), %rdi
leaq 0x30443(%rip), %rsi     # 0x46555
callq 0x6410
movq %rax, -0x920(%rbp)
jmp 0x16120
movq -0x920(%rbp), %rdi
leaq 0x30436(%rip), %rsi     # 0x46564
callq 0x6410
movq %rax, -0x928(%rbp)
jmp 0x1613c
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x930(%rbp)
jmp 0x1614e
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x938(%rbp)
jmp 0x16163
movq -0x938(%rbp), %rsi
movq -0x930(%rbp), %rdi
callq 0x1c3c0
movq %rax, -0x940(%rbp)
jmp 0x1617f
movq -0x940(%rbp), %rsi
movq -0x928(%rbp), %rdi
callq 0x63f0
movq %rax, -0x948(%rbp)
jmp 0x1619b
movq -0x948(%rbp), %rdi
leaq 0x303ac(%rip), %rsi     # 0x46555
callq 0x6410
movq %rax, -0x950(%rbp)
jmp 0x161b7
movq -0x950(%rbp), %rdi
leaq 0x303af(%rip), %rsi     # 0x46574
callq 0x6410
movq %rax, -0x958(%rbp)
jmp 0x161d3
leaq -0x58(%rbp), %rdi
callq 0x1c090
movq %rax, -0x960(%rbp)
jmp 0x161e5
leaq -0x240(%rbp), %rdi
callq 0x1c090
movq %rax, -0x968(%rbp)
jmp 0x161fa
movq -0x968(%rbp), %rsi
movq -0x960(%rbp), %rdi
callq 0x1c3f0
movq %rax, -0x970(%rbp)
jmp 0x16216
movq -0x970(%rbp), %rsi
movq -0x958(%rbp), %rdi
callq 0x63f0
movq %rax, -0x978(%rbp)
jmp 0x16232
movq -0x978(%rbp), %rdi
movq 0x49d60(%rip), %rsi     # 0x5ffa0
callq 0x6470
jmp 0x16247
jmp 0x16249
leaq -0x240(%rbp), %rdi
callq 0x1c040
leaq -0x58(%rbp), %rdi
callq 0x1c040
addq $0x980, %rsp            # imm = 0x980
popq %rbp
retq
leaq -0x240(%rbp), %rdi
callq 0x1c040
leaq -0x58(%rbp), %rdi
callq 0x1c040
movq -0x68(%rbp), %rdi
callq 0x6800
nopw %cs:(%rax,%rax)
nop