Avatar billede ckrame Nybegynder
12. oktober 2000 - 09:33 Der er 17 kommentarer og
1 løsning

Jonglere med milisekunder i Borland C++ Builder

Jeg vil gerne lave en program stump der kan fortælle mig hvor lang tid det tager at løbe f.eks en løkke igennem. Jeg forestiller mig at det skal være noget i retning af:

(pseudokode)

Start = now i milisekunder
  Her er den løkke der skal løbes igennem
Slut = now i milisekunder

Varighed = Slut - Start
Avatar billede borrisholt Novice
12. oktober 2000 - 09:36 #1

int Start = GetTickCount();
for (int i=0; i<1000000;++i);
int Slut = GetTickCount() - Start;

i slut variablen hat du nu den tid der er gået i millisekunder

Jens B

Avatar billede borrisholt Novice
12. oktober 2000 - 09:36 #2
Det var så et svar.
Avatar billede powell Nybegynder
12. oktober 2000 - 10:18 #3
Den hårde fysisk vej er at se på den enkelte kommando og hvordan borland compileren kompilerer den enkelte kode over i asm, og se her hvor mange linjer den fylder, en linje er så en clockcycle.
Avatar billede ckrame Nybegynder
12. oktober 2000 - 10:21 #4
Et lille kig i online manualen har aldrig skadet nogen :-)
Dette virker ihvertfald.

