// File: enfiskutensykkel[P]lamport/src/producer.cpp
// Function: Producer::test_queue(Queue&, unsigned int, unsigned int)
bool Producer::test_queue(Queue& queue, unsigned repetitions, unsigned num_threads)
{
	std::vector<TProducer> tests;

	fprintf(stderr, "Testing %s...\n", queue.type().c_str());

	// Create a barrier to synchronize threads
	pthread_barrier_t barrier;
	if (pthread_barrier_init(&barrier, nullptr, num_threads + 1) != 0)
	{
		assert(false);
		return false;
	}

	// Create and start threads
	fprintf(stderr, "%-25s", "Creating producers");
	for (unsigned i = 0; i < num_threads; ++i)
	{
		try
		{
			tests.push_back(std::make_pair(std::shared_ptr<Producer>( new Producer(barrier, i, queue, repetitions) ), true));
		}
		catch (const std::runtime_error& e)
		{
			fprintf(stderr, "FAIL\n");
			return false;
		}
	}
	fprintf(stderr, "DONE\n");

	// Synchronize with threads
	fprintf(stderr, "%-25s", "Synchronizing threads");
	int ret = pthread_barrier_wait(&barrier);
	if (ret != PTHREAD_BARRIER_SERIAL_THREAD && ret != 0)
	{
		tests.clear(); // this invokes the destructor on all producers
		pthread_barrier_destroy(&barrier);
		fprintf(stderr, "FAIL\n");
		return false;
	}
	fprintf(stderr, "DONE\n");

	// Run tests
	uint64_t duration;
	fprintf(stderr, "%-25s", "Running test");
	try
	{
		duration = test_dequeuing(queue, tests, repetitions);
		fprintf(stderr, "%s\n", "DONE");
	}
	catch (const std::runtime_error& e)
	{
		pthread_barrier_destroy(&barrier);
		fprintf(stderr, "%s\n", "FAIL");
		return false;
	}
	pthread_barrier_destroy(&barrier);
	fprintf(stderr, "\n");

	// Write summary
	fprintf(stdout, "\033[1;96mTest result\033[0m\n");
	fprintf(stdout, "Queue type    : %s\n", queue.type().c_str());
	fprintf(stdout, "Queue capacity: %u slots\n", queue.capacity);
	fprintf(stdout, "Queue size    : %u elements left (%s)\n", queue.size(), queue.empty() && queue.size() == 0 ? "\033[0;92mPASS\033[0m" : "\033[0;91mFAIL\033[0m");
	fprintf(stdout, "Queue elements: %u elements per thread\n", repetitions);
	fprintf(stdout, "Producers     : %u threads\n", num_threads);
	fprintf(stdout, "Total duration: %.5f seconds\n", duration / (1000000000.0));

	unsigned failed = 0;
	for (unsigned i = 0; i < tests.size(); ++i)
	{
		fprintf(stdout, "    %2u\t", i + 1);
		if (!tests[i].second)
		{
			fprintf(stdout, "\033[0;91mFAIL\033[0m\n"); 
			++failed;
		}
		else
		{
			fprintf(stdout, "\033[0;92mPASS\033[0m\n");
		}
	}
	fprintf(stdout, "%u out of %u producer threads passed\n", (num_threads - failed), num_threads);
	fprintf(stdout, "\n");

	return failed == 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x190, %rsp            # imm = 0x190
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x3bb0
movq 0x5fc3(%rip), %rax      # 0x8fd8
movq (%rax), %rax
movq %rax, -0x108(%rbp)
movq -0x10(%rbp), %rsi
movq (%rsi), %rax
movq 0x10(%rax), %rax
leaq -0x50(%rbp), %rdi
callq *%rax
jmp 0x3032
leaq -0x50(%rbp), %rdi
callq 0x2080
movq -0x108(%rbp), %rdi
movq %rax, %rdx
leaq 0x30b4(%rip), %rsi      # 0x6100
movb $0x0, %al
callq 0x21a0
leaq -0x50(%rbp), %rdi
callq 0x20c0
movl -0x18(%rbp), %edx
addl $0x1, %edx
leaq -0x80(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x21f0
cmpl $0x0, %eax
je 0x3098
movb $0x0, -0x1(%rbp)
movl $0x1, -0x84(%rbp)
jmp 0x36fa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0x3711
movq 0x5f39(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x3066(%rip), %rsi      # 0x610f
leaq 0x3065(%rip), %rdx      # 0x6115
movb $0x0, %al
callq 0x21a0
movl $0x0, -0x88(%rbp)
movl -0x88(%rbp), %eax
cmpl -0x18(%rbp), %eax
jae 0x322c
movl $0x28, %edi
callq 0x2130
movq %rax, -0x110(%rbp)
jmp 0x30e3
movq -0x110(%rbp), %rdi
movl -0x88(%rbp), %edx
movq -0x10(%rbp), %rcx
movl -0x14(%rbp), %r8d
leaq -0x80(%rbp), %rsi
callq 0x38c0
jmp 0x3103
movq -0x110(%rbp), %rsi
leaq -0xb0(%rbp), %rdi
callq 0x3c40
jmp 0x3118
movb $0x1, -0xb1(%rbp)
leaq -0xa0(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
leaq -0xb1(%rbp), %rdx
callq 0x3c00
jmp 0x313b
leaq -0x30(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x3bd0
jmp 0x314d
leaq -0xa0(%rbp), %rdi
callq 0x3c70
leaq -0xb0(%rbp), %rdi
callq 0x3c90
jmp 0x3216
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0x31c4
movq -0x110(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
callq 0x2120
jmp 0x31c4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0x31b8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
leaq -0xa0(%rbp), %rdi
callq 0x3c70
leaq -0xb0(%rbp), %rdi
callq 0x3c90
movl -0x5c(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x3711
movq -0x58(%rbp), %rdi
callq 0x2070
movq %rax, -0xc0(%rbp)
movq 0x5ded(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2f33(%rip), %rsi      # 0x6128
xorl %eax, %eax
callq 0x21a0
movb $0x0, -0x1(%rbp)
movl $0x1, -0x84(%rbp)
callq 0x2200
jmp 0x3211
jmp 0x36fa
jmp 0x3218
movl -0x88(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x88(%rbp)
jmp 0x30c1
movq 0x5da5(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2ef1(%rip), %rsi      # 0x612e
movb $0x0, %al
callq 0x21a0
movq 0x5d8d(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2eba(%rip), %rsi      # 0x610f
leaq 0x2ed8(%rip), %rdx      # 0x6134
movb $0x0, %al
callq 0x21a0
leaq -0x80(%rbp), %rdi
callq 0x2160
movl %eax, -0xc4(%rbp)
cmpl $-0x1, -0xc4(%rbp)
je 0x32c1
cmpl $0x0, -0xc4(%rbp)
je 0x32c1
leaq -0x30(%rbp), %rdi
callq 0x3cb0
leaq -0x80(%rbp), %rdi
callq 0x2140
movq 0x5d3b(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2e81(%rip), %rsi      # 0x6128
movb $0x0, %al
callq 0x21a0
movb $0x0, -0x1(%rbp)
movl $0x1, -0x84(%rbp)
jmp 0x36fa
movq 0x5d10(%rip), %rax      # 0x8fd8
movq %rax, -0x128(%rbp)
movq (%rax), %rdi
leaq 0x2e55(%rip), %rsi      # 0x612e
xorl %eax, %eax
movb %al, -0x119(%rbp)
callq 0x21a0
movq -0x128(%rbp), %rcx
movb -0x119(%rbp), %al
movq (%rcx), %rdi
leaq 0x2e12(%rip), %rsi      # 0x610f
leaq 0x2e46(%rip), %rdx      # 0x614a
callq 0x21a0
movq -0x10(%rbp), %rdi
movl -0x14(%rbp), %edx
leaq -0x30(%rbp), %rsi
callq 0x3730
movq %rax, -0x118(%rbp)
jmp 0x3322
movq -0x118(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq 0x5ca1(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2e48(%rip), %rsi      # 0x6189
leaq 0x2e0f(%rip), %rdx      # 0x6157
movb $0x0, %al
callq 0x21a0
jmp 0x33bf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
movl -0x5c(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x3711
movq -0x58(%rbp), %rdi
callq 0x2070
movq %rax, -0xd8(%rbp)
leaq -0x80(%rbp), %rdi
callq 0x2140
movq 0x5c4b(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2df2(%rip), %rsi      # 0x6189
leaq 0x2dbe(%rip), %rdx      # 0x615c
xorl %eax, %eax
callq 0x21a0
movb $0x0, -0x1(%rbp)
movl $0x1, -0x84(%rbp)
callq 0x2200
jmp 0x33ba
jmp 0x36fa
leaq -0x80(%rbp), %rdi
callq 0x2140
movq 0x5c09(%rip), %rax      # 0x8fd8
movq (%rax), %rdi
leaq 0x2df3(%rip), %rsi      # 0x61cc
xorl %eax, %eax
movb %al, -0x139(%rbp)
callq 0x21a0
movb -0x139(%rbp), %al
movq 0x5bbd(%rip), %rcx      # 0x8fb0
movq %rcx, -0x138(%rbp)
movq (%rcx), %rdi
leaq 0x2d5d(%rip), %rsi      # 0x6161
callq 0x21a0
movq -0x138(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x130(%rbp)
movq -0x10(%rbp), %rsi
movq (%rsi), %rax
movq 0x10(%rax), %rax
leaq -0xf8(%rbp), %rdi
callq *%rax
jmp 0x3430
leaq -0xf8(%rbp), %rdi
movq %rdi, -0x160(%rbp)
callq 0x2080
movq -0x130(%rbp), %rdi
movq %rax, %rdx
leaq 0x2d25(%rip), %rsi      # 0x6179
xorl %eax, %eax
movb %al, -0x151(%rbp)
callq 0x21a0
movq -0x160(%rbp), %rdi
callq 0x20c0
movb -0x151(%rbp), %al
movq 0x5b36(%rip), %rcx      # 0x8fb0
movq %rcx, -0x150(%rbp)
movq (%rcx), %rdi
movq -0x10(%rbp), %rcx
movl 0x8(%rcx), %edx
leaq 0x2cfb(%rip), %rsi      # 0x618d
callq 0x21a0
movq -0x150(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x148(%rbp)
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
movl %eax, -0x140(%rbp)
jmp 0x34bd
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x30(%rax), %rax
callq *%rax
movb %al, -0x161(%rbp)
jmp 0x34d2
movb -0x161(%rbp), %al
testb $0x1, %al
jne 0x34de
jmp 0x350e
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq 0x28(%rax), %rax
callq *%rax
movl %eax, -0x168(%rbp)
jmp 0x34f3
movl -0x168(%rbp), %eax
cmpl $0x0, %eax
jne 0x350e
leaq 0x2cc9(%rip), %rax      # 0x61ce
movq %rax, -0x170(%rbp)
jmp 0x351e
leaq 0x2cc9(%rip), %rax      # 0x61de
movq %rax, -0x170(%rbp)
jmp 0x351e
movl -0x140(%rbp), %edx
movq -0x148(%rbp), %rdi
movq -0x170(%rbp), %rcx
leaq 0x2c6e(%rip), %rsi      # 0x61a7
xorl %eax, %eax
movb %al, -0x179(%rbp)
callq 0x21a0
movb -0x179(%rbp), %al
movq 0x5a5d(%rip), %rcx      # 0x8fb0
movq %rcx, -0x178(%rbp)
movq (%rcx), %rdi
movl -0x14(%rbp), %edx
leaq 0x2c87(%rip), %rsi      # 0x61ee
callq 0x21a0
movq -0x178(%rbp), %rcx
movb -0x179(%rbp), %al
movq (%rcx), %rdi
movl -0x18(%rbp), %edx
leaq 0x2c90(%rip), %rsi      # 0x6216
callq 0x21a0
movq -0x178(%rbp), %rax
movq (%rax), %rdi
movaps 0x2b44(%rip), %xmm1     # 0x60e0
movq -0xd0(%rbp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x2b40(%rip), %xmm1     # 0x60f0
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd 0x2b11(%rip), %xmm1     # 0x60d8
divsd %xmm1, %xmm0
leaq 0x2c60(%rip), %rsi      # 0x6232
movb $0x1, %al
callq 0x21a0
movl $0x0, -0xfc(%rbp)
movl $0x0, -0x100(%rbp)
movl -0x100(%rbp), %eax
movq %rax, -0x188(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x3cd0
movq %rax, %rcx
movq -0x188(%rbp), %rax
cmpq %rcx, %rax
jae 0x36a5
movq 0x5993(%rip), %rax      # 0x8fb0
movq (%rax), %rdi
movl -0x100(%rbp), %edx
addl $0x1, %edx
leaq 0x2c20(%rip), %rsi      # 0x6250
movb $0x0, %al
callq 0x21a0
movl -0x100(%rbp), %eax
movl %eax, %esi
leaq -0x30(%rbp), %rdi
callq 0x3d00
testb $0x1, 0x10(%rax)
jne 0x3677
movq 0x595b(%rip), %rax      # 0x8fb0
movq (%rax), %rdi
leaq 0x2bfa(%rip), %rsi      # 0x6259
movb $0x0, %al
callq 0x21a0
movl -0xfc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xfc(%rbp)
jmp 0x368f
movq 0x5932(%rip), %rax      # 0x8fb0
movq (%rax), %rdi
leaq 0x2be2(%rip), %rsi      # 0x626a
movb $0x0, %al
callq 0x21a0
jmp 0x3691
movl -0x100(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x100(%rbp)
jmp 0x35ed
movq 0x5904(%rip), %rax      # 0x8fb0
movq (%rax), %rdi
movl -0x18(%rbp), %edx
subl -0xfc(%rbp), %edx
movl -0x18(%rbp), %ecx
leaq 0x2bb9(%rip), %rsi      # 0x627b
movb $0x0, %al
callq 0x21a0
movq 0x58e0(%rip), %rax      # 0x8fb0
movq (%rax), %rdi
leaq 0x2af2(%rip), %rsi      # 0x61cc
movb $0x0, %al
callq 0x21a0
cmpl $0x0, -0xfc(%rbp)
sete %al
andb $0x1, %al
movb %al, -0x1(%rbp)
movl $0x1, -0x84(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x3d20
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x190, %rsp            # imm = 0x190
popq %rbp
retq
leaq -0x30(%rbp), %rdi
callq 0x3d20
movq -0x58(%rbp), %rdi
callq 0x2220
nopw %cs:(%rax,%rax)