Wątek przeniesiony 2023-02-12 01:35 z Delphi i Pascal przez furious programming.

Wydajność i zmienne w pętli

0

Ostatnio sprawdziłem z ciekawości na ile pozwolić sobie będzie mógł pascal przy użyciu FPC na starym komputerze bez karty graficznej itp. Moim oczom ukazał się zdumiewający rezultat bowiem wykonanie się zmiany wartości jednej zmiennej dwustukrotnie na sekunde spowodowało zużycie mocy obliczeniowej procesora o połowę.

W programie funkcjonują cztery zmienne gdzie tylko pierwsza zmienia swoją wartość tak szybko. Wartość drugiej zmiennej zmienia się jednorazowo co wyzerowanie się wartości zmiennej pierwszej co następuje po osiągnięciu wartości bliskiej tysiącu jednostek a wartości pozostałych zmiennych natomiast są podstawionymi wartoścami dwóch poprzednich zmiennych z nałorzoną dodatkową operacją matematyczną jedynie dodającą do wartości określoną stałą liczbę.

Wszystko dzieje się w niekończącej się pętli. W praktyce wartości owych zmiennych oznaczają współrzędne ekranu wyrażane w polach co przetwarzane jest następnie na położenie na ekranie w ramach rozdzielczości ekranu co nie ma większego znaczenia na ten moment dla reszty programu ponieważ zgrupsza stanowią je wcześniej wspomniane zmienne i ich funkcjonalność.

Optymalizacja tak prostego programu przy jednoczesnym wykorzystaniu podstawowych funkcji języka bez używania wstawek asemblerowych zdaje się być nieosiągalna.

Wniosek: Commodore64 radził sobie lepiej z Basic'iem prawie pół wieku temu niż stacjonarka z Pascal'em dzisiaj.

5

Pamiętaj że wklejenie "print screen" z czterech linijek tekstu to skrajne marnotrawstwo zasobów i świadczy o Tobie !
Drżenie rak spowodowane jest nadmiarem alkoholu ? Bo zdjęcia i tak nieczytelne

2

[...] spowodowało zużycie mocy obliczeniowej procesora o połowę

W jaki sposób moc obliczeniowa może się zużywać?

4

@matej47 opisz metodologię testowania, co to znaczy lepiej ?
Przy mglistych kryteriach to można udowodnić każdy wniosek np. matiz jeździ lepiej od BMW

2

Bosch ... pomyślałeś CO TESTUJESZ ?
Bo 99% czasu zjada NIE zmiana prostych zmiennych

(ps pewnie dlatego wstydzisz sie podac kod)

3

@matej47: jeśli nie umiesz robić benchmarków, to nie zwalaj winy na język, że powolny. :D

Doprecyzuję może. Nieskończona pętla działająca w ramach jednego wątku, która nie wykorzystuje mechnizmów usypiających, takich jak np. funkcja Sleep z biblioteki systemowej, podczas działania będzie zużywać pełną moc jednego rdzenia CPU. Twój procesor ma dwa rdzenie fizyczne, więc zużycie będzie wynosiło mniej więcej 50%. U mnie będzie to średnio 35-40%, dla dwóch rdzeni fizycznych (czterech logicznych) i przy włączonym Hyper-Threadingu. Nie jest to zależne ani od procesora, ani od użytego języka programowania, bo dany rdzeń będzie działać na pełną moc w trakcie wykonywania kodu programu.

matej47 napisał(a):

Moim oczom ukazał się zdumiewający rezultat bowiem wykonanie się zmiany wartości jednej zmiennej dwustukrotnie na sekunde spowodowało zużycie mocy obliczeniowej procesora o połowę.

A w jaki sposób regulujesz częstotliwość aktualizacji tej zmiennej? Spinlockiem? Przy okazji — benchmarków nie robi się w ten sposób, że się otwiera Menedżer zadań i gapi na wykresy. To jest smutny żart, nie benchmark.

W programie funkcjonują cztery zmienne gdzie tylko pierwsza zmienia swoją wartość tak szybko. Wartość drugiej zmiennej zmienia się jednorazowo co wyzerowanie się wartości zmiennej pierwszej co następuje po osiągnięciu wartości bliskiej tysiącu jednostek a wartości pozostałych zmiennych natomiast są podstawionymi wartoścami dwóch poprzednich zmiennych z nałorzoną dodatkową operacją matematyczną jedynie dodającą do wartości określoną stałą liczbę.

Bla bla bla…

screenshot-20230130123247.png

Optymalizacja tak prostego programu przy jednoczesnym wykorzystaniu podstawowych funkcji języka bez używania wstawek asemblerowych zdaje się być nieosiągalna.

Dla takiego ignoranta jak Ty, zapewne tak jest. :D

0

Dla jasności.
Myślicie że dlaczego nie poruszyłem w tym temacie kwestii wstawek asemblerowych?
Jestem świadom uciążliwości podstawowych funckji w większych projektach.
Co do kodu to możecie sami sobie wyobrazić taki kod ale uproszcze wam zadanie i powiem wam że głównym winowajcą zapewne jest:

zmienna:=zmienna+wartosc;

zamiast tego powinno być choćby..:

Inc(zmienna);

..ale to już asembler a nie Pascal czego chyba nikt nie zrozumiał.

4