int main(void)
{
  clock_t start, end;
  start = clock();
  long i = 6000000L;

    while (i--) {
    i++;
    i--;
    }

  end = clock();
  printf(\"The time was: %f\\n\", (end - start) / CLK_TCK);

  return 0;
}

>>borrisholt Jeg tjekker lige din løsning.
Avatar billede ckrame Nybegynder
12. oktober 2000 - 10:26 #5
>>borrisholt - med din løsning får jeg blot 0.0000 sekunder, eller 2.121996e-313 hvilket vist ikke er helt korrekt
Avatar billede borrisholt Novice
12. oktober 2000 - 10:33 #6
Det kan jeg nu ikke lige forstå ....

Jeg har ikke C Builder her .. men \"kun\" en Delphi. Men mon ikke selv du kan porte :

Det her virker :

procedure TForm1.Button2Click(Sender: TObject);
var
  Start,Stop : DWORD;
  i : Integer;
begin
  Start := getTickCount;
  for i:= 0 to 10000 do
    Caption := IntToStr(i);
  Stop := getTickCount - Start;
  Caption := IntToStr(Stop) + \'Millisekunder\';
end;

Det har jeg lige tested

jens B
Avatar billede soepro Nybegynder
12. oktober 2000 - 10:46 #7
Det kan jo rent faktisk godt være at 10000 gennemløb af ovenstående forholdsvis simple løkkestruktur tager under 1 millisekund og at 0.0 derfor er korrekt. Ligepræcis en for løkke kan i ASM forkortes til stort set to instruktioner: DECR, JNZ, hvis blot programmet starter med at loede I til f.eks. AX registret.
Avatar billede lars_computerworld Seniormester
12. oktober 2000 - 16:01 #8
OK borrisholt det fungerer også, men problemet har udviklet sig til et konverteringsproblem.

Når jeg nu har lavet 10000 gennemløb vil jeg gerne regne ud hvor lang tid det tog pr gennemløb, hvordan laver jeg en sådan division med en præcision på ca 10 betydende cifre.
Avatar billede borrisholt Novice
12. oktober 2000 - 16:09 #9
Så skal du bruge en mere nøjagtig tæller :

prøv det her :


procedure TForm1.Button1Click(Sender: TObject);
var
  i : Integer;
  Start, Stop, Freq: Int64;
begin
  QueryPerformanceCounter(Start);
  for i:= 0 to 10000 do
  begin
    Caption := IntToStr(i);
  end;
  QueryPerformanceCounter(Stop);
  QueryPerformanceFrequency(Freq);
  Caption := \'Tid Brugt : \' + floatToStr((Stop - Start) / Freq) + \'Sekunder\';
end;

Så kan du jo selv dividere og gøre ved på det bag efter ....

Er det ikke nøjagtigt nok må vil jo tælle clock cycels ... Men den tid den sorg ...

Jens B
Avatar billede ckrame Nybegynder
16. oktober 2000 - 10:23 #10
Følgende giver en EAccessViolation ! Hvad er der galt ?

_LARGE_INTEGER *Start, *Stop, *Freq;

  QueryPerformanceCounter(Start);
  for (int i = 0; i< 10000; i++ )
  { Memo1->Lines->Add( IntToStr(i) );
  }

  QueryPerformanceCounter(Stop);
  QueryPerformanceFrequency(Freq);
  Memo1->Lines->Add(\"Tid Brugt : \" + FloatToStr((Stop->HighPart - Start->HighPart) / Freq->HighPart) + \"Sekunder\");
Avatar billede ckrame Nybegynder
18. oktober 2000 - 10:16 #11
nu får jeg en compiler fejl:
Kan ikke konvertere en _large_integer til en _large_integer ???
Avatar billede borrisholt Novice
18. oktober 2000 - 10:55 #12
problemert er et kombalitets problem mellem en record der ser sådan ud :

  _LARGE_INTEGER = record
    case Integer of
    0: (
      LowPart: DWORD;
      HighPart: Longint);
    1: (
      QuadPart: LONGLONG);
  end;

og så en alm 64 bits integer: __int64

  QueryPerformance funktionerne forventer en __int64 og ikke en LARGE_INTEGER

eventuelt kan du laven en type definition alla den her :

typedef _LARGE_INTEGER  TLargeInteger;

også nede i funktions kaldene overstyre det til en 64bits integer du ved alla

_LARGE_INTEGER *Start, *Stop, *Freq;

  QueryPerformanceCounter((__int64)Start);
  for (int i = 0; i< 10000; i++ )
  { Memo1->Lines->Add( IntToStr(i) );
  }
Jens B
 
Avatar billede borrisholt Novice
18. oktober 2000 - 11:32 #13
Går det hele så helt i u-fisk for dig må du jo tælle clock cykler og regne lidt på dem. Til det formål vil jeg anbefalde det følgende :

#include \"stdafx.h\"
#include \"windows.h\"

union TTimeStamp
{
    __int64 Whole;
    struct
    {
        int Lo;
        int Hi;
    }Other;
};

__int64 GetTimeStamp()
{
  TTimeStamp TimeStamp;
    __asm
    {
      _emit 0x0f
      _emit 0x31
      mov TimeStamp.Other.Lo, eax
      mov TimeStamp.Other.Hi, edx
    }
    return TimeStamp.Whole;
}


double GetCpuSpeed()
{
  const DelayTime = 500;

  int TimerLo, TimerHi;

  int PriorityClass = GetPriorityClass( GetCurrentProcess() );
  int Priority      = GetThreadPriority( GetCurrentThread() );
  SetPriorityClass(GetCurrentProcess() , REALTIME_PRIORITY_CLASS);
  SetThreadPriority(GetCurrentThread() , THREAD_PRIORITY_TIME_CRITICAL);

  SleepEx(10, false);

  __asm
  {
    _emit 0x0f
    _emit 0x31
    mov TimerLo, eax
    mov TimerHi, edx
  }

  SleepEx(DelayTime, false);

  __asm
  {
    _emit 0x0f
    _emit 0x31
    sub eax, TimerLo
    sbb edx, TimerHi
    mov TimerLo, eax
    mov TimerHi, edx
  }

  SetThreadPriority(GetCurrentThread() , Priority);
  SetPriorityClass(GetCurrentProcess() , PriorityClass);
 
  return (double) TimerLo / (1000 * DelayTime);   
}


int main(int argc, char* argv[])
{   
__int64 Start, Stop;
double TotalSeconds;
double CPUSpeed =  GetCpuSpeed() ;

for(;;)
{

    Start = GetTimeStamp();
    int j = 0;
    for (int i= 0; i<1000000; ++i)
    {
        ++j *=3 %373272323;
        j /=3;
        j *=i % 33;
    }
    Stop = GetTimeStamp();
   
    TotalSeconds = (Stop - Start) / (CPUSpeed * 1e6);
 
    printf(\"Tid Brugt : %f Sekunder\\n\", TotalSeconds);
}
return 0;
}

Jens B
Avatar billede borrisholt Novice
18. oktober 2000 - 11:37 #14
orv ja .. hvrofor sagde du ikke det inden jeg postede ?

I C++ Builder skal du erstatte _emit med db

Det kunne du godt have sagt !

:)

jens B
Avatar billede ckrame Nybegynder
20. oktober 2000 - 13:43 #15
>>borrisholt
Jeg tester lige din sidste løsning. hav venligst lidt tålmodighed.
Avatar billede borrisholt Novice
30. oktober 2000 - 16:19 #16
ckrame  >> \"hav venligst lidt tålmodighed\" nu er der gået 10 dage ...

Hvor længe skal du bruge på at teste noget så simplet ?

Jens B

Avatar billede ckrame Nybegynder
30. oktober 2000 - 16:23 #17
Jammen jeg er ikke så hurtig :-)
Nå men vi besluttede at benytte den første løsning selvom den ikke er så præcis igen, så jeg har ikke lige fået testet den sidste løsning.

Du skal dog have dine point alligevel - tak for hjælpen
Avatar billede borrisholt Novice
30. oktober 2000 - 16:25 #18
:o)

Jens B
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester