unit uSThreads;
{
  COSBI: Comprehensive Open Source Benchmarking Initiative
  Copyright (c) 2003 Van Smith
   
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  The current web address of the GNU General Public License is:
  http://www.gnu.org/licenses/gpl.html

  You can contact the authors of this software at:
  cosbi@vanshardware.com
  See www.vanshardware.com or www.cosbi.org for more contact details.
}
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls, COSBI_Common, Mask;

type
  TfrmSThreads = class(TForm)
    StartBtn: TButton;
    edCount: TEdit;
    edN: TEdit;
    Label1: TLabel;
    Panel1: TPanel;
    memoResults: TMemo;
    Label2: TLabel;
    MaskEd_NbrOfThreads: TMaskEdit;
    rbPi: TRadioButton;
    rbFib: TRadioButton;
    procedure FormCreate(Sender: TObject);
    procedure StartBtnClick(Sender: TObject);
    procedure RunThreads;
    procedure PiThreadDone(Sender: TObject);
    procedure FibThreadDone(Sender: TObject);
  private
    eFibStartTime : extended;
    eThreadStartTime: array[1..99] of extended;
    iThreadsRunning : integer;
    iThreadCount : integer;
    iThreadsTotal : integer;
    iIterate :integer;
    n : integer;
    iNbrOfTests : integer;
    StopWatch : TStopWatch;
  public
  end;

var
  frmSThreads: TfrmSThreads;

implementation

uses uThreads;

{$R *.DFM}

//type
//  TSortArray =  array[0..300000] of Integer; //array[0..33000] of Integer;

//var
//  ArraysRandom: Boolean;
//  SortArray {BubbleSortArray, SelectionSortArray, QuickSortArray}: TSortArray;

const
  VERSION             = 'v0.11';
  MSG_NOTICE          = 'NOTICE: This test takes one to five minutes per multithreaded iteration.';
  TEST_STARTS         = '**** Test Starts ****';
  TEST_ENDS           = '**** Test Ends ****';
  P4CEL_TOTAL_TIME    = 115.33;
  P4CEL_PI_TIME       = 59.48;
  P4CEL_PI_TIME_2     = 115.33;
  P4CEL_FIB_TIME      = 55.89;
  P4CEL_FIB_TIME_2    = 111.72;
  DEFAULT_N           = 46;
  PI_DIGITS           = 1500;

{ TThreadSortForm }

procedure TfrmSThreads.FormCreate(Sender: TObject);
begin
  Caption := Caption + ', Version ' + VERSION;
  StopWatch := TStopWatch.Create;
  StopWatch.Resolution := swresHigh;
  GetSystemInfo(memoResults, StopWatch);
  memoResults.Lines.Add(MSG_NOTICE);
  edN.Text := IntToStr(DEFAULT_N);
end;

procedure TfrmSThreads.RunThreads;
var
  i : integer;
begin
  n := StrToInt( edN.Text );
  if n < 1 then n := 1;
  if (rbPi.Checked) then begin
    StartBtn.Enabled := False;
    for i := 1 to iThreadCount do begin
      eThreadStartTime[ i ] := StopWatch.SplitTime;
      with TPiThread.Create( PI_DIGITS ) do begin
        inc( iThreadsRunning );
        ThreadNumber := i;
        OnTerminate := PiThreadDone;
      end; // with
    end; // for
  end else if (rbFib.Checked) then begin
    StartBtn.Enabled := False;
    for i := 1 to iThreadCount do begin
      eThreadStartTime[ i ] := StopWatch.SplitTime;
      with TFibThread.Create( n ) do begin
        inc( iThreadsRunning );
        ThreadNumber := i;
        OnTerminate := FibThreadDone;
      end; // with
    end; // for
  end; // if...else
//  with TSelectionSort.Create(SelectionSortArray) do
//    OnTerminate := ThreadDone;
//  with TSelectionSort.Create(QuickSortArray) do
//    OnTerminate := ThreadDone;
end; // procedure TfrmSThreads.RunThreads;

