// File: chahk0129[P]hash_bench/test/string.cpp
// Function: main
int main(int argc, char* argv[]){
#ifdef MICROBENCH 
    if(argc < 2){
	std::cout << "Usage: " << std::endl;
	std::cout << "1. index type: ext, cuc, lin" << std::endl;
	std::cout << "2. numData" << std::endl;
	std::cout << "3. numThreads" << std::endl;
	std::cout << "4. runmode: 1(microbench), 2(latency), 3(mixed)" << std::endl;
	std::cout << "5. insert-only" << std::endl;
	return 1;
    }

    int index_type;
    if(strcmp(argv[1], "ext") == 0)
	index_type = TYPE_EXTENDIBLE_HASH;
    else if(strcmp(argv[1], "cuc") == 0)
	index_type = TYPE_CUCKOO_HASH;
    else if(strcmp(argv[1], "lin") == 0)
	index_type = TYPE_LINEAR_HASH;
    else{
	fprintf(stderr, "unkown index type %s\n", argv[2]);
	return 1;
    }

    int init_num = atoi(argv[2]);
    int num_threads = atoi(argv[3]);
    int mode = atoi(argv[4]);
    if(argc > 5){
    	int insert_only_ = atoi(argv[5]);
    	if(insert_only_ > 0) insert_only = true;
    }
    benchmark_t<Key_t>* bench = new benchmark_t<Key_t>(pcm_enabled);

    Pair<Key_t>* init_kv = new Pair<Key_t>[init_num];
    if(mode == 1)
	bench->microbench(index_type, init_kv, init_num, insert_only);
    else if(mode == 2)
	bench->latency(index_type, init_kv, init_num, num_threads);
    else
	bench->mixed(index_type, init_kv, init_num, num_threads);
    return 0;

#else

    if(argc < 4){
	std::cout << "Usage: " << std::endl;
	std::cout << "1. workload type: a, b, c, d" << std::endl;
	std::cout << "2. index type: ext, cuc, lin" << std::endl;
	std::cout << "3. number of threads" << std::endl;
	std::cout << "   --hyper: whether to pin all threads on single NUMA node" << std::endl;
	std::cout << "   --pcm: whether to use pcm to monitor memory patterns" << std::endl;
	std::cout << "   --mem: whether to monitor memory access" << std::endl;
	std::cout << "   --numa: whether to monitor NUMA throughput" << std::endl;
	return 1;
    }

    int workload_type;
    if(strcmp(argv[1], "a") == 0)
	workload_type = WORKLOAD_A;
    else if(strcmp(argv[1], "b") == 0)
	workload_type = WORKLOAD_B;
    else if(strcmp(argv[1], "c") == 0)
	workload_type = WORKLOAD_C;
    else if(strcmp(argv[1], "d") == 0)
	workload_type = WORKLOAD_D;
    else{
	fprintf(stderr, "unknown workload type %s\n", argv[1]);
	return 1;
    }

    int index_type;
    if(strcmp(argv[2], "ext") == 0)
	index_type = TYPE_EXTENDIBLE_HASH;
    else if(strcmp(argv[2], "cuc") == 0)
	index_type = TYPE_CUCKOO_HASH;
    else if(strcmp(argv[2], "lin") == 0)
	index_type = TYPE_LINEAR_HASH;
    else{
	fprintf(stderr, "unkown index type %s\n", argv[2]);
	return 1;
    }

    int num_threads = atoi(argv[3]);
    if(num_threads < 1){
	fprintf(stderr, "number of threads must be larger than 1 (not supporting %d\n", num_threads);
	return 1;
    }

    char** argv_end = argv + argc;
    for(char** v=argv+4; v!=argv_end; v++){
	if(strcmp(*v, "--hyper") == 0)
	    hyperthreading = true;
	else if(strcmp(*v, "--pcm") == 0)
	    pcm_enabled = true;
	else if(strcmp(*v, "--mem") == 0)
	    memory_bandwidth = true;
	else if(strcmp(*v, "--numa") == 0)
	    numa = true;
	else{
	    fprintf(stderr, "unkown option: %s\n", *v);
	    return 1;
	}
    }

    /*
    if(memory_bandwidth){
	if(geteuid() != 0){
	    fprintf(stderr, "Must be the root user to measure memory bandwidth\n");
	    return 1;
	}
	fprintf(stderr, "Measuring memory bandwidth\n");
	PCM_memory::InitMemoryMonitor();
    }

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

    int init_num = 50000000;
    int run_num = 50000000;
    benchmark_t<Key_t>* bench = new benchmark_t<Key_t>(pcm_enabled);

    Pair<Key_t>* init_kv = new Pair<Key_t>[init_num];
    Pair<Key_t>* run_kv = new Pair<Key_t>[run_num];
    int* ops = new int[run_num];

    memset(&init_kv[0], 0x0, sizeof(Pair<Key_t>)*init_num);
    memset(&run_kv[0], 0x0, sizeof(Pair<Key_t>)*run_num);

    bench->ycsb_load(workload_type, index_type, init_kv, init_num, run_kv, run_num, ops);
    bench->ycsb_exec(workload_type, index_type, init_kv, init_num, run_kv, run_num, num_threads, ops, pcm_enabled);
    //bench->ycsb_exec(workload_type, index_type, init_kv, init_num, run_kv, run_num, num_threads, ops, memory_bandwidth, numa);
    return 0;
#endif
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x2, -0x8(%rbp)
jge 0x732b
movq 0x52d5e(%rip), %rdi     # 0x59fb8
leaq 0x3aebb(%rip), %rsi     # 0x4211c
callq 0x6400
movq %rax, %rdi
movq 0x52d30(%rip), %rsi     # 0x59fa0
callq 0x6460
movq 0x52d3c(%rip), %rdi     # 0x59fb8
leaq 0x3aea1(%rip), %rsi     # 0x42124
callq 0x6400
movq %rax, %rdi
movq 0x52d0e(%rip), %rsi     # 0x59fa0
callq 0x6460
movq 0x52d1a(%rip), %rdi     # 0x59fb8
leaq 0x3ae9c(%rip), %rsi     # 0x42141
callq 0x6400
movq %rax, %rdi
movq 0x52cec(%rip), %rsi     # 0x59fa0
callq 0x6460
movq 0x52cf8(%rip), %rdi     # 0x59fb8
leaq 0x3ae85(%rip), %rsi     # 0x4214c
callq 0x6400
movq %rax, %rdi
movq 0x52cca(%rip), %rsi     # 0x59fa0
callq 0x6460
movq 0x52cd6(%rip), %rdi     # 0x59fb8
leaq 0x3ae71(%rip), %rsi     # 0x4215a
callq 0x6400
movq %rax, %rdi
movq 0x52ca8(%rip), %rsi     # 0x59fa0
callq 0x6460
movq 0x52cb4(%rip), %rdi     # 0x59fb8
leaq 0x3ae7f(%rip), %rsi     # 0x4218a
callq 0x6400
movq %rax, %rdi
movq 0x52c86(%rip), %rsi     # 0x59fa0
callq 0x6460
movl $0x1, -0x4(%rbp)
jmp 0x7564
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
leaq 0x3ae5f(%rip), %rsi     # 0x42199
callq 0x6590
cmpl $0x0, %eax
jne 0x734d
movl $0x0, -0x14(%rbp)
jmp 0x73c1
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
leaq 0x3ae41(%rip), %rsi     # 0x4219d
callq 0x6590
cmpl $0x0, %eax
jne 0x736f
movl $0x2, -0x14(%rbp)
jmp 0x73bf
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
leaq 0x3adbf(%rip), %rsi     # 0x4213d
callq 0x6590
cmpl $0x0, %eax
jne 0x7391
movl $0x1, -0x14(%rbp)
jmp 0x73bd
movq 0x52c28(%rip), %rax     # 0x59fc0
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdx
leaq 0x3adf7(%rip), %rsi     # 0x421a1
movb $0x0, %al
callq 0x65c0
movl $0x1, -0x4(%rbp)
jmp 0x7564
jmp 0x73bf
jmp 0x73c1
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x6670
movl %eax, -0x18(%rbp)
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0x6670
movl %eax, -0x1c(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
callq 0x6670
movl %eax, -0x20(%rbp)
cmpl $0x5, -0x8(%rbp)
jle 0x7416
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rdi
callq 0x6670
movl %eax, -0x24(%rbp)
cmpl $0x0, -0x24(%rbp)
jle 0x7414
movb $0x1, 0x5387d(%rip)     # 0x5ac91
jmp 0x7416
movl $0x20, %edi
callq 0x6420
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x50(%rbp)
movzbl 0x53861(%rip), %esi     # 0x5ac92
andl $0x1, %esi
callq 0x14c00
jmp 0x743b
movq -0x50(%rbp), %rax
movq %rax, -0x30(%rbp)
movslq -0x18(%rbp), %rax
movq %rax, -0x60(%rbp)
movl $0x28, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
movq %rdi, -0x68(%rbp)
callq 0x6030
movq %rax, %rcx
movq -0x60(%rbp), %rax
movq %rcx, -0x58(%rbp)
cmpq $0x0, %rax
je 0x74bf
movq -0x58(%rbp), %rax
movq -0x60(%rbp), %rcx
imulq $0x28, %rcx, %rdx
movq %rax, %rcx
addq %rdx, %rcx
movq %rcx, -0x78(%rbp)
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rdi
movq %rdi, -0x80(%rbp)
callq 0x14ce0
jmp 0x74aa
movq -0x78(%rbp), %rcx
movq -0x80(%rbp), %rax
addq $0x28, %rax
cmpq %rcx, %rax
movq %rax, -0x70(%rbp)
jne 0x749b
movq -0x58(%rbp), %rax
movq %rax, -0x48(%rbp)
cmpl $0x1, -0x20(%rbp)
jne 0x7525
movq -0x30(%rbp), %rdi
movl -0x14(%rbp), %esi
movq -0x48(%rbp), %rdx
movl -0x18(%rbp), %ecx
movb 0x537b0(%rip), %al      # 0x5ac91
andb $0x1, %al
movzbl %al, %r8d
callq 0x14d10
jmp 0x755d
movq -0x50(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
movl $0x20, %esi
callq 0x6430
jmp 0x7570
movq -0x68(%rbp), %rsi
movq -0x58(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
callq 0x6830
jmp 0x7570
cmpl $0x2, -0x20(%rbp)
jne 0x7544
movq -0x30(%rbp), %rdi
movl -0x14(%rbp), %esi
movq -0x48(%rbp), %rdx
movl -0x18(%rbp), %ecx
movl -0x1c(%rbp), %r8d
callq 0x15580
jmp 0x755b
movq -0x30(%rbp), %rdi
movl -0x14(%rbp), %esi
movq -0x48(%rbp), %rdx
movl -0x18(%rbp), %ecx
movl -0x1c(%rbp), %r8d
callq 0x15850
jmp 0x755d
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x80, %rsp
popq %rbp
retq
movq -0x38(%rbp), %rdi
callq 0x6780
nopl (%rax)