// File: helchr[P]reMap/main.cpp
// Function: setupMeasure(int, unsigned int, unsigned int, unsigned int, bool)
int setupMeasure(int cpuid, unsigned int channel,unsigned int rank, unsigned int bank, bool bankGroup=false)
{
    struct perf_event_attr pe;
    int fd;

    memset(&pe, 0, sizeof(struct perf_event_attr));

    auto imcs = SysInfo::getImcs();
    if(imcs.size() == 0)
    {
        std::cout << "No memory controller PMU found" << std::endl;
        exit(EXIT_FAILURE);
    }
    auto imc = imcs[channel];
    pe.type = SysInfo::getTypeOfImc(imc);
    pe.size = sizeof(struct perf_event_attr);
    //pe.config = (0b11 << 8) | 0x04; // CAS_COUNT_READ
    //pe.config = (0b00001100 << 8) | 0x04; // CAS_COUNT_WR
    //unsigned int bankBits = 0b00010000;//all banks
    unsigned int bankBits = 0;
    if(bankGroup==true)
    {
        bankBits = 0b00010001 + bank;
    }
    else
    {
        bankBits = bank;
    }
    bankBits = bankBits << 8;
    auto rankBits = 0xb0 + rank;
    auto bits = bankBits | rankBits;
    pe.config = bits ; //umask first followed by event id
    // exact config is in cat /sys/devices/cpu/format/event
    pe.disabled = 1;
    pe.sample_type=PERF_SAMPLE_IDENTIFIER;
    pe.inherit=0;
    pe.exclude_guest=1;

    //how to get per-socket numbers? choose the cpu id in syscall
    //pid = -1 cpu >= 0 -> global measurement
    fd = perf_event_open(&pe, -1, cpuid, -1, 0);
    if (fd == -1) {
        std::cout << "Setup of performance counters failed" << std::endl;
        exit(EXIT_FAILURE);
    }

    return fd;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movb %r8b, %al
movl %edi, -0x4(%rbp)
movl %esi, -0x8(%rbp)
movl %edx, -0xc(%rbp)
movl %ecx, -0x10(%rbp)
andb $0x1, %al
movb %al, -0x11(%rbp)
leaq -0x98(%rbp), %rdi
xorl %esi, %esi
movl $0x80, %edx
callq 0x6310
leaq -0xb8(%rbp), %rdi
callq 0x19e20
leaq -0xb8(%rbp), %rdi
callq 0xc980
cmpq $0x0, %rax
jne 0x97e2
movq 0x3c819(%rip), %rdi     # 0x45fb0
leaq 0x299df(%rip), %rsi     # 0x3317d
callq 0x6570
movq %rax, -0x100(%rbp)
jmp 0x97ac
movq -0x100(%rbp), %rdi
movq 0x3c7ae(%rip), %rsi     # 0x45f68
callq 0x65b0
jmp 0x97c1
movl $0x1, %edi
callq 0x6660
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc0(%rbp)
movl %eax, -0xc4(%rbp)
jmp 0x9985
movl -0x8(%rbp), %eax
movl %eax, %esi
leaq -0xb8(%rbp), %rdi
callq 0xc9a0
movq %rax, %rsi
leaq -0xe8(%rbp), %rdi
callq 0x6260
jmp 0x9804
leaq -0xe8(%rbp), %rdi
callq 0x1a3a0
movl %eax, -0x104(%rbp)
jmp 0x9818
movl -0x104(%rbp), %eax
movl %eax, -0x98(%rbp)
movl $0x80, -0x94(%rbp)
movl $0x0, -0xec(%rbp)
movb -0x11(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x9876
movl -0x10(%rbp), %eax
addl $0x11, %eax
movl %eax, -0xec(%rbp)
jmp 0x987f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc0(%rbp)
movl %eax, -0xc4(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x6a88
jmp 0x9985
movl -0x10(%rbp), %eax
movl %eax, -0xec(%rbp)
movl -0xec(%rbp), %eax
shll $0x8, %eax
movl %eax, -0xec(%rbp)
movl -0xc(%rbp), %eax
addl $0xb0, %eax
movl %eax, -0xf0(%rbp)
movl -0xec(%rbp), %eax
movl -0xf0(%rbp), %ecx
orl %ecx, %eax
movl %eax, -0xf4(%rbp)
movl -0xf4(%rbp), %eax
movq %rax, -0x90(%rbp)
movb -0x70(%rbp), %al
orb $0x1, %al
movb %al, -0x70(%rbp)
movq $0x10000, -0x80(%rbp)   # imm = 0x10000
movb -0x70(%rbp), %al
andb $-0x3, %al
movb %al, -0x70(%rbp)
movb -0x6e(%rbp), %al
orb $0x10, %al
movb %al, -0x6e(%rbp)
movl -0x4(%rbp), %edx
xorl %eax, %eax
movl %eax, %r8d
leaq -0x98(%rbp), %rdi
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
movl %ecx, %esi
callq 0x99a0
movq %rax, -0x110(%rbp)
jmp 0x9901
movq -0x110(%rbp), %rax
movl %eax, -0x9c(%rbp)
cmpl $-0x1, -0x9c(%rbp)
jne 0x9952
movq 0x3c692(%rip), %rdi     # 0x45fb0
leaq 0x29877(%rip), %rsi     # 0x3319c
callq 0x6570
movq %rax, -0x118(%rbp)
jmp 0x9933
movq -0x118(%rbp), %rdi
movq 0x3c627(%rip), %rsi     # 0x45f68
callq 0x65b0
jmp 0x9948
movl $0x1, %edi
callq 0x6660
movl -0x9c(%rbp), %eax
movl %eax, -0x11c(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x6a88
leaq -0xb8(%rbp), %rdi
callq 0xc9c0
movl -0x11c(%rbp), %eax
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
leaq -0xb8(%rbp), %rdi
callq 0xc9c0
movq -0xc0(%rbp), %rdi
callq 0x6950
nopl (%rax)