procedure TfrmSThreads.StartBtnClick(Sender: TObject);
begin
  iThreadCount := StrToInt(MaskEd_NbrOfThreads.Text);
  iIterate := StrToInt(edCount.Text);;
{  iNbrOfTests := ( integer(chkboxFib.Checked) +  integer(chkboxSort.Checked) );

  if iNbrOfTests = 0 then begin
    showmessage( 'You need to select at least one thread.' );
    exit;
  end; // if
}
  iThreadsTotal := iThreadCount * iIterate;
  iThreadsRunning := 0;

  memoResults.Lines.Add( TEST_STARTS );
  memoResults.Lines.Add('Test, Score, Time(s)');
  memoResults.Lines.Add('====  =====  =======');

  StopWatch.StartTimer;
  RunThreads;

end; // procedure TfrmThreads.StartBtnClick(Sender: TObject);

procedure TfrmSThreads.PiThreadDone(Sender: TObject);
var
  eTime    : extended;
  eAvgTime : extended;
  dScore   : double;
  li_ThreadNumber : integer;
begin
  li_ThreadNumber := TPiThread( Sender ).ThreadNumber;
  eTime := StopWatch.SplitTime - eThreadStartTime[li_ThreadNumber];

  if iNbrOfTests = 1 then begin
    dScore := ( P4CEL_PI_TIME / eTime ) * 1000;
    memoResults.Lines.Add(Format('Pi(%d), %n, %n', [PI_DIGITS, dScore, eTime]));
  end else begin
    dScore := ( P4CEL_PI_TIME_2 / eTime ) * 1000;
    memoResults.Lines.Add(Format('Pi(%d), %n, %n', [PI_DIGITS, dScore, eTime]));
  end;

  Dec(iThreadsRunning);
  Dec(iThreadsTotal);
  if iThreadsRunning = 0 then
  begin
    if iThreadsTotal = 0 then
    begin
      eTime := StopWatch.StopTimer;
      if iNbrOfTests > 1 then begin
        eAvgTime := eTime / iIterate;
        dScore := ( P4CEL_TOTAL_TIME / eAvgTime ) * 1000;
        memoResults.Lines.Add(Format('2xThreads, %n, %n', [dScore, eAvgTime ]));
      end; // if
      if iIterate > 1 then begin
        memoResults.Lines.Add(Format('Total test time: %n s', [eTime]));
      end; // if
      memoResults.Lines.Add( TEST_ENDS );
      memoResults.Lines.Add( '' );
      StartBtn.Enabled := True;
    end
    else
    begin
      RunThreads;
    end;
  end;
end;

procedure TfrmSThreads.FibThreadDone(Sender: TObject);
var
  eTime     : extended;
  eAvgTime  : extended;
  dScore    : double;
begin
  eTime := StopWatch.SplitTime - eFibStartTime;
  dScore := ( P4CEL_FIB_TIME / eTime ) * 1000;

  // we can only calculate scores for default n:
  if n = DEFAULT_N then begin

    if iNbrOfTests = 1 then begin
      dScore := ( P4CEL_FIB_TIME / eTime ) * 1000;
      memoResults.Lines.Add(Format('Fib(%d), %n, %n', [n, dScore, eTime]));
    end else begin
      dScore := ( P4CEL_FIB_TIME_2 / eTime ) * 1000;
      memoResults.Lines.Add(Format('Fib(%d), %n, %n', [n, dScore, eTime]));
    end; // if iNbrOfTests

  end else begin
    memoResults.Lines.Add(Format('Fib(%d) thread time (s), %n s', [n, eTime]));
  end; // if n = DEFAULT_N

  Dec(iThreadsRunning);
  Dec(iThreadsTotal);

  if iThreadsRunning = 0 then
  begin
    if iThreadsTotal = 0 then
    begin
      eTime := StopWatch.StopTimer;
      if iNbrOfTests > 1 then begin
        eAvgTime := eTime / iIterate;
        dScore := ( P4CEL_TOTAL_TIME / eAvgTime ) * 1000;
        memoResults.Lines.Add(Format('2xThreads, %n, %n', [dScore, eAvgTime ]));
      end; // if
      if iIterate > 1 then begin
        memoResults.Lines.Add(Format('Total test time: %n', [eTime]));
      end; // if
      memoResults.Lines.Add( TEST_ENDS );
      memoResults.Lines.Add( '' );
      StartBtn.Enabled := True;
    end
    else
    begin
      RunThreads;
    end;
  end;
end;

end.
