// File: /workspace/github_cpp_makefile_star2_O3/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 0x29cf
movq 0x1275d(%rip), %rbx     # 0x14fc0
leaq 0xb926(%rip), %rsi      # 0xe190
movl $0x7, %edx
movq %rbx, %rdi
callq 0x2210
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21d0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2120
leaq 0xb8f3(%rip), %rsi      # 0xe198
movl $0x1c, %edx
movq %rbx, %rdi
callq 0x2210
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21d0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2120
leaq 0xb8d5(%rip), %rsi      # 0xe1b5
movl $0xa, %edx
movq %rbx, %rdi
callq 0x2210
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21d0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2120
leaq 0xb8a5(%rip), %rsi      # 0xe1c0
movl $0xd, %edx
movq %rbx, %rdi
callq 0x2210
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21d0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2120
leaq 0xb878(%rip), %rsi      # 0xe1ce
movl $0x2f, %edx
movq %rbx, %rdi
callq 0x2210
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21d0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2120
leaq 0xb86d(%rip), %rsi      # 0xe1fe
movl $0xe, %edx
movq %rbx, %rdi
callq 0x2210
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21d0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2120
movl $0x1, %eax
jmp 0x2b12
movq %rsi, %r15
movl %edi, %r13d
movq 0x8(%rsi), %rbx
leaq 0xb82d(%rip), %rsi      # 0xe20d
movq %rbx, %rdi
callq 0x2250
testl %eax, %eax
je 0x2a21
leaq 0xb81e(%rip), %rsi      # 0xe211
movq %rbx, %rdi
callq 0x2250
testl %eax, %eax
je 0x2a25
leaq 0xb7ab(%rip), %rsi      # 0xe1b1
movq %rbx, %rdi
callq 0x2250
movl $0x1, %ebx
testl %eax, %eax
je 0x2a2a
movq %r15, %rdi
callq 0x2380
jmp 0x29c5
xorl %ebx, %ebx
jmp 0x2a2a
movl $0x2, %ebx
movq 0x10(%r15), %rdi
callq 0x22c0
movl %eax, %ebp
movq 0x18(%r15), %rdi
callq 0x22c0
movl %eax, %r14d
movq 0x20(%r15), %rdi
callq 0x22c0
movl %eax, %r12d
cmpl $0x6, %r13d
jb 0x2a67
movq 0x28(%r15), %rdi
callq 0x22c0
testl %eax, %eax
jle 0x2a67
movb $0x1, 0x1285a(%rip)     # 0x152c1
movl $0x20, %edi
callq 0x21f0
movq %rax, %r15
xorl %eax, %eax
movq %rax, (%r15)
movq %rax, 0x18(%r15)
movslq %ebp, %r13
movl $0x28, %ecx
movq %r13, %rax
mulq %rcx
movq $-0x1, %rdi
cmovnoq %rax, %rdi
callq 0x2030
testl %ebp, %ebp
je 0x2ac5
shlq $0x3, %r13
leaq (,%r13,4), %rcx
addq %r13, %rcx
xorl %edx, %edx
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rax,%rdx)
movups %xmm0, (%rax,%rdx)
addq $0x28, %rdx
cmpq %rdx, %rcx
jne 0x2ab3
cmpl $0x2, %r12d
je 0x2aea
cmpl $0x1, %r12d
jne 0x2afe
movzbl 0x127e8(%rip), %r8d     # 0x152c1
movq %r15, %rdi
movl %ebx, %esi
movq %rax, %rdx
movl %ebp, %ecx
callq 0x7e9e
jmp 0x2b10
movq %r15, %rdi
movl %ebx, %esi
movq %rax, %rdx
movl %ebp, %ecx
movl %r14d, %r8d
callq 0x8718
jmp 0x2b10
movq %r15, %rdi
movl %ebx, %esi
movq %rax, %rdx
movl %ebp, %ecx
movl %r14d, %r8d
callq 0x8a10
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop