// File: shreyas-gopalakrishna[P]Concurrent-Skip-list/benchmark.cpp
// Function: main
int main(int argc, char *argv[]){

    static struct option long_options[] = {
        {"name", no_argument, NULL, 'n'},
        {"benchmark", required_argument, NULL, 'b'},
        {"help", no_argument, NULL, 'h'},
        {0, 0, 0, 0}
    };

    //Variables for options
    bool name = false;
    string benchmark = "";
    bool help = false;

    while (true) {
        int option_index = 0;
        int flag_char = getopt_long(argc, argv, "i:t:", long_options, &option_index);
        if (flag_char == -1) {
          break;
        }

        switch (flag_char) {
            case 'n':
                name = true;
                break;
            case 'b':
                benchmark = std::string(optarg);
                break;
            case 'h':
                help = true;
                break;
            case 't':
                num_threads = stoi(optarg);
                break;
            case 'i':
                max_number = stoi(optarg);
                break;
            case '?':
                break;
            default:
                exit(EXIT_FAILURE);
        }
    }

    if(name){
        cout << "\nShreyas Gopalakrishna\n";
    }

    if(help){
        show_usage();
    }

	if(argc > 2){
	    if(benchmark == "" || max_number <= 0 || num_threads < 1 ){
	        show_usage();
	    }else{

	        if(benchmark == "insert"){
                generate_input(max_number);
                skiplist = SkipList(numbers_insert.size(), 0.5);
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                insert_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }
	        else if (benchmark == "delete"){
                generate_input(max_number);
                skiplist = SkipList(numbers_insert.size(), 0.5);
                insert_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                delete_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }else if (benchmark == "search"){
                generate_input(max_number);
                skiplist = SkipList(numbers_insert.size(), 0.5);
                insert_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                search_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }else if (benchmark == "range"){
                generate_input(max_number);
                skiplist = SkipList(numbers_insert.size(), 0.5);
                insert_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                range_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }
            else if (benchmark == "all_operations"){
                generate_input(max_number);
                skiplist = SkipList(numbers_insert.size(), 0.5);
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                all_operations_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }else if (benchmark == "high_contention"){
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                high_contention_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }else if (benchmark == "low_contention"){
                clock_gettime(CLOCK_MONOTONIC,&start_time);
                low_contention_benchmark();
                clock_gettime(CLOCK_MONOTONIC,&end_time);
	        }else{
	            cout << "Invalid benchmark type \n";
	            show_usage();
	        }
            show_elapsed_time();
	    }
    }else{
        show_usage();
    }
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x180, %rsp            # imm = 0x180
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movb $0x0, -0x11(%rbp)
leaq -0x39(%rbp), %rdi
movq %rdi, -0x128(%rbp)
callq 0x33c0
movq -0x128(%rbp), %rdx
leaq 0xa41a(%rip), %rsi      # 0xf115
leaq -0x38(%rbp), %rdi
callq 0x5c40
jmp 0x4d06
leaq -0x39(%rbp), %rdi
callq 0x32a0
movb $0x0, -0x4d(%rbp)
jmp 0x4d15
movl $0x0, -0x54(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0xa84f(%rip), %rdx      # 0xf579
leaq 0x124ff(%rip), %rcx     # 0x17230
leaq -0x54(%rbp), %r8
callq 0x3390
movl %eax, -0x58(%rbp)
cmpl $-0x1, -0x58(%rbp)
jne 0x4d62
jmp 0x4fa9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x39(%rbp), %rdi
callq 0x32a0
jmp 0x5464
movl -0x58(%rbp), %eax
addl $-0x3f, %eax
movl %eax, %ecx
movq %rcx, -0x130(%rbp)
subl $0x35, %eax
ja 0x4f9a
movq -0x130(%rbp), %rax
leaq 0xa2ac(%rip), %rcx      # 0xf034
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, -0x11(%rbp)
jmp 0x4fa4
movq 0x1220f(%rip), %rax     # 0x16fb0
movq (%rax), %rax
movq %rax, -0x140(%rbp)
leaq -0x79(%rbp), %rdi
movq %rdi, -0x138(%rbp)
callq 0x33c0
movq -0x140(%rbp), %rsi
movq -0x138(%rbp), %rdx
leaq -0x78(%rbp), %rdi
callq 0x5c40
jmp 0x4dd4
leaq -0x38(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x3300
leaq -0x78(%rbp), %rdi
callq 0x3170
leaq -0x79(%rbp), %rdi
callq 0x32a0
jmp 0x4fa4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x79(%rbp), %rdi
callq 0x32a0
jmp 0x545b
movb $0x1, -0x4d(%rbp)
jmp 0x4fa4
movq 0x1218e(%rip), %rax     # 0x16fb0
movq (%rax), %rax
movq %rax, -0x150(%rbp)
leaq -0xa1(%rbp), %rdi
movq %rdi, -0x148(%rbp)
callq 0x33c0
movq -0x150(%rbp), %rsi
movq -0x148(%rbp), %rdx
leaq -0xa0(%rbp), %rdi
callq 0x5c40
jmp 0x4e5b
xorl %eax, %eax
movl %eax, %esi
leaq -0xa0(%rbp), %rdi
movl $0xa, %edx
callq 0x5d20
movl %eax, -0x154(%rbp)
jmp 0x4e78
movl -0x154(%rbp), %eax
cltq
movq %rax, 0x12399(%rip)     # 0x17220
leaq -0xa0(%rbp), %rdi
callq 0x3170
leaq -0xa1(%rbp), %rdi
callq 0x32a0
jmp 0x4fa4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x4eca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0xa0(%rbp), %rdi
callq 0x3170
leaq -0xa1(%rbp), %rdi
callq 0x32a0
jmp 0x545b
movq 0x120ce(%rip), %rax     # 0x16fb0
movq (%rax), %rax
movq %rax, -0x168(%rbp)
leaq -0xc9(%rbp), %rdi
movq %rdi, -0x160(%rbp)
callq 0x33c0
movq -0x168(%rbp), %rsi
movq -0x160(%rbp), %rdx
leaq -0xc8(%rbp), %rdi
callq 0x5c40
jmp 0x4f1b
xorl %eax, %eax
movl %eax, %esi
leaq -0xc8(%rbp), %rdi
movl $0xa, %edx
callq 0x5d20
movl %eax, -0x16c(%rbp)
jmp 0x4f38
movl -0x16c(%rbp), %eax
cltq
movq %rax, 0x122e1(%rip)     # 0x17228
leaq -0xc8(%rbp), %rdi
callq 0x3170
leaq -0xc9(%rbp), %rdi
callq 0x32a0
jmp 0x4fa4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x4f87
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0xc8(%rbp), %rdi
callq 0x3170
leaq -0xc9(%rbp), %rdi
callq 0x32a0
jmp 0x545b
jmp 0x4fa4
movl $0x1, %edi
callq 0x32f0
jmp 0x4d13
testb $0x1, -0x11(%rbp)
je 0x4fd7
movq 0x12012(%rip), %rdi     # 0x16fc8
leaq 0xa5c1(%rip), %rsi      # 0xf57e
callq 0x3240
jmp 0x4fc4
jmp 0x4fd7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x545b
testb $0x1, -0x4d(%rbp)
je 0x4fe6
callq 0x36a0
jmp 0x4fe4
jmp 0x4fe6
cmpl $0x2, -0x8(%rbp)
jle 0x5436
leaq 0xa11e(%rip), %rsi      # 0xf115
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x16d(%rbp)
jmp 0x5008
movb -0x16d(%rbp), %al
testb $0x1, %al
jne 0x5028
jmp 0x5014
cmpq $0x0, 0x1220c(%rip)     # 0x17228
jbe 0x5028
cmpq $0x1, 0x121fa(%rip)     # 0x17220
jae 0x5034
callq 0x36a0
jmp 0x502f
jmp 0x5434
leaq 0xa5ce(%rip), %rsi      # 0xf609
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x16e(%rbp)
jmp 0x504c
movb -0x16e(%rbp), %al
testb $0x1, %al
jne 0x5058
jmp 0x50d1
movl 0x121ca(%rip), %edi     # 0x17228
callq 0x3860
jmp 0x5065
leaq 0x12294(%rip), %rdi     # 0x17300
callq 0x55e0
movl %eax, %esi
leaq -0xe0(%rbp), %rdi
movss 0x9fae(%rip), %xmm0     # 0xf030
callq 0xae20
jmp 0x5089
movups -0xe0(%rbp), %xmm0
movups %xmm0, 0x12239(%rip)    # 0x172d0
leaq -0xe0(%rbp), %rdi
callq 0xca30
leaq 0x12236(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x3ce0
jmp 0x50bb
movl $0x1, %edi
leaq 0x12229(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x542b
leaq 0xa4be(%rip), %rsi      # 0xf596
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x16f(%rbp)
jmp 0x50e9
movb -0x16f(%rbp), %al
testb $0x1, %al
jne 0x50f8
jmp 0x5178
movl 0x1212a(%rip), %edi     # 0x17228
callq 0x3860
jmp 0x5105
leaq 0x121f4(%rip), %rdi     # 0x17300
callq 0x55e0
movl %eax, %esi
leaq -0xf0(%rbp), %rdi
movss 0x9f0e(%rip), %xmm0     # 0xf030
callq 0xae20
jmp 0x5129
movups -0xf0(%rbp), %xmm0
movups %xmm0, 0x12199(%rip)    # 0x172d0
leaq -0xf0(%rbp), %rdi
callq 0xca30
callq 0x3ce0
jmp 0x514a
leaq 0x1218f(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x3ed0
jmp 0x5162
movl $0x1, %edi
leaq 0x12182(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x5429
leaq 0xa41e(%rip), %rsi      # 0xf59d
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x170(%rbp)
jmp 0x5190
movb -0x170(%rbp), %al
testb $0x1, %al
jne 0x519f
jmp 0x521f
movl 0x12083(%rip), %edi     # 0x17228
callq 0x3860
jmp 0x51ac
leaq 0x1214d(%rip), %rdi     # 0x17300
callq 0x55e0
movl %eax, %esi
leaq -0x100(%rbp), %rdi
movss 0x9e67(%rip), %xmm0     # 0xf030
callq 0xae20
jmp 0x51d0
movups -0x100(%rbp), %xmm0
movups %xmm0, 0x120f2(%rip)    # 0x172d0
leaq -0x100(%rbp), %rdi
callq 0xca30
callq 0x3ce0
jmp 0x51f1
leaq 0x120e8(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x40c0
jmp 0x5209
movl $0x1, %edi
leaq 0x120db(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x5427
leaq 0xa37e(%rip), %rsi      # 0xf5a4
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x171(%rbp)
jmp 0x5237
movb -0x171(%rbp), %al
testb $0x1, %al
jne 0x5246
jmp 0x52c6
movl 0x11fdc(%rip), %edi     # 0x17228
callq 0x3860
jmp 0x5253
leaq 0x120a6(%rip), %rdi     # 0x17300
callq 0x55e0
movl %eax, %esi
leaq -0x110(%rbp), %rdi
movss 0x9dc0(%rip), %xmm0     # 0xf030
callq 0xae20
jmp 0x5277
movups -0x110(%rbp), %xmm0
movups %xmm0, 0x1204b(%rip)    # 0x172d0
leaq -0x110(%rbp), %rdi
callq 0xca30
callq 0x3ce0
jmp 0x5298
leaq 0x12041(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x42b0
jmp 0x52b0
movl $0x1, %edi
leaq 0x12034(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x5425
leaq 0xa2dd(%rip), %rsi      # 0xf5aa
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x172(%rbp)
jmp 0x52de
movb -0x172(%rbp), %al
testb $0x1, %al
jne 0x52ea
jmp 0x5363
movl 0x11f38(%rip), %edi     # 0x17228
callq 0x3860
jmp 0x52f7
leaq 0x12002(%rip), %rdi     # 0x17300
callq 0x55e0
movl %eax, %esi
leaq -0x120(%rbp), %rdi
movss 0x9d1c(%rip), %xmm0     # 0xf030
callq 0xae20
jmp 0x531b
movups -0x120(%rbp), %xmm0
movups %xmm0, 0x11fa7(%rip)    # 0x172d0
leaq -0x120(%rbp), %rdi
callq 0xca30
leaq 0x11fa4(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x46b0
jmp 0x534d
movl $0x1, %edi
leaq 0x11f97(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x5423
leaq 0xa24f(%rip), %rsi      # 0xf5b9
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x173(%rbp)
jmp 0x537b
movb -0x173(%rbp), %al
testb $0x1, %al
jne 0x5387
jmp 0x53b2
leaq 0x11f52(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x4790
jmp 0x539f
movl $0x1, %edi
leaq 0x11f45(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x5421
leaq 0xa210(%rip), %rsi      # 0xf5c9
leaq -0x38(%rbp), %rdi
callq 0x5d60
movb %al, -0x174(%rbp)
jmp 0x53ca
movb -0x174(%rbp), %al
testb $0x1, %al
jne 0x53d6
jmp 0x5401
leaq 0x11f03(%rip), %rsi     # 0x172e0
movl $0x1, %edi
callq 0x3230
callq 0x4a20
jmp 0x53ee
movl $0x1, %edi
leaq 0x11ef6(%rip), %rsi     # 0x172f0
callq 0x3230
jmp 0x541f
movq 0x11bc0(%rip), %rdi     # 0x16fc8
leaq 0xa1c9(%rip), %rsi      # 0xf5d8
callq 0x3240
jmp 0x5416
callq 0x36a0
jmp 0x541d
jmp 0x541f
jmp 0x5421
jmp 0x5423
jmp 0x5425
jmp 0x5427
jmp 0x5429
jmp 0x542b
callq 0x37c0
jmp 0x5432
jmp 0x5434
jmp 0x543f
callq 0x36a0
jmp 0x543d
jmp 0x543f
movl $0x0, -0x4(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x3170
movl -0x4(%rbp), %eax
addq $0x180, %rsp            # imm = 0x180
popq %rbp
retq
leaq -0x38(%rbp), %rdi
callq 0x3170
movq -0x48(%rbp), %rdi
callq 0x33b0
nopl (%rax)