Gå til innhold

Anbefalte innlegg

Jeg laget et enkelt komandolinjeprogram for å teste PC-ene mines "hastighet". Jeg laget et idiotisk enkelt program som teller fra 0 til 1'000'000, mens den tar tiden på dette, hva jeg oppdaget var at dette tok like lang tid uansett PC, (og en er en ace aspire one 1st gen som kjører ThinPC, og burde brukt betydlig lengre tid en sine stasjonære 'brødre').

 

Er det slik at .net -platformen ikke kan kjøre slike prosesser raskere enn en gitt hastighet? eller er det begrensninger i CMD?

 

-frank

Lenke til kommentar
Videoannonse
Annonse

Bare teller du, eller skriver du tallet ut til skjerm også?

ja, sånn at for hver incriment får man tallet dyttet ut og så får man printet tiden det tok til slutt, slik:

 

--------

999997

999998

999999

1000000

Time = ####### millisecons

--------

 

Siden du sier cmd går jeg utifra at du teller med tiden det tar å skrive til kommandolinjen. Ta vekk dette så funker det nok bedre.

Jeg starter en Timer når programmet og tellinge starter og etter loopen som teller er ferdikjørt stopper timeren og printer resultatet, psudocode ex:

Program
{
  start.timer();
  $i = "0";
  while($i<1000001)
     {
     print($i);
     $i++
     }
  end.timer();
  print (result.timer);
}

(innså at jeg kunne likegjerne gjort en copypast på koden for det var ikke my "psudo" over denne koden :p )

 

-frank

Lenke til kommentar

Å printe en million ganger til skjermen tar så mye tid at prosessorhastigheten blir uvesentlig. Det du måler er hastigheten på å skrive tekst til skjermen.

 

Løkka di må gjøre noe, ellers vil compileren skjønne at den ikke trenger eksekvere den, men det må være noe som belaster prosessoren alene. (Og antagelig minnet på maskinen).

 

Geir :)

Endret av tom waits for alice
  • Liker 1
Lenke til kommentar

Å printe en million ganger til skjermen tar så mye tid at prosessorhastigheten blir uvesentlig. Det du måler er hastigheten på å skrive tekst til skjermen.

 

Løkka di må gjøre noe, ellers vil compileren skjønne at den ikke trenger eksekvere den, men det må være noe som belaster prosessoren alene. (Og antagelig minnet på maskinen).

 

Geir :)

Det ante meg at dette var en for lett løsning :p

 

-frank

Lenke til kommentar

Eksempel i C

#include <stdio.h>

int main(int argc, char *argv[])
{
       int i;
       for(i=0;i<1000000;i++) {
       }
       return 0;
}

 

Uten optimalisering overhodet ( gcc -O0 -o loop loop.c ) kompileres den til følgende:

(mye "boilerplate" her, men du ser rutinen i midten)

       .file   "loop.c"
       .text
       .globl  main
       .type   main, @function
main:
.LFB0:
       .cfi_startproc
       pushl   %ebp
       .cfi_def_cfa_offset 8
       .cfi_offset 5, -8
       movl    %esp, %ebp
       .cfi_def_cfa_register 5
       subl    $16, %esp
       movl    $0, -4(%ebp)
       jmp     .L2
.L3:
       addl    $1, -4(%ebp)
.L2:
       cmpl    $999999, -4(%ebp)
       jle     .L3
       movl    $0, %eax
       leave
       .cfi_restore 5
       .cfi_def_cfa 4, 4
       ret
       .cfi_endproc
.LFE0:
       .size   main, .-main
       .ident  "GCC: (GNU) 4.6.2 20120120 (prerelease)"
       .section        .note.GNU-stack,"",@progbits

 

 

Kompilert med full optimalisering ( gcc -O3 -S loop loop.c ) gir den følgende :


       .file   "loop.c"
       .section        .text.startup,"ax",@progbits
       .p2align 4,,15
       .globl  main
       .type   main, @function
main:
.LFB11:
       .cfi_startproc
       xorl    %eax, %eax
       ret
       .cfi_endproc
.LFE11:
       .size   main, .-main
       .ident  "GCC: (GNU) 4.6.2 20120120 (prerelease)"
       .section        .note.GNU-stack,"",@progbits

 

Her ser compileren at denne loopen er meningsløs, og tar den rett og slett bort.

xorl %eax, %eax nullstiller eax-registeret (returverdien). Dette er en optimalisert versjon av movl $0, %eax i forrige eksempel.

 

Så, tidtakning:

 

Uoptimalisert:

$ time ./loop

real    0m0.011s
user    0m0.010s
sys     0m0.000s

 

Optimalisert:

$ time ./loop

real    0m0.002s
user    0m0.000s
sys     0m0.000s

Endret av Sokkalf™
  • Liker 1
Lenke til kommentar

Jeg merker meg at den ikke dropper løkka i C# i Release... men koden blir vesentlig kortere

Debug:

