// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
cmpl $0x1, %edi
jg 0x27f6
movq 0x1185c(%rip), %rbx     # 0x13fc0
leaq 0x99ed(%rip), %rsi      # 0xc158
movq %rbx, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20c0
leaq 0x99de(%rip), %rsi      # 0xc160
movq %rbx, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20c0
leaq 0x99e4(%rip), %rsi      # 0xc17d
movq %rbx, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20c0
leaq 0x99d8(%rip), %rsi      # 0xc188
movq %rbx, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20c0
leaq 0x99cf(%rip), %rsi      # 0xc196
movq %rbx, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20c0
leaq 0x99e8(%rip), %rsi      # 0xc1c6
movq %rbx, %rdi
callq 0x21d0
movq %rax, %rdi
callq 0x20c0
pushq $0x1
popq %rax
jmp 0x291d
movq %rsi, %r15
movl %edi, %r13d
movq 0x8(%rsi), %rbx
leaq 0x99ce(%rip), %rsi      # 0xc1d5
movq %rbx, %rdi
callq 0x2260
testl %eax, %eax
je 0x2841
leaq 0x99bf(%rip), %rsi      # 0xc1d9
movq %rbx, %rdi
callq 0x2260
testl %eax, %eax
je 0x2845
leaq 0x994c(%rip), %rsi      # 0xc179
movq %rbx, %rdi
callq 0x2260
testl %eax, %eax
jne 0x292c
pushq $0x1
jmp 0x2847
xorl %ebx, %ebx
jmp 0x2848
pushq $0x2
popq %rbx
movq 0x10(%r15), %rdi
callq 0x22d0
movl %eax, %ebp
movq 0x18(%r15), %rdi
callq 0x22d0
movl %eax, %r14d
movq 0x20(%r15), %rdi
callq 0x22d0
movl %eax, %r12d
cmpl $0x6, %r13d
jb 0x2885
movq 0x28(%r15), %rdi
callq 0x22d0
testl %eax, %eax
jle 0x2885
movb $0x1, 0x11a4c(%rip)     # 0x142d1
pushq $0x20
popq %rdi
callq 0x21e0
movq %rax, %r15
andq $0x0, (%rax)
andq $0x0, 0x18(%rax)
movslq %ebp, %r13
pushq $0x28
popq %rcx
movq %r13, %rax
mulq %rcx
pushq $-0x1
popq %rdi
cmovnoq %rax, %rdi
callq 0x2030
testl %ebp, %ebp
je 0x28d0
imulq $0x28, %r13, %rcx
xorl %edx, %edx
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rax,%rdx)
movups %xmm0, (%rax,%rdx)
addq $0x28, %rdx
cmpq %rdx, %rcx
jne 0x28be
cmpl $0x2, %r12d
je 0x28f5
cmpl $0x1, %r12d
jne 0x2909
movzbl 0x119ed(%rip), %r8d     # 0x142d1
movq %r15, %rdi
movl %ebx, %esi
movq %rax, %rdx
movl %ebp, %ecx
callq 0x65c8
jmp 0x291b
movq %r15, %rdi
movl %ebx, %esi
movq %rax, %rdx
movl %ebp, %ecx
movl %r14d, %r8d
callq 0x6c20
jmp 0x291b
movq %r15, %rdi
movl %ebx, %esi
movq %rax, %rdx
movl %ebp, %ecx
movl %r14d, %r8d
callq 0x6db8
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x11695(%rip), %rax     # 0x13fc8
movq (%rax), %rdi
movq 0x10(%r15), %rdx
leaq 0x989c(%rip), %rsi      # 0xc1dd
xorl %eax, %eax
callq 0x2270
jmp 0x27ee
nop