No to może przestań już marnować nasz czas i pokaż kod źródłowy, który testowałeś — od razu wszystko się wyjaśni. Chyba że nadal wolisz uprawiać wodolejstwo i tłumaczyć się w coraz to bardziej absurdalny sposób, to sobie siedź w swoim bagienku przekonań, że Pascal jest powolny, bo inkrementacja zmiennej trwa dwa dni.

3

Załóżmy zgodnie z tezą OP że nikt nie zrozumiał co OP miał na myśli.
To czy problem leży po stronie autora wątku czy też wszyscy inni są winni ?

5

Pierwszy post jasno pokazuje, że jego autor ani nie potrafi tworzyć sensownych benchmarków do mierzenia wydajności kodu, ani nie potrafi poprawnie określić jakości technologii. Do tego celowo nie pokazuje żadnych dowodów na poparcie swoich tez, w tym nie pokazuje kodu źródłowego, który rzekomo testował, a także nie posiada podstawowej wiedzy z zakresu programowania, działania systemów operacyjnych. Jedyne na co go stać to na lanie wody i pokazywanie zrzutów ekranu zrobionych ziemniakiem, nie wiadomo czego dotyczących.

Ten wątek to smutny żart — jego autor chciał zabłysnąć, a jedynie się zaorał.

4

zamiast tego powinno być choćby..: [...]

Ale czym w zasadzie miałoby się różnić jedno od drugiego? 👀

Inline'ing ogarniały kompilatory już w latach osiemdziesiątych, więc wydaje mi się dosyć nieprawdopodobne, aby między inc a = + była jakakolwiek różnica w FPC w 2023 (chyba że na danym typie operacje różnią się sematycznie, tj. robią coś innego - ale w przypadku liczb jedno i drugie działa identycznie afair).

2

W debugu (bez mocniejszych optymalizacji), instrukcja Inc(Foo) tłumaczona jest bezpośrednio do rozkazu addl, natomiast konstrukcje Foo := Foo + 1 oraz Foo += 1 są tożsame, tłumaczone do rozkazów add i mov:

screenshot-20230130163305.png

To jednak nadal nie zmienia faktu, że CPU potrafi wykonać setki milionów inkrementacji na sekundę. Sprawdziłem to sobie prostym kodem, z optymalizacjami -O1, czyli przyjazymi debuggerowi:

{$mode objfpc}{$H+}

uses
  Windows;
var
  Foo: Integer = 0;
  TimeBegin, TimeEnd, I: Integer;
begin
  TimeBegin := GetTickCount();

  for I := 0 to 999999999 do
    Foo += 1;

  TimeEnd := GetTickCount();
  WriteLn('time: ', TimeEnd - TimeBegin, ' ms');
end.

Miliard inkrementacji zmiennej w pętli na moim 10-letnim laptopie trwa średnio 2469 milisekund, czyli na sekundę przypada średnio 405 milionów inkrementacji. Oczywiście mierzone nie są same inkrementacje, bo testowanie warunku pętli i związane z tym skoki warunkowe też zabierają czas procesorowi. Ale to nie ma znaczenia, bo gdzie rzekome 12 inkrementacji na sekundę u autora, a gdzie kilkaset milionów. :D

Ntaomiast w trybie release ten sam test daje wynik średnio 2172 milisekund, dla wszystkich trzech sposobów inkrementacji. Najwyraźniej FPC optymalizuje proste inkrementacje do minimalnej liczby rozkazów, stąd zauważalny zysk czasowy (ale nie chce mi się tego sprawdzać).

0
furious programming napisał(a):

... bo testowanie warunku pętli i związane z tym skoki warunkowe też zabierają czas procesorowi. Ale to nie ma znaczenia, bo gdzie rzekome 12 inkrementacji na sekundę u autora, a gdzie kilkaset milionów. :D

{$mode objfpc}{$H+}

uses
  Windows;
const
  TestSize:Integer=1000000000;
var
  Foo:Integer=0;
  Foq:Integer=0;
  Fop:Integer=0;
  TimeBegin,TimeMid,TimeEnd,I:Integer;
begin
  TimeBegin := GetTickCount();
  for I:=1 to TestSize do
  begin
    Foo+=1;
  end;
  TimeMid:=GetTickCount();
  for I:=1 to TestSize do
  begin
    Foq+=1;
    Fop+=1;
  end;
  TimeEnd:=GetTickCount();  
  WriteLn('time inc only: ',TimeEnd-2*TimeMid+TimeBegin,' ms'); //(TimeEnd-TimeMid)-(TimeMid-TimeBegin)
end.
2

@matej47:

Zamiast zrzutów ekranu pokaż kod!
Procesor Commodora miał taktowanie rzędu kilkunastu megaherców i był ośmiobitowy. Obecne procesory mają taktowanie na poziomie kilku gigaherców czyli 200 -300 razy większe oraz słowo 32 albo 64 bity. To jest wydajnościowa przepaść. Coś zawaliłeś w kodzie i zwalasz swój błąd na kompilator.

1

Ten wątek to zwykły trolling. Przecież wiadomo, że inkrementacja zmiennej sprowadza się raptem do kilku rozkazów CPU, więc to niemożliwe, aby kilkanaście inkrementacji powodowało długotrwałe zużycie mocy obliczeniowej.

Tak czy siak ten wątek najpewniej wyląduje w perełkach, bo do niczego innego się nie nadaje. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1