{
00000000  mov         qword ptr [rsp+8],rcx 
00000005  sub         rsp,38h 
00000009  mov         dword ptr [rsp+20h],0 
00000011  mov         byte ptr [rsp+24h],0 
00000016  mov         rax,7FF001A3C40h 
00000020  mov         eax,dword ptr [rax] 
00000022  test        eax,eax 
00000024  je          000000000000002B 
00000026  call        FFFFFFFFECC770D0 
0000002b  nop 
           int i;
           for (i = 0; i < 1000000; i++)
0000002c  mov         dword ptr [rsp+20h],0 
00000034  jmp         0000000000000042 
           {
00000036  nop 
           }
00000037  nop 
           for (i = 0; i < 1000000; i++)
00000038  mov         eax,dword ptr [rsp+20h] 
0000003c  inc         eax 
0000003e  mov         dword ptr [rsp+20h],eax 
00000042  xor         eax,eax 
00000044  cmp         dword ptr [rsp+20h],0F4240h 
0000004c  setl        al 
0000004f  mov         dword ptr [rsp+28h],eax 
00000053  movzx       eax,byte ptr [rsp+28h] 
00000058  mov         byte ptr [rsp+24h],al 
0000005c  movzx       eax,byte ptr [rsp+24h] 
00000061  test        eax,eax 
00000063  jne         0000000000000036 
       }
00000065  jmp         0000000000000067 
00000067  add         rsp,38h 
0000006b  ret 

 

Release:

            for (i = 0; i < 1000000; i++)
00000000  mov         qword ptr [rsp+8],rcx 
00000005  sub         rsp,38h 
00000009  mov         dword ptr [rsp+20h],0 
00000011  mov         rax,7FF00183C40h 
0000001b  mov         eax,dword ptr [rax] 
0000001d  test        eax,eax 
0000001f  je          0000000000000026 
00000021  call        FFFFFFFFECC97040 
00000026  mov         dword ptr [rsp+20h],0 
0000002e  jmp         000000000000003A 
00000030  mov         eax,dword ptr [rsp+20h] 
00000034  inc         eax 
00000036  mov         dword ptr [rsp+20h],eax 
0000003a  cmp         dword ptr [rsp+20h],0F4240h 
00000042  jl          0000000000000030 
           {
           }
       }
00000044  jmp         0000000000000046 
00000046  add         rsp,38h 
0000004a  ret 

 

Det synes jeg er litt dårlig av .NET... Det er jo åpenbar død kode.

Lenke til kommentar

Jeg laget et enkelt komandolinjeprogram for å teste PC-ene mines "hastighet". Jeg laget et idiotisk enkelt program som teller fra 0 til 1'000'000, mens den tar tiden på dette, hva jeg oppdaget var at dette tok like lang tid uansett PC, (og en er en ace aspire one 1st gen som kjører ThinPC, og burde brukt betydlig lengre tid en sine stasjonære 'brødre').

 

Er det slik at .net -platformen ikke kan kjøre slike prosesser raskere enn en gitt hastighet? eller er det begrensninger i CMD?

 

-frank

Som mange sier så tester du ikke minne hastigheten i det hele tatt her. Men utvid programmet ditt litt med håndtering av collections og slikt. Da blir det fort litt minnebruk.

 

Noe sånt kansje:

List<int> liste = new List<int>();
DateTime t1 = DateTime.Now;
for (int i = 0; i < 1000000; i++)
   liste.Add(i);
DateTime t2 = DateTime.Now.Subtract(t1);

Lenke til kommentar

Det funker på maskinspråk-nivå, hvertfall gjorde det det i 1996 når vi satt og lærte Assembly på en 286 på skolen.

Da lagde vi loops for å forsinke koden, f.eks. for å lage 3-sekunders intervaller på trafikklys programmet styrte. For å regne hvor mange ganger loopen skulle repeteres, måtte man regne ut fra hvor mange millisekunder CPU'n brukte på hver cycle. Hastigheten ville da bli helt annerledes på en annen CPU.

 

Men vi skrev ingenting til skjerm i det programmet. CPU'r idag er vel så sofistikerte og kjappe at man ikke kan "pause" kjøringen med en loop X antall ganger..

Endret av Bytex
Lenke til kommentar

Slik gjøres det som OP forsøkte enkelt (ingen skriving til skjerm mens du utfører performance testen da det ødelegger):

var start = DateTime.Now;
long cnt=1;
for (int i = 0; i < 1000000; i++) {
   cnt += i;
}
var end = DateTime.Now;
Console.WriteLine("Det tok: " + end.Subtract(start).TotalMilliseconds +" ms.     - " + cnt.ToString()); //cnt.Tostring slik at cnt ikke optimialiseres vekk på noe vis.

Lenke til kommentar

Slik gjøres det som OP forsøkte enkelt (ingen skriving til skjerm mens du utfører performance testen da det ødelegger):

var start = DateTime.Now;
long cnt=1;
for (int i = 0; i < 1000000; i++) {
   cnt += i;
}
var end = DateTime.Now;
Console.WriteLine("Det tok: " + end.Subtract(start).TotalMilliseconds +" ms.     - " + cnt.ToString()); //cnt.Tostring slik at cnt ikke optimialiseres vekk på noe vis.

Så fordi jeg addet inn i en collection så var det feil ??? Ser ikke helt forskjellen her annet en at mitt eksempel kansje gir litt mere forskjell i tid da en collection krever mange flere klokke sykluser en simple increment.

Lenke til kommentar

Nei, det er ikke feil av den grunn jeg nevnte over. Et problem med å lage rene ytelsestester er at det er ekstremt vanskelig å vite om ytelsesmålingen er rettferdig eller ikke. Grunnen er at kode som ikke fører til noe produktivt kan godt hende blir fullstendig fjernet av compileren (eksempelvis en løkke som kun teller opp et tall.

for(i = 0; i< 100; i++);

er funksjonelt synonymt med

i = 100;

og dersom compileren klarer å gjøre denne antagelsen faller hele poenget med løkken bort.

Ved å legge inn i en liste vil du garantere at compileren ikke lenger kan gjøre denne antagelsen.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...