// File: /workspace/github_cpp_makefile_star2_O1/gulshan216[P]Perceptron_Based_Reuse_Prediction/efectiu.cc
// Function: main
int main (int argc, char *argv[]) {
	int i;

	assert (argc >= 2);
	ncores = argc - 1;
	nthreads = ncores;
	if (ncores > MAX_CORES) ncores = MAX_CORES;

	// initialize private caches and trace readers

	for (i=0; i<nthreads; i++) {
		readers[i] = new tracereader (argv[i+1]);
	}
	GET_PARAM ("DAN_POLICY", dan_policy);
	GET_LL_PARAM ("DAN_MAX_INST", dan_max_inst);
	GET_LL_PARAM ("DAN_MAX_CYCLE", dan_max_cycle);
	GET_PARAM ("DAN_WARM_INST", dan_warm_inst);
	GET_PARAM ("DAN_SET_SHIFT", dan_set_shift);
	char *s = getenv ("BENCHMARK_NAME");
	if (s) strcpy (benchmark_name, s); else strcpy (benchmark_name, "unknown");

	// initialize last-level cache

	init_cache (
		&LLC, 		// pointer to last-level cache data structure
		LLC_NSETS, 	// number of sets in last-level cache
		LLC_ASSOC, 	// last-level cache associativity
		LLC_BLOCKSIZE, 	// last-level cache block size
		dan_policy, 	// last-level cache replacement policy; 0=lru, 1=rand, etc. as in CRC
		dan_set_shift);	// number of lower-order bits in set index to ignore; safe to set to 0 here

	printf ("LLC %d bytes, %d assoc\n", LLC_NSETS * LLC_ASSOC * LLC_BLOCKSIZE, LLC_ASSOC);
	// prime the traces

	for (i=0; i<nthreads; i++) {
		traces[i] = readers[i]->read();
		assert (traces[i]);
		cycles[i] = traces[i]->cycle;
	}

	// read a lot of traces
	// currently, the trace reader just sets the number of cycles equal to the number of instructions in that thread.
	// after the simulation is done we translate this to estimated cycles using misses and a linear model.
	
	long long int iterations = 0;
	bool done_cycle = false;
	bool done_inst = false;
	for (;;) {

		// see which trace comes first in terms of cycle count (i.e. instruction count for now)

		int min_cycle_thread = -1;
		for (int j=0; j<nthreads; j++) {
			if (min_cycle_thread == -1) {
				if (traces[j]) min_cycle_thread = j;
			} else {
				if (traces[j] && (traces[j]->cycle < traces[min_cycle_thread]->cycle)) min_cycle_thread = j;
			}
			last_insts[j] = traces[j]->instr;// readers[j]->get_icount();
			if (warming && last_insts[j] > dan_warm_inst) {
				warming = false;
				fprintf (stderr, "stopped warming at thread %d with %lld instructions...\n", j, last_insts[j]);
				fflush (stderr);
				for (int i=0; i<ncores; i++) {
					l3_misses_at_warming[i] = l3_misses[i];
				}
				memcpy (cycles_at_warming, cycles, sizeof (cycles));
				for (int z=0; z<nthreads; z++) {
					insts_at_warming[z] = readers[z]->get_icount();
				}
			}
		}
		// all traces have been read, we're done

		if (min_cycle_thread == -1) {
			fprintf (stderr, "all done\n");
			for (int i=0; i<ncores; i++) printf ("icount core %d: %lld\n", i, readers[i]->get_icount());
			break;
		}

		// make t point to the oldest trace

		trace *t = traces[min_cycle_thread];

		// figure out what kind of operation this is; if it is a
		// branch then we don't need to know that.  if it is a iread
		// or dread, or write, then we need it.

		// put the core ID in the address so we have no coherence issues 

		t->address &= 0x00ffffffffffffffull;
		t->address |= (((unsigned long long) min_cycle_thread % MAX_CORES) << 56);

		bool use_cache = true;
		bool use_br = false;
		switch (t->cmd) {
			case DAN_IREAD: 
			case DAN_PREFETCH:
			case DAN_DREAD:
			case DAN_WRITEBACK:
			case DAN_WRITE: use_cache = true; break;
			case DAN_BRTAKEN: 
			case DAN_BRUNTAKEN: 
			case DAN_BRIND:
				assert (0);
				use_cache = false; 
				use_br = true; break;
			default: assert (use_br && 0);
		}
		if (use_cache) {
			// simulate memory access with this trace

			unsigned int miss;
			miss = memory_access (NULL, NULL, &LLC, t->address, t->pc, t->size, t->cmd, min_cycle_thread % MAX_CORES);
			if (miss & 4) l3_misses[min_cycle_thread%MAX_CORES]++;
		}

		// replace the oldest trace with a new trace from the same trace file

		if (traces[min_cycle_thread]) {
			traces[min_cycle_thread] = readers[min_cycle_thread]->read();
			if (traces[min_cycle_thread]) 
				cycles[min_cycle_thread] = traces[min_cycle_thread]->cycle;
		}
		if (iterations && iterations % 100000000 == 0) {
			printf ("core 0 icount = %lld\n", readers[0]->get_icount());
			print_stats ();
		}
		iterations++;

		// see if we are done in terms of getting to the maximum number of instructions for some thread

		//done_cycle = true;
		done_cycle = false;
		done_inst = false;
		// all threads must have executed at least this many cycles or we're not done,
		// or at least one thread must have executed at least this many instructions or we're not done
		for (int j=0; j<nthreads; j++) {
			if (readers[j]->get_cycles() < dan_max_cycle) {
				done_cycle = false;
			}
			if (readers[j]->get_icount() >= dan_max_inst) {
				printf ("thread %d reached %lld instructions; stopping\n", j, readers[j]->get_icount());
				done_inst = true;
			}
		}
		if (done_cycle) {
			printf ("all threads have reached at least %lld cycles; stopping\n", dan_max_cycle);
			break;
		}
		if (done_inst) break;
	}
	print_stats ();
	if (traceout) fclose (traceout);
	//for (i=0; i<ncores; i++) delete readers[i];
	if (mintracefp) fclose (mintracefp);
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
cmpl $0x1, %edi
jle 0x40574e
movq %rsi, %rbx
leal -0x1(%rdi), %eax
movl %eax, 0x1f8e0d(%rip)    # 0x5fe0c8
movl %eax, 0x1f8e0b(%rip)    # 0x5fe0cc
cmpl $0x12, %edi
jl 0x4052d0
movl $0x10, 0x1f8df8(%rip)   # 0x5fe0c8
cmpl $0x0, 0x1f8df5(%rip)    # 0x5fe0cc
jle 0x405318
leaq 0x1f7ce0(%rip), %r15    # 0x5fcfc0
xorl %r12d, %r12d
movl $0x450, %edi            # imm = 0x450
callq 0x417bd0
movq %rax, %r14
movq 0x8(%rbx,%r12,8), %rsi
movl $0x3b9aca00, %edx       # imm = 0x3B9ACA00
movq %rax, %rdi
callq 0x405ac6
incq %r12
movq %r14, (%r15)
movslq 0x1f8dbd(%rip), %rax    # 0x5fe0cc
addq $0x8, %r15
cmpq %rax, %r12
jl 0x4052e3
leaq 0x184400(%rip), %rdi    # 0x58971f
callq 0x4d2e60
testq %rax, %rax
jne 0x4056b0
leaq 0x1843fd(%rip), %rdi    # 0x589731
callq 0x4d2e60
testq %rax, %rax
jne 0x4056bd
leaq 0x184403(%rip), %rdi    # 0x58974c
callq 0x4d2e60
testq %rax, %rax
jne 0x4056ca
leaq 0x1843fc(%rip), %rdi    # 0x58975a
callq 0x4d2e60
testq %rax, %rax
jne 0x4056d7
leaq 0x1843f5(%rip), %rdi    # 0x589768
callq 0x4d2e60
testq %rax, %rax
jne 0x4056e4
leaq 0x1843ee(%rip), %rdi    # 0x589776
callq 0x4d2e60
testq %rax, %rax
je 0x4053a3
leaq 0x1fad87(%rip), %rdi    # 0x600120
movq %rax, %rsi
callq 0x401078
jmp 0x4053b4
movabsq $0x6e776f6e6b6e75, %rax # imm = 0x6E776F6E6B6E75
movq %rax, 0x1fad6c(%rip)    # 0x600120
movl 0x1fad59(%rip), %r8d    # 0x600114
movl 0x1fad4e(%rip), %r9d    # 0x600110
leaq 0x1f7b5f(%rip), %rdi    # 0x5fcf28
movl $0x1000, %esi           # imm = 0x1000
movl $0x10, %edx
movl $0x40, %ecx
callq 0x404a7e
leaq 0x1843a1(%rip), %rdi    # 0x589785
movl $0x400000, %esi         # imm = 0x400000
movl $0x10, %edx
xorl %eax, %eax
callq 0x4de520
cmpl $0x0, 0x1f8cd0(%rip)    # 0x5fe0cc
leaq 0x1f83bd(%rip), %r14    # 0x5fd7c0
jle 0x405449
xorl %ebx, %ebx
leaq 0x1f7bb2(%rip), %r15    # 0x5fcfc0
leaq 0x1f94fb(%rip), %r12    # 0x5fe910
xorl %r13d, %r13d
movq (%rbx,%r15), %rdi
callq 0x405b22
movq %rax, (%rbx,%r14)
testq %rax, %rax
je 0x4056f1
movq 0x20(%rax), %rax
movq %rax, (%rbx,%r12)
incq %r13
movslq 0x1f8c8c(%rip), %rax    # 0x5fe0cc
addq $0x8, %rbx
cmpq %rax, %r13
jl 0x405418
leaq 0x1f8cc0(%rip), %r15    # 0x5fe110
xorl %ebp, %ebp
cmpl $0x0, 0x1f8c73(%rip)    # 0x5fe0cc
jle 0x4054e7
movl $0xffffffff, %r12d      # imm = 0xFFFFFFFF
xorl %r13d, %r13d
xorl %ebx, %ebx
movq (%r13,%r14), %rax
cmpl $-0x1, %r12d
je 0x405495
testq %rax, %rax
je 0x4054a5
movq 0x20(%rax), %rcx
movslq %r12d, %rax
movq (%r14,%rax,8), %rdx
movl %ebx, %eax
cmpq 0x20(%rdx), %rcx
jb 0x405490
movl %r12d, %eax
movl %eax, %r12d
jmp 0x4054a5
cmpq $0x1, %rax
movl $0x0, %r12d
sbbl %r12d, %r12d
orl %ebx, %r12d
movq (%r13,%r14), %rax
movq 0x18(%rax), %rsi
movq %rsi, (%r13,%r15)
cmpb $0x1, 0x1f556e(%rip)    # 0x5faa28
jne 0x4054c8
movslq 0x1f5569(%rip), %rax    # 0x5faa2c
cmpq %rax, %rsi
jg 0x4054dd
incq %rbx
movslq 0x1f8bfa(%rip), %rax    # 0x5fe0cc
addq $0x8, %r13
cmpq %rax, %rbx
jl 0x40546a
jmp 0x4054ed
movq %rbx, %rdi
callq 0x401273
jmp 0x4054c8
movl $0xffffffff, %r12d      # imm = 0xFFFFFFFF
cmpl $-0x1, %r12d
je 0x40565b
movslq %r12d, %rbx
movq (%r14,%rbx,8), %rdx
movq 0x10(%rdx), %rax
movabsq $0xffffffffffffff, %rcx # imm = 0xFFFFFFFFFFFFFF
andq %rcx, %rax
movl %r12d, %ecx
andl $0xf, %ecx
shlq $0x38, %rcx
orq %rax, %rcx
movq %rcx, 0x10(%rdx)
movl (%rdx), %eax
cmpl $0x7, %eax
leaq 0x1842f5(%rip), %r13    # 0x589821
ja 0x40572f
movl $0xc7, %esi
btl %eax, %esi
jae 0x405710
movq 0x8(%rdx), %r8
movl 0x4(%rdx), %r9d
leal 0xf(%r12), %edx
testl %r12d, %r12d
cmovnsl %r12d, %edx
andl $-0x10, %edx
subl %edx, %r12d
xorl %edi, %edi
xorl %esi, %esi
leaq 0x1f79c3(%rip), %rdx    # 0x5fcf28
pushq %r12
pushq %rax
callq 0x405260
addq $0x10, %rsp
testb $0x4, %al
je 0x405583
movslq %r12d, %rax
leaq 0x1f8a41(%rip), %rcx    # 0x5fdfc0
incq (%rcx,%rax,8)
cmpq $0x0, (%r14,%rbx,8)
je 0x4055b2
leaq 0x1f7a2f(%rip), %rax    # 0x5fcfc0
movq (%rax,%rbx,8), %rdi
callq 0x405b22
movq %rax, (%r14,%rbx,8)
testq %rax, %rax
je 0x4055b2
movq 0x20(%rax), %rax
leaq 0x1f9362(%rip), %rcx    # 0x5fe910
movq %rax, (%rcx,%rbx,8)
movq %rbp, %rax
movabsq $0x55e63b88c230e77f, %rcx # imm = 0x55E63B88C230E77F
imulq %rcx
testq %rbp, %rbp
je 0x405602
movq %rdx, %rax
shrq $0x3f, %rax
sarq $0x19, %rdx
addq %rax, %rdx
imulq $0x5f5e100, %rdx, %rax  # imm = 0x5F5E100
movq %rbp, %rcx
subq %rax, %rcx
jne 0x405602
movq 0x1f79d5(%rip), %rax    # 0x5fcfc0
movq 0x30(%rax), %rsi
leaq 0x184215(%rip), %rdi    # 0x58980b
xorl %eax, %eax
callq 0x4de520
callq 0x405785
incq %rbp
cmpl $0x0, 0x1f8ac0(%rip)    # 0x5fe0cc
jle 0x40564f
xorl %ebx, %ebx
leaq 0x1f79a9(%rip), %r12    # 0x5fcfc0
xorl %eax, %eax
movq (%r12), %rcx
movq 0x30(%rcx), %rdx
cmpq 0x1f5408(%rip), %rdx    # 0x5faa30
jb 0x405638
movq %r13, %rdi
movl %ebx, %esi
xorl %eax, %eax
callq 0x4de520
movb $0x1, %al
incq %rbx
movslq 0x1f8a8a(%rip), %rcx    # 0x5fe0cc
addq $0x8, %r12
cmpq %rcx, %rbx
jl 0x405619
xorb $0x1, %al
jmp 0x405651
movb $0x1, %al
testb $0x1, %al
jne 0x405452
jmp 0x405678
movq %rbp, %rdi
leaq 0xf(%rsp), %rsi
leaq 0x10(%rsp), %rdx
callq 0x401313
movb 0xf(%rsp), %al
movq 0x10(%rsp), %rbp
jmp 0x405651
callq 0x405785
movq 0x1fae84(%rip), %rdi    # 0x600508
testq %rdi, %rdi
je 0x40568e
callq 0x4ecba0
movq 0x1f791b(%rip), %rdi    # 0x5fcfb0
testq %rdi, %rdi
je 0x40569f
callq 0x4ecba0
xorl %eax, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rdi
callq 0x401140
jmp 0x40532d
movq %rax, %rdi
callq 0x40117d
jmp 0x405342
movq %rax, %rdi
callq 0x4011bb
jmp 0x405357
movq %rax, %rdi
callq 0x4011f9
jmp 0x40536c
movq %rax, %rdi
callq 0x401236
jmp 0x405381
leaq 0x1840a5(%rip), %rdi    # 0x58979d
leaq 0x183ffe(%rip), %rsi    # 0x5896fd
leaq 0x184002(%rip), %rcx    # 0x589708
movl $0x77, %edx
callq 0x4cc560
leaq 0x1840f2(%rip), %rdi    # 0x589809
leaq 0x183fdf(%rip), %rsi    # 0x5896fd
leaq 0x183fe3(%rip), %rcx    # 0x589708
movl $0xbb, %edx
callq 0x4cc560
leaq 0x1840c9(%rip), %rdi    # 0x5897ff
leaq 0x183fc0(%rip), %rsi    # 0x5896fd
leaq 0x183fc4(%rip), %rcx    # 0x589708
movl $0xbe, %edx
callq 0x4cc560
leaq 0x183f9e(%rip), %rdi    # 0x5896f3
leaq 0x183fa1(%rip), %rsi    # 0x5896fd
leaq 0x183fa5(%rip), %rcx    # 0x589708
movl $0x56, %edx
callq 0x4cc560
movq %rax, %rbx
movl $0x450, %esi            # imm = 0x450
movq %r14, %rdi
callq 0x416d30
movq %rbx, %rdi
callq 0x4b7900