//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
using System;
using System.Threading;
using System.Collections;

namespace Benchmark
{
	/// <summary>
	/// Podsumowanie dla ThreadTest.
	/// </summary>
	public class ThreadTest
	{
		private int threadCount;
		private int threadIterations;
		private int threadWork;
		private WorkComplete resourceLock;

		private int startElapsed;
		private int stopElapsed;
		private int totalElapsed;

		private double sumStartElapsed;
		private double sumStopElapsed;
		private double sumTotalElapsed;

		private double averageStartElapsed;
		private double averageStopElapsed;
		private double averageTotalElapsed;

		private double minStartElapsed;
		private double minStopElapsed;
		private double minTotalElapsed;

		private double maxStartElapsed;
		private double maxStopElapsed;
		private double maxTotalElapsed;

		public ThreadTest(int count, int iterations, int work)
		{
			this.threadCount = count;
			this.threadIterations = iterations;
			this.threadWork = work;

			this.startElapsed = 0;
			this.stopElapsed = 0;

			this.sumStartElapsed = 0.0;
			this.sumStopElapsed = 0.0;
			this.sumTotalElapsed = 0.0;

			this.averageStartElapsed = 0.0;
			this.averageStopElapsed = 0.0;
			this.averageTotalElapsed = 0.0;

			this.minStartElapsed = 0.0;
			this.minStopElapsed = 0.0;
			this.minTotalElapsed = 0.0;

			this.maxStartElapsed = 0.0;
			this.maxStopElapsed = 0.0;
			this.maxTotalElapsed = 0.0;
		}
		private void SpinThreads()
		{
			resourceLock.Reset(threadCount);
			int begin, end;
			begin = Environment.TickCount;
			int start = Environment.TickCount;
			try
			{
				for(int count = 0; count < threadCount; count++)
				{
					Thread t = new Thread(new ThreadStart(ThreadEntry));
					t.Start();
				}
			}
			catch(Exception e)
			{
			}

			int stop = Environment.TickCount;
			startElapsed = stop - start;
			start = Environment.TickCount;
			resourceLock.P();
			stop = Environment.TickCount;
			stopElapsed = stop - start;

			end = Environment.TickCount;
			totalElapsed = end - begin;
		}
		public void Start()
		{
			resourceLock = new WorkComplete(threadCount);
			int begin, end;
			begin = Environment.TickCount;
			for(int count = 0; count < threadIterations; count++)
			{

				SpinThreads();

				if(minStartElapsed == 0.0)
					minStartElapsed = (double)startElapsed;
				if((double)startElapsed > maxStartElapsed)
					maxStartElapsed = (double)startElapsed;
				if((double)startElapsed < minStartElapsed)
					minStartElapsed = (double)startElapsed;
				if(minStopElapsed == 0.0)
					minStopElapsed = (double)stopElapsed;
				if((double)stopElapsed > maxStopElapsed)
					maxStopElapsed = (double)stopElapsed;
				if((double)stopElapsed < minStopElapsed)
					minStopElapsed = (double)stopElapsed;
				if(minTotalElapsed == 0.0)
					minTotalElapsed = (double)totalElapsed;
				if((double)totalElapsed > maxTotalElapsed)
					maxTotalElapsed = (double)totalElapsed;
				if((double)totalElapsed < minTotalElapsed)
					minTotalElapsed = (double)totalElapsed;
				sumStartElapsed += (double)startElapsed;
				sumStopElapsed += (double)stopElapsed;
				sumTotalElapsed += (double)totalElapsed;
			}

			averageStartElapsed = sumStartElapsed/(double)threadIterations;
			averageStopElapsed = sumStopElapsed/(double)threadIterations;
			averageTotalElapsed = sumTotalElapsed/(double)threadIterations;

			end = Environment.TickCount;
			totalElapsed = end - begin;
		}
		private void ThreadEntry()
		{
			Fibonacci fib = new Fibonacci(threadWork);
			fib.Compute();
			resourceLock.V();
		}
		public double AverageTotalElapsed
		{
			get
			{
				return averageTotalElapsed;
			}
		}
		public double AverageStartElapsed
		{
			get
			{
				return averageStartElapsed;
			}
		}
		public double AverageStopElapsed
		{
			get
			{
				return averageStopElapsed;
			}
		}
	}
}
