atarionline.pl Języki programowania - testy - Forum Atarum

Jeśli chcesz wziąć udział w dyskusjach na forum - zaloguj się. Jeżeli nie masz loginu - poproś o członkostwo.

  • :
  • :

Vanilla 1.1.4 jest produktem Lussumo. Więcej informacji: Dokumentacja, Forum.

    • 1: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    No to jeszcze YoshPlus z synchronizacją do ramki i w wersji zoptymalizowanej i bez dla CC65.

    n = OS.rtclok[2]

    To zostawiłem tak jak dostarczył @ilmenit ale być może zmiana na PEEK dała by jeszcze pare obrotów na korzyść CC65?

    Z drugiej stony jak kompilator podstawia za to coś sensowniejszego niż każdorazowe sięganie do tablicy to nic się nie powinno zmienić w osiągach. Teraz nie sprawdzę, bo jest już 4 rano :D

    Mad Pascal 1.6.4 zaktualizowałem o wyniki mastera z dnia 01.03.2020.

    Monte-Carlo PI trochę przyspieszyło, YoshPlus trochę zwolnił po aktualizacji mastera z 02.02.2020 do 01.03.2020.

    Co ciekawe w YoshPlus ma obecnie takie same osiągi w wersji zoptymalizowanej co MadP w wersji ze zmiennymi na stronie zerowej.

    Także, w tych dwóch benchmarkach CC65 straciło swój prymat.

    W wolnej chwili powalczę jeszcze z REAL SIEVE i ChessBoard.
    • 2:
       
      CommentAuthorKaz
    • CommentTime2 Mar 2020
     
    Trochę nie na temat, a trochę w temacie. Otoż kilka dni temu w FastBasic pojawiła się dopiero obsługa DLI. To skłania do refleksji, że same wyniki szybkości testów matematycznych nie mówią nic o przydatności języka do tworzenia programów. Może powinno się też testować jakieś operacje graficzne, obsługę duszków, etc., aby ocenić kompletność i przydatność do tworzenia realnych programów? Np. prosty arkanoid czy inny pac-man.
    • 3: CommentAuthortebe
    • CommentTime2 Mar 2020 zmieniony
     
    Testowałem Rascal dla C64, tam optymalizacja nie powala, ale nadrabia dedykowanymi procedurami, funkcjami realizującymi konkretne zadania.

    p.s
    YoshPlus zwolnił bo nowa wersja MP ma ten sam sposób organizacji pętli WHILE co CC65, który w większości przypadków jest wydajniejszy, ale nie w tym przypadku :)
    • 4: CommentAuthorilmenit
    • CommentTime2 Mar 2020
     
    @zbyti - niestety, nie mam teraz czasu, bo w wolnych chwilach piszę w CC65 ;)
    Kod wygląda OK, tylko bym polecał dwie zmiany:
    1. b *= 4; zamiast b = 4 * b
    2. Stałe p i n powinny być stałymi, nie zmiennymi, bo kompilator nie robi automatycznej identyfikacji stałych, a na 6502 są one szybsze.
    Ponieważ te stałe są duże, to trzeba dodać do nich postfix U. ->link<-
    CC65 zdecydowanie nie wygra w teście wydajności gdy się włączy w innym kompilatorze stablicowane procedury mnożenia (to $f w MP) :)
    • 5: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    @tebe dzięki za wyjaśnienie. Faktycznie pisałeś o tym tydzień temu z wątku o Action!, że while w tym przypadku zwalnia.

    Fajnie, że obadałeś Rascal :]

    @Kaz to co proponujesz to na inną bajkę. Jak masz wydajny język to resztę też zrobisz wydajnie.

    To co proponujesz to ocena jak bogaty jest w bibliotek dany język i jak efektywnie są one napisane.

    Np. w Quick masz obsługę DLI natywnie a w Action! nie ale przecież w obu napisał bym tą samą grę, przy czym spodziewam się, że w Action! działała by 2x szybciej ;) W Mad Pascalu bym pewnie w tym celu skorzystał z template @bocianu który DLI napisał w ASM jako bibilotekę do Pascala bo było mu tak wygonie etc.

    To co wtedy powiedzieć o MADS? Tam jest obsług DLI czy nie? ;)

    Nie oceniam wygody pisania w danym języku bo to subiektywne a większość z aktywnych programistów ma w/w problem rozwiązany bo ma już własne procedury.

    Np. panowie co napisali konwersję Time Pilot stworzyli własny wypasiony multiplekser i tego żadną biblioteką nie pobijesz, musisz to napisać sem. etc.

    Jeżeli widzimy, jak drastyczna jest różnica między optymalizowanym CC65 a niezoptymalizowanym, a z drugiej strony jak przychodzi do rysowania szachownicy (jeszcze to sprawdzę) to pomimo szybkości dodawania tej samej co Mad Pascal CC65 osiąga 40% lepszy wynik, albo przy operacjach mnożenia, jak nie żal nam 2K RAM na szybkie mnożenie w MP, to CC65 jest 3x wolniejszy od MP to coś to jednak mówi.

    Wtedy w zależności co chcemy pisać dobierzemy właściwe narzędzie.

    Erg. Skoro praktycznie DLI, obsługę sprite-ów itd. itp. każdy sam może sobie napisać to ciekawi mnie po prostu jak szybki kod wynikowy powstanie na końcu (pomijam wprawę danego kodera, badam tylko czynnik jakim jest sam kompilator).

    Zajętością pamięci w dzisiejszych czasach też się za bardzo nie przejmuję bo Sikor robi ładne obudowy ;)

    @ilmenit naniosę te poprawki i sprawdzę :]
    • 6: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    #include <stdio.h>
    #include <peekpoke.h>

    #define p 10000
    #define r 16129
    #define tick (PEEK(0x14))
    #define tack (PEEK(0x13) * 256)
    #define rndp (PEEK(0xd20a))

    void main(void)
    {
    register unsigned int stop, i, x, y;
    register unsigned int b = 0;
    register unsigned char n;

    n = tick;
    while (tick == n) { ; }

    printf("\nMonte-Carlo PI cc65 V2.18\n");

    asm(" lda #0");
    asm(" sta $13");
    asm(" sta $14");

    for (i = 0 ; i < p; ++i)
    {
    n = (rndp | 128) ^ 128;
    x = n * n;
    n = (rndp | 128) ^ 128;
    y = n * n;
    if ((x + y) <= r)
    ++b;
    }
    b *= 4;
    stop = tick + tack;

    printf("%d%c%c%c%c%c%c\n", b, 30, 30, 30, 30, 255, 46);
    printf("%d ticks\n", stop);

    infinite:
    goto infinite;
    }

    Dzięki podpowiedzi @ilmenit faktycznie jest szybciej, ale nadal w mnożeniach to zoptymalizowany CC65 nie dorównuje Mad Pascalowi bez żadnych kombinacji.

    Nie użyłem postfixu U bo według zalinkowanych hintów to się robi jak się przekracza połowę INT-a a ja tu operuję w granicy 1/4.

    Poniżej wyniki dla kompilacji 'z' i 'bez' podanych wcześniej flag włączających optymalizację.

    EDIT:
    Jak już pisać elegancko to pisać ;) Zmieniłem PEEK na makra.





    • 7: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    OK. Od teraz (jeżeli o mnie chodzi) dalsze testy będę robił tylko dla języków które kompiluję na PC:

    1. Mad Pascal
    2. CC65
    3. FastBasic

    Jakie możliwości ma Action! to już mamy wyobrażenie, więc już w testach nie będę się nim posługiwał. FastBasic będzie po to by mieć od dołu jakieś porównanie.

    1. YoshPlus - generalnie mierzy szybkość wykonywania się pętli WHILE lekko dociążonej inkrementacją wartości zmiennych o 1 i przepisywaniem wartości.

    2. REAL SIEVE po przeróbce będzie mierzył generalnie operacje dodawania na INT-ach i śmiganie po jednowymiarowej tablicy.

    3. Monte-Carlo PI mierzy skuteczność w mnożeniu INT-ów

    4. Chesspoard - w sumie to nie wiem, implementację pointera? ;D Wypełnianie pamięci danymi?

    Chyba jeszcze napiszę test typowo na tablice, jakieś sortowanie bombelkowe itd.
    • 8: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    Aby nie było wątpliwości, poniższy kod daje ten sam wynik. Zmiana po przeczytaniu hintów ;)

    Acha! ;) Dla niewtajemniczonych: register to jest ta sama opcja co umieszczenie w Mad Pascalu zmiennych na stronie zerowej.

    Muszę dać to w kolumnie INFO przy wyniku.

    #include <stdio.h>

    #define p 10000
    #define r 16129
    #define tick 0x14
    #define tack 0x13
    #define rndp 0xd20a

    void main(void)
    {
    register unsigned int stop, i, x, y;
    register unsigned int b = 0;
    register unsigned char n;

    n = *(char*)tick;
    while (*(char*)tick == n) { ; }

    printf("\nMonte-Carlo PI cc65 V2.18\n");

    asm(" lda #0");
    asm(" sta $13");
    asm(" sta $14");

    for (i = 0 ; i < p; ++i)
    {
    n = (*(char*)rndp | 128) ^ 128;
    x = n * n;
    n = (*(char*)rndp | 128) ^ 128;
    y = n * n;
    if ((x + y) <= r)
    ++b;
    }
    b *= 4;
    stop = *(char*)tick + 256 * *(char*)tack;

    printf("%d%c%c%c%c%c%c\n", b, 30, 30, 30, 30, 255, 46);
    printf("%d ticks\n", stop);

    infinite:
    goto infinite;
    }
    • 9: CommentAuthorzbyti
    • CommentTime2 Mar 2020
     
    @ilmenit nie wiem na czym polega sztuczka z rysowaniem szachownicy 76 razy w CC65 w stosunku do 42 jak to właśnie udało mi się uzyskać w Mad Pascalu, stosują stronę zerową (w sumie uzyskałem tak tylko jedno przerysowanie).

    To jedyny kod gdzie dostarczyłeś swój plik konfiguracyjny do kompilatora, ale nic z niego dla mnie nie wynika co by się przykładało na taką różnice prędkości.

    Możesz to jakoś wyjaśnić?

    Czy ten kod po kompilacji w ASM co w kleiłeś w wątku o Action! tłumaczyć może tę sztuczkę?

    To jedyny test gdzie CC65 na ten moment bierze górę. W pozostały testach albo równo z MP albo tak jak w mnożeniu znacząco odstaje.
    • 10: CommentAuthorantrykot
    • CommentTime2 Mar 2020 zmieniony
     
    #include <stdio.h>
    #include <boost/preprocessor/repetition/repeat_from_to.hpp>
    #define RTCLOK (*(volatile unsigned char*)0x14)
    #define RANDOM (*(volatile unsigned char*)0xd20a)
    #define SQR(z, n, t) n*n,

    const unsigned sqr[] = { BOOST_PP_REPEAT_FROM_TO(0, 128, SQR,) };

    int main(void)
    {
    unsigned i, count = 0;
    RTCLOK = 0;
    for (i = 0; i < 10000; ++i)
    {
    unsigned x, y;
    x = sqr[RANDOM & 127];
    y = sqr[RANDOM & 127];
    if (x + y <= 127 * 127)
    ++count;
    }

    printf("%u\x1e\x1e\x1e\x1e\xff.\n%u ticks\n", count * 4, RTCLOK);
    for (;;);
    }
    • 11: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    @antrykot ja tu piszę benchmarki, które dam radę przepisać na inne języki a Ty się tu magią posługujesz :D

    To miał być benchmark na mnożenie a nie na losowe bieganie po przygotowanej tablicy wyników i dodawanie ;)

    Mad Pascal bez szybkiego mnożenia wciąż ma lepsze osiągi od CC65.

    --------------------

    A na poważnie, to jak zwykle Twój wpis jest ciekawy, dzięki! :]

    Widzę jak fajnie zadeklarować pointer bez tych kombinacji co u mnie :]
    • 12: CommentAuthorzbyti
    • CommentTime2 Mar 2020 zmieniony
     
    No to test dla fanów supremacji A8 nad C64 w kwestii CPU :D

    277 A8 Vs. 425 C64 ==> 148 ramek różnicy.

    Kod na C64 wykonuje się w 8,5 sek. czyli na A8 działa o 3 sekundy szybciej :]

    Do tego z POKEY idą bez kombinacji lepsze "randomy" niż z SID-a :]

    PS. już mi się nie chciało dostawiać kropki więc niech każdy sobie sam podzieli przez 10 000 :D

    EDIT: może ktoś zrobi port na ZX Spectrum?! :D

    #include <stdio.h>

    #define p 10000
    #define r 16129
    #define RTCLOK1 (*(volatile unsigned char*)0xa1)
    #define RTCLOK2 (*(volatile unsigned char*)0xa2)
    #define RANDOM (*(volatile unsigned char*)0xd41b)

    void main(void)
    {
    register unsigned int stop, i, x, y;
    register unsigned int b = 0;
    register unsigned char n;

    //SID's Random Number Generator
    asm(" lda #$ff"); //maximum frequency value
    asm(" sta $D40E"); //voice 3 frequency low byte
    asm(" sta $D40F"); //voice 3 frequency high byte
    asm(" lda #$80"); //noise waveform, gate bit off
    asm(" sta $D412"); //voice 3 control register

    n = RTCLOK2;
    while (RTCLOK2 == n) { ; }

    printf("\nMonte-Carlo PI cc65 V2.18\n");

    RTCLOK1 = 0; RTCLOK2 = 0;
    for (i = 0 ; i < p; ++i)
    {
    n = (RANDOM | 128) ^ 128;
    x = n * n;
    n = (RANDOM | 128) ^ 128;
    y = n * n;
    if ((x + y) <= r)
    ++b;
    }
    b *= 4;
    stop = RTCLOK2 + 256 * RTCLOK1;

    printf("%u\n%u ticks\n", b, stop);

    infinite:
    goto infinite;
    }
    • 13: CommentAuthorzbyti
    • CommentTime3 Mar 2020
     
    OK na razie pass :]

    Piszę o 3 nad ranem i później wydaje mi się, że:

    (rndp | 128) ^ 128 to nie to samo co rndp & 127 i sobie obciach robię :D

    Z mojej strony przerwa :]
    • 14: CommentAuthorzbyti
    • CommentTime3 Mar 2020 zmieniony
     

    jhusak 9 Jun 2012:

    Nie bierz się za atalana. To jest projekt, w którym masochiści piszą:)

    A tak na poważnie - jest problem ze zmiennymi i ograniczeniami. Obszar na zmienne rośnie w niekontrolowany sposób i po prostu w pewnym momencie wszystko przestaje działać. programy często się nie kompilują, bo zamienisz a*b z b*a (obrazowy przykład) Rudla traktuje ten projekt jako pole do eksperymentów, raczej nie inwestuje czasu w nudne rzeczy.

    Mimo wszystko da się w Atalanie napisać prostą gierkę; jednak wąż, tetris, czy układanka to szczyt, co można w tym języku zrobić.

    W przypadku gier typu Kupiec stosuje się często gęsto liczby zmiennoprzecinkowe, więc i Action! odpada. zostaje cc65 z typem float i TB XL, który jest lekki, łatwy i wygodny. Wbrew pozorom TB może być szybszy ze względu na bardzo szybkie procedury float :)

    Jednak sposób operowania zmiennymi tekstowymi może być w TB XL wygodniejszy.

    Ja bym spróbował w cc65, bo to jednak C i można taką grę przeportować na co innego :)
    • 15: CommentAuthorzbyti
    • CommentTime3 Mar 2020 zmieniony
     

    rudla 11 Jun 2012:

    About Atalan:

    In my opinion, the compilers generally are mess to read and understand. Maybe not parsers, but code optimization code without the doubt.

    I don't know, if Atalan if worse or better in this part, as I understand the code quite well :-) However I know, that I had problem understanding this type of code in other compilers and was basically unable to get some useful insights about how to perform optimizations.

    Note, that architecture of 6502 is very compiler unfriendly and many classic optimizations can not be applied.

    The main problem with Atalan as I see it is that I always succumb to the temptation of adding another optimization or new language feature or refactor it so it is more readable :-) Very often, it means rewriting significant portions of optimization code and breaking much of existing functionality. And we are talking about major changes like supporting processor flags (something not supported in many commercial compilers) etc. So it's hard to make Atalan stable, while enhancing it this way.
    • 16:
       
      CommentAuthorjhusak
    • CommentTime3 Mar 2020
     
    @zbyti, myślałem, że to specjalnie, (ten or i xor) żeby testować, czy kompilator to zauważy i zoptymalizuje :) Ale - każdemu się może przydarzyć pomyłka, tylko temu nie kto nie próbuje :)
    • 17: CommentAuthorzbyti
    • CommentTime3 Mar 2020 zmieniony
     
    @jhusak dla benchmarka to lepiej bo ma trochę więcej operacji do wykonania ;)

    Chciałbym być tak sprytny, by testować tak kompilatory ale prawda jest bolesna...

    Gdzieś o trzeciej nad ranem by testować w językach gdzie nie ma INT-a bez znaku napisałem rnd & 128 by zmniejszyć promień koła :D i zamiast się zastanowić, że odciąłem nie tą cześć bajtu bo powinno być 127 to mój otumaniony umysł wymyśli to co widać :D

    Ale to już takie efekty publikowania na szybko ;)

    Tak czy inaczej w każdym języku był ten sam trick więc w tabelce się "zgadza".

    Jakbym pisał jakiś kurs to już bym się zastanowił pewnie co "daję do druku" ;)

    Z drugiej strony jak ludzie mnie poprawiają to się sporo można dowiedzieć, więc po za publicznym wstydem to nic się nie stało :D :D :D
    • 18: CommentAuthorzbyti
    • CommentTime3 Mar 2020
     
    Beka pewnie będzie jeszcze lepsza, bo skoro mało kto dołączył do zabawy to brakujące mi testy w ASM spróbuję napisać sam i dopiero mogą być jaja.

    Ale trzeba uczyć się na błędach. Wróciłem niedawno do programowania po kilku latach rozłąki w ogóle więc nie mam jeszcze tego mindsetu co trzeba :]
    • 19:
       
      CommentAuthorjhusak
    • CommentTime3 Mar 2020
     
    Dawaj asm!
    • 20: CommentAuthorzbyti
    • CommentTime6 Mar 2020 zmieniony
     
    Przypadkiem napisałem benchmark użyty i opisany w artykule zamieszczonym w numerze ANALOG Computing #16 ->link<-

    Poniżej listing w BASIC TURBO XL, Action! i MADS oraz w kolejności ekrany z ich wynikami ;)

    Listing BASIC i Action! żywcem z artykułu jakby co, no może w Action! poprawiłem 2 literówki.

    Oczywiście w ASM napisałem to przypadkiem, jako przygotowanie do do benchmarku z przerysowywaniem szachownicy, także uwagi mile widziane, bo to mój pierwszy kod EVER na podstawie tego co widziałem u Petera Della.

    # to będzie 3 ticks dla ASM.

    BASIC TURBO XL 1.5 bez kompilacji
    10 REM * SCREEN-FILL BENCHMARK
    11 GRAPHICS 24
    12 POKE 19,0:POKE 20,0
    13 SCREEN=PEEK(88)+256*PEEK(89)
    14 FOR I=0 TO 31
    15 FOR J=0 TO 239
    16 POKE SCREEN+J,255
    17 NEXT J
    18 SCREEN=SCREEN+240
    19 NEXT I
    20 TIME=PEEK(20)+256*PEEK(19)
    21 GRAPHICS 0
    22 PRINT TIME;" JIFFIES"

    Action 3.7P
    BYTE RTCLOCK=20, ; addr of sys timer
    SAVMSCL=88, ; lsb of screen addr
    SAVMSCH=89, ; msb

    I,J,TIME ; declare variables

    CARD SCREEN

    PROC BENCH()

    GRAPHICS(24)
    RTCLOCK=0

    SCREEN=SAVMSCL+256*SAVMSCH

    FOR I=0 TO 31
    DO
    FOR J=0 TO 239
    DO
    POKE(SCREEN+J,255)
    OD
    SCREEN==+240
    OD

    TIME=RTCLOCK

    GRAPHICS(0)
    PRINTF("%E %U JIFFIES",TIME)

    RETURN

    MADS 2.1.0
    schess1	= $3000
    schess2 = $4000
    stext = $5000
    RTCLOCK = $14

    org $2000

    mwa #dl8 $230 ;Set Display List pointer

    mva #0 RTCLOCK

    lda #$ff
    ldx #$1f
    ldy #0
    loop sta schess1,y
    iny
    bne loop
    inc loop+2
    dex
    bne loop

    mva RTCLOCK stext

    mva #$ff $2fc
    anykey cmp $2fc
    beq anykey

    mwa #dl0 $230 ;Set Display List pointerb

    jmp * ;End


    .local dl8
    .byte $70,$70 ;2x8 empty scanlines
    .byte $4f,a(schess1)
    :94 .byte $0f
    .byte $4f,a(schess2)
    :92 .byte $0f
    .byte $41,a(dl8) ;Wait VBL, jump DL
    .endl

    .local dl0
    .byte $70,$70 ;2x8 empty scanlines
    .byte $42,a(stext)
    .byte $02
    .byte $41,a(dl0) ;Wait VBL, jump DL
    .endl

    • 21: CommentAuthorzbyti
    • CommentTime6 Mar 2020 zmieniony
     
    Z racji, że @xxl w innym wątku liczył ile cykli tracę adresując indirect to wklejam znalezione na AA ->link<- wyliczenia aby problem sobie jakoś przybliżyć:

    Scenario 1: Brute-Force redraw (completely unrolled scanline drawing code (e.g. no loops))

    - I am pretty sure, that at narrow resolution (128x192), you could get this to run at 25 fps on PAL, even with brute-force redraw

    - 1 frame on PAL is about 35,568 cycles

    - Antic would steal each frame: 96*9=864 (Refresh), 96*3 + 9 = 297 (DL), 128/4*96 = 3,072 (FrameBuffer) -> 864+297+3,072 = 4,233 cycles

    - After Antic toll, we have 35,568 - 4,233 = 31,335 cycles available for the game

    - The skybox via GTIA would take roughly additional 500 cycles, so we're down to 30,800 per frame

    - Two frames (e.g. 25 fps) result in 2*30,800 = 61,600 cycles



    - there's no clearing of the framebuffer (as it always occupies same scanlines), which saves easily 50%-75% of a frame time

    - since you have fixed screen position of both playfields, you can use fastest possible quad-pixel (1 cycle per pixel) drawing via 4-cycle STA $2000, STA $2001, STA $2002, ...

    - Drawing 2 playfields (each 128x48 = 6,144 pixels) results in 6,144 cycles

    - But we need to change the color few times at each scanline via 2-cycle LDA #Color. How many times ? 3x on the nearest scanline and 11 times on furthest, so on average (11-3)/2 = 4x per scanline. That means 4x 2 cycles = 8 cycles / scanline -> 2x48x8 = 768 cycles for whole screen

    - But there's one more thing to account for : The byte boundary, which happens as often as the color change, so on average 4x per scanline, and it's just another 2-cycle LDA, so for both playfields it takes 2x8x48 = 768 cycles for whole screen

    - There's also going to be a logic (per each scanline) which will choose which of the 4 codepaths to JSR into (depending on starting X offset) - this should be under 25 cycles / scanline, so 25*2*48 = 2,400 cycles for whole screen



    So we have: 6,144 + 768 + 768 + 2,400 = 10,080 cycles, which is mere 16% of our frame budget of 2*30,800 (61,600).



    We still have 50,000 cycles for input, audio, HSCROLL and handling PMGs. Easy peasy :)
    • 22: CommentAuthorValdghir
    • CommentTime7 Mar 2020
     
    Cześć.

    Chciałbym zwrócić uwagę czytającym wnikliwie ten wątek, że wszelkie opisane tutaj sprawy nie mają nic wspólnego z porównywaniem prędkości czy wydajności działania poszczególnych języków programowania pomiędzy sobą.

    Załóżmy następującą sytuację: mamy do przerzucenia z punktu A do B tonę piachu. W pierwszym wariancie do dyspozycji mamy jednego ludzia z łopatą, który może nabrać na łopatę piach, przenieść z punku A do B, tam wysypać i wrócić po kolejną.

    W wariancie drugim mamy do dyspozycji ładowarkę zasięrzutną, o ładowności 1 tony, która ładuje i przerzuca tonę piachu jednym ruchem.

    Program wypełniający ekran z postu 20 to jest wariant A zastosowany wobec możliwości zastosowania B.

    Jaki to ma sens ?
    • 23:
       
      CommentAuthorjhusak
    • CommentTime7 Mar 2020
     
    Musisz to dokładniej wyjaśnić, bo ja się z tezą zupełnie nie zgadzam. Nie rozumiem też ostatniego zdania twierdzącego.
    • 24: CommentAuthorzbyti
    • CommentTime7 Mar 2020 zmieniony
     
    Też jestem ciekawe co miało by być tą ładowarką?

    Benchmarki maja pokazać jak efektywny kod maszynowy przy tym samym zadaniu i algorytmie generują ich kompilatory ewentualnie pracują interpretatory.

    Aby mieć punkt odniesienia staram się też mieć tą samą pracę wykonaną przez ASM.

    Pomijając wariant B (którego nie rozumiem) to benchmarki pokazują jak silny i szybki jest w danym języku facet z łopatą z wariantu A, sprawdzamy także czy chodzi w miarę prostą drogą do celu czy też zahacza zbyt często o budkę z piwem :D

    To jeszcze przypomnę co na temat testu z postu #20 miał do powiedzenia sam autor przywołanego przeze mnie artykułu w Analogu:

    Although I love standards, I don't like the Sieve. It's not easy for beginners to understand, it takes too long (in BASIC, anyway), and it doesn't test the Atari under real-world conditions, with lots of 6502 processor time being "stolen" by Antic for video DMA. I wanted a benchmark that anybody could appreciate, operating under the kind of DMA conditions an Atari program is likely to find itself up against.

    Back in Issue 11, I devised a little program that fills a GRAPHICS 24 screen with color, one byte (eight pixels) at a time. It was used to compare a couple of BASIC compilers at the time, but it's equally valid in any run-time environment. My definitive BASIC implementation of this test appears in Listing 5. Screen Fill, as the program shall henceforth be known, executes in 4.025 jiffies or about 67 seconds on a 48K 800. (Again, improvements are possible, but for the sake of clarity let's stick to Listing 5.) I'll be using Screen-Fill in conjunction with the Sieve to judge the performance of every new language I review from now on. So let it be written; so let it be done.
    • 25: CommentAuthorValdghir
    • CommentTime7 Mar 2020
     
    - "Benchmarki maja pokazać jak efektywny kod maszynowy przy tym samym zadaniu i algorytmie generują ich kompilatory ewentualnie pracują interpretatory."

    To wszystko jest bez sensu.

    To samo zadanie można w starym języku wykonać stosując kilkadziesiąt rozkazów, a w nowszym jednym. Po co porównywać języki stosując algorytm z najgorszego z nich? Jak sądzę po to w nowszym w języku specjalizowane polecenia, żeby między innymi wykonać "zadanie" szybciej. Dla mnie prawdziwą miarą wydajności jest pomiar jak szybko wykonać konkretne "zadanie" (lub ich zbiór) stosując dostępne możliwości języka a nie jak zrobić to najgorszą możliwą metodą.

    Lepiej opracować zbiór zadań do wykonania z różnych obszarów: obliczenia matematyczne, operacje graficzne, operacje na pamięci, operacje I/O i pokazać jak szybko można je wykonać w konkretnym języku programowania - to będzie miarodajne.
    • 26: CommentAuthorzbyti
    • CommentTime7 Mar 2020 zmieniony
     
    W nowszym języku taki FILL albo będzie jako polecenie albo jako biblioteka. Teraz pytanie czy będzie od razu miało to implementację w ASM czy też nie?

    Oczy Cię oszukują, nie sprawdzamy wypełniania pamięci (ekranu) danymi tylko podstawy każdego języka jak np. efektywność pracy pętli, dostępu do komórek pamięci itd. itp.

    To taka pierwsza z brzegu riposta ;)

    Jeżeli interesuję Cię inne testy to je po prost napisz, ja piszę te które mnie interesują, wiem co mierzą i wyciągam pożyteczne dla siebie wnioski.

    Do tego sam sobie przeczysz, testy które proponujesz rozbić się mogą o to samo co zarzucasz temu testowi - mogą w danym języku wysokiego poziomu być dedykowane funkcje napisane w języku maszynowym niedostępne w innym.

    To tak jakbyś chciał porównywać szybkość MEMSET/CC65 z FILLCHAR/MadPascal ja wolę zobaczyć jak się zachowują przy posługiwaniu się konstrukcjami wspólnymi dla każdego języka.
    • 27:
       
      CommentAuthorjhusak
    • CommentTime7 Mar 2020
     
    Dla mnie istotną cechą jest długość generowanego kodu; ale jak to @zbyti gdzieś napisałeś, jest wyraźna korelacja pomiędzy długością kodu, a szybkością wykonania. Z tego mogło by wynikać, że najkrótszy kod wygeneruje atalan, madpascal i cc65. Action powinien być dłuższy. Na Atari nie jest tak ważna szybkość, co ilość kodu zmieszczalna w tych trzydziestu - czterdziestu kilobajtach.

    I tu bejziki wygrywają, zwłaszcza(?) te, które liczą na dwubajtowych intach.
    • 28: CommentAuthorzbyti
    • CommentTime7 Mar 2020 zmieniony
     
    @jhusak w czasach gdy kartridże 1MB nie kosztują majątku jak 30-40 lat temu a tak zwany "retro rynek" nie kieruje się ceną na pierwszym miejscu to kwestia pamięci jest dla mnie drugorzędna.

    Pomijając czy coś z siebie ostatecznie wypluję to nie będę miał ambicji mieścić się na Atari800XL dla mnie docelowa jest tylko i wyłącznie 130XE ze stacją dysków a najlepiej jakbym się nauczył pisać na kartridż.

    Reasumując. Robię jakieś tam testy, tyle że pod siebie. Po drodze dowiaduję się pożytecznych rzeczy o platformie etc. Jeżeli komuś te testy też się do czegoś przydają to OK.

    Fajnie jakby inne osoby też coś wrzuciły tylko problem jest taki, że nowy to jestem tutaj tylko ja, reszta co miała się dowiedzieć już dawno wie :D i takie banalne testy niewiele wnoszą do tego jak i na czym programują.

    O ile z ograniczeniami wydajności CPU to chętnie powalczę (jak zdobędę wiedzę) to z ograniczeniami pamięci nie mam zamiaru walczyć.

    To moje podejście, rozumiem inne tyle że do mnie nie przemawiają :]

    ps. oczywiście doceniam przewrotność Twojego wpisu ;)
    • 29: CommentAuthorilmenit
    • CommentTime7 Mar 2020 zmieniony
     
    Podobnie jak 'fill' czy 'memset', różnice są też w przypadku mniej widzianych "funkcji bibliotecznych" jak np. mnożenie czy dzielenie, których 6502 nie ma ;)
    Historia 'benchmarków' jest stara jak kompilatory i nie istnieje idealny benchmark. Niektóre rzeczy można zrobić efektywniej w jednym języku, inne w drugim. Przykładowo Millfork, który jest jednym z najbardziej obiecujących nowych języków jest szybki tam, gdzie autor zrobił jego dobre optymalizacje, zaś w innych miejscach przegrywa z CC65 (vide dyskusja ->link<- ) lub podrzucony wcześniej przez Tebe benchmark RomSum, który napisany po Millforkowemu jest super szybki w tym języku, a wolny w CC65 ->link<- . Zaś po przepisaniu na generyczny "C" jest ->link<- odwrotnie ;)
    Z testów, które były zrobione dla mnie aktualnie najlepszy jest ten "fake sieve", ponieważ ma wiele różnych rzeczy (dużą tablicę, mnożenie *3, operacje na typach word, wiele różnych zmiennych używanych jednocześnie) oraz fajnym testem jest "chessboard", ponieważ dostęp do poszczególnych linii ekranu jest częstym problemem przy programowaniu.
    A Basic? Wooolny... ;-)
    • 30: CommentAuthorzbyti
    • CommentTime7 Mar 2020 zmieniony
     

    ilmenit:

    Z testów, które były zrobione dla mnie aktualnie najlepszy jest ten "fake sieve", ponieważ ma wiele różnych rzeczy (dużą tablicę, mnożenie *3, operacje na typach word, wiele różnych zmiennych używanych jednocześnie).

    prime = i*2 + 3; //CC65
    prime := i shl 1 + 3; //MadP

    Jesteś pewien z tym mnożeniem? Wydaje się, że w przypadku mnożenia przez 2 kompilator CC65 poprzesuwał bity w lewo (zamiast odpalać swoją procedurę na mnożenie) tak jak explicite w kodzie napisał @tebe w Mad Pascalu. Oczywiście pamiętam, że to liczba dwubajtowa ;)
    • 31: CommentAuthorilmenit
    • CommentTime7 Mar 2020
     
    Ach, true. Tam bylo *2 + 3, nie odwrotnie.
    • 32: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    No i proszę :D Udało mi się w ASM napisać kod wolniejszy od tego co osiągnął Mad Pascal z użyciem zmiennych na stronie zerowej ale bez szybkiego mnożenia a także od tego bez zmiennych na stronie zerowej i bez szybkiego mnożenia.

    Albo coś naprawdę ostro źle napisałem albo procedura mnożenia (zwykła) w MadP jest o wiele lepsza od tej zastosowanej przeze mnie.

    Wciąż jestem szybszy od optymalizowanego kodu w CC65 ale szału nie ma ;)

    Proszę o sugestie :]

    Zaznaczę jeszcze, że te makra co poznałem to użyłem, w innych miejscach pisałem "jak mi się wydaje" ;)

    Jeżeli procedura mnożenia w MadP nie jest szybsza od tej użytej przeze mnie to potwierdzało by wniosek, że jak ktoś nie umie w ML to niech pisze w MadP/CC65 bo wiele na szybkości nie straci (a czasem zyska) :D

    ; Monte-Carlo PI in MADS
    org $2000

    .var time .word
    .var i,b,radius,x,y,result .word = $80
    .var fac1,fac2 .byte = $e0

    mwa #16129 radius
    mwa #0 i
    mwa #0 b

    wait
    mwa #0 $13

    loop #while .word i < #10000

    inw i

    lda $d20a
    and #$7f
    sta fac1
    sta fac2
    multi
    mwa result x

    lda $d20a
    and #$7f
    sta fac1
    sta fac2
    multi
    mwa result y

    adw x y

    sbw x radius
    bcs loop
    inw b

    #end

    mva #0 x
    lda b+1
    sta fac1
    lda #4
    sta fac2
    multi
    mva result x+1

    lda b
    sta fac1
    lda #4
    sta fac2
    multi
    mwa result y

    adw x y

    mva $14 time
    mva $13 time+1

    jsr printf
    .by 'pi %',$1e,$1e,$1e,$1e,$ff,$2c,$9b
    .by 'fps % ',$9b,0
    dta a(x)
    dta a(time)

    jmp *

    .proc wait
    lda:cmp:req $14
    rts
    .endp

    .proc multi
    lda #$00
    ldx #$08
    clc
    m0 bcc m1
    clc
    adc fac2
    m1 ror
    ror fac1
    dex
    bpl m0
    ldx fac1
    stx result
    sta result+1
    rts
    .endp

    .link 'printf.obx'
    • 33: CommentAuthorantrykot
    • CommentTime8 Mar 2020
     
    Ale wynik jest nieprawidłowy, bo 31457 nie dzieli się przez 4.
    • 34: CommentAuthorzbyti
    • CommentTime8 Mar 2020
     
    @antrykot masz rację, coś musiałem pokręcić mnożąc przez 4, zraz sprawdzę i poprawię kod.
    • 35: CommentAuthorrobert
    • CommentTime8 Mar 2020
     
    lda b+1
    sta fac1
    lda #4
    sta fac2
    multi
    mva result x+1
    tu zdaje sie brakuje:
    mva #0 x
    • 36: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    @robert własnie to odkryłem, że skoro robię mva na .word to wcześniej wypadało by wyzerować oba bajty za pomocą mwa. Albo tak jak zaproponowałeś.

    Wyprzedziłeś mnie o 3 sek ze wpisem :D

    Dzięki :]
    • 37: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    Zastanawia mnie jeszcze ten fragment:

    sbw radius n z
    bcc loop
    inw b

    Wydaje mi się, że czy zapiszę za pomocą SBW wynik do Z czy też nie to BCC powinno tak samo działać...
    • 38: CommentAuthorrobert
    • CommentTime8 Mar 2020
     
    Mam nadzieje ze nauki nie popsulem wyrywajac sie z podpowiedzia :]
    • 39: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    @robert nie, po prostu zbieg okoliczności, że wróciłem do kompa po przerwie i zobaczyłem gdzie jest błąd. Wpisaliśmy się prawie jednocześnie, nawet nie miałem okazji skorzystać z podpowiedzi ;)

    Bardzo proszę o podpowiedzi i optymalizacje, po prostu jak sam będę chciał pomóżdżyć to nie będę czytał rozwiązania. Dopiero po nie sięgnę jak się poddam ;)

    Miło mi, że się zainteresowałeś problemem i podałeś prawidłowe rozwiązanie :]
    • 40: CommentAuthorrobert
    • CommentTime8 Mar 2020
     
    W opisu SBW w instrukcji do MADS wynika ze z dwoma argumentami wynik jest zapisywany do pierwszego argumentu czyli nadpisywany jest radius. Tak mi sie zdaje, bo tez dopiero sie ucze.
    • 41: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    @robert ale własnie jak jest to Z to mam inne wyniki PI niż bez (pomijając losowość) jakby różnie flaga C była zapalana czy zapisuje się do RADIUS czy też do Z.

    To tak z obserwacji, bo na logikę wydaje mi się, że powinno być bez różnicy.

    --------------------------------

    Sprawdzę jeszcze inne mnożenia z tej strony ->link<-

    Obecny algorytm nie dogania Mad Pascala, zobaczę, że jaki kod wypluwa Mad Pascal przy Monte-Carlo :]
    • 42: CommentAuthorrobert
    • CommentTime8 Mar 2020
     
    Nadpisywane jest RADIUS ktore przez to nie jest stale, a powinno byc stale
    • 43: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    Dzięki, umykają mi takie oczywistości widzę :]

    W takim razie można zamienić N z RADIUS miejscami i warunek skoku rezygnując z Z.

    sbw n radius
    bcs loop
    inw b

    To jeszcze wywalę N z kodu.
    • 44: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    Mnożenie w Mad Pascalu.

    /*

    ;
    ; Ullrich von Bassewitz, 2009-08-17
    ;
    ; CC65 runtime: 8x8 => 16 unsigned multiplication
    ;

    */
    .proc imulCL
    ptr1 = ecx
    ptr4 = eax

    ldy #8
    lda #0

    lsr ptr4 ; Get first bit into carry
    @L0: bcc @L1
    clc
    adc ptr1
    @L1: ror @
    ror ptr4
    dey
    bne @L0
    sta ptr4+1

    rts
    .endp

    Skoro jest to mnożenie z CC65 a CC65 przegrał w Monte-Carlo z MadP znaczy ... że nie ten algorytm jest domyślnie używany? Zajrzę w wolnej chwili do wyniku kompilacji.
    • 45: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    Wrzuciłem mnożenie z Mad Pascala do mojego kodu Monte-Carlo w MADS chociaż na pierwszy rzut oka wyglądał podobnie.

    org $2000

    .var time .word
    .var i,b,radius,x,y,result .word = $80
    .var fac1,fac2 .byte = $e0

    mwa #16129 radius
    mwa #0 i
    mwa #0 b

    wait
    mwa #0 $13

    loop #while .word i < #10000

    inw i

    lda $d20a
    and #$7f
    sta fac1
    sta fac2
    imulCL
    mwa result x

    lda $d20a
    and #$7f
    sta fac1
    sta fac2
    imulCL
    mwa result y

    adw x y

    sbw x radius
    bcs loop
    inw b

    #end

    mva #0 x
    lda b+1
    sta fac1
    lda #4
    sta fac2
    imulCL
    mva result x+1

    lda b
    sta fac1
    lda #4
    sta fac2
    imulCL
    mwa result y

    adw x y

    mva $14 time
    mva $13 time+1

    jsr printf
    .by 'pi %',$1e,$1e,$1e,$1e,$ff,$2c,$9b
    .by 'fps % ',$9b,0
    dta a(x)
    dta a(time)

    jmp *

    .proc wait
    lda:cmp:req $14
    rts
    .endp

    .proc multi
    lda #$00
    ldx #$08
    clc
    m0 bcc m1
    clc
    adc fac2
    m1 ror
    ror fac1
    dex
    bpl m0
    ldx fac1
    stx result
    sta result+1
    rts
    .endp

    .proc imulCL
    ldy #8
    lda #0
    lsr fac1 ; Get first bit into carry
    @L0: bcc @L1
    clc
    adc fac2
    @L1: ror @
    ror fac1
    dey
    bne @L0
    sta fac2
    sta result+1
    lda fac1
    sta result
    rts
    .endp

    .link 'printf.obx'

    Wynik wciąż w okolicach 198 ramek przy stosowaniu zmiennych na stornie zerowej. Znaczy, że siła Mad Pascala tkwi w optymalizacjach których ja w MADS nie robię bo jest o 10 ramek szybszy od mojego ASM.

    W tym konkretnym teście Mad Pascal zaskakuje po całości! :]
    • 46: CommentAuthorrobert
    • CommentTime8 Mar 2020
     
    Cos poprawi jesli:
    mwa result y
    adw x y
    zamienic na:
    adw x result
    • 47: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    @robert faktycznie dobry skrót, tylko każdy taki skrót i kod coraz mniej czytelny :D no ale właśnie w tym kierunku chcę iść co proponujesz ;)

    Dzięki @robert prawie dogoniliśmy Mad Pascal! Drugi ekran to MadP, brakuje jeszcze parę ramek ;)

    Wyniki wahają się o 1 ramkę w zależności czy wpada się w IF czy nie.

    Optymalizacje MadP to widzę, raczej używanie mva niż mwa idt.

    EDIT: chyba jeszcze coś z tego kodu w ASM wycisnę, postaram się go uprościć.
    • 48: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    No... urwałem jeszcze parę ramek ;)

    org $2000

    .var time .word
    .var i,b,radius,x,y .word = $80
    .var fac1,fac2 .byte = $e0
    .var result .word =$e0

    mwa #16129 radius
    mwa #0 i
    mwa #0 b

    wait
    mwa #0 $13

    loop #while .word i < #10000

    inw i

    lda $d20a
    and #$7f
    sta fac1
    sta fac2
    imulCL
    mwa result x

    lda $d20a
    and #$7f
    sta fac1
    sta fac2
    imulCL
    mwa result y

    adw x y

    sbw x radius
    bcs loop
    inw b

    #end

    mva #0 x
    lda b+1
    sta fac1
    lda #4
    sta fac2
    imulCL
    mva result x+1

    lda b
    sta fac1
    lda #4
    sta fac2
    imulCL

    adw x result

    mva $14 time
    mva $13 time+1

    jsr printf
    .by 'pi %',$1e,$1e,$1e,$1e,$ff,$2c,$9b
    .by 'fps % ',$9b,0
    dta a(x)
    dta a(time)

    jmp *

    .proc wait
    lda:cmp:req $14
    rts
    .endp

    .proc imulCL
    ldy #8
    lda #0
    lsr fac1 ; Get first bit into carry
    @L0: bcc @L1
    clc
    adc fac2
    @L1: ror @
    ror fac1
    dey
    bne @L0
    sta fac2
    rts
    .endp

    .link 'printf.obx'

    Pomysłów na dalszą optymalizację (przy mojej obecnej znajomości ASM) brak.

    Przy tym samym algorytmie mnożenia, nie przebiłem rezultatu Mad Pascala.
    • 49: CommentAuthorrobert
    • CommentTime8 Mar 2020 zmieniony
     
    Poprawke ktora proponowalem mialem na mysli umiescic wewnatrz petli, tam gdzie liczenie y^2. Na ostatnim listingu tego nie ma, jest tylko zastosowany na koncowych obliczeniach za petla. Procedure mnozenia mozna rozpisac bez petli i pewnie bedzie szybciej, tak jak jest pod linkiem strony z mnozeniami.
    (8bit multiplication (16bit product) fast no tables - by djmips) ->link<-
    • 50: CommentAuthorzbyti
    • CommentTime8 Mar 2020 zmieniony
     
    @robert musiałem, czegoś nie dostrzec, może wklej swój kod w całości i zastosuj <code></code> tylko nawiasy kwadratowe.

    Zobacz, że zmieniłem procedurę mnożenia tak, ze result już nie jest przepisywane.

    By mieć porównanie to mnożenie niech będzie (z grubsza) takie jakie stosuje kompilator Mad Pascala.

    -----------------------------------------------------------

    Yosh Plus MADS 2.1.0
    org $2000

    .var i,a,b .word = $80

    mwa #0 a
    mwa #0 b
    mwa #0 i

    wait
    mva #0 $14

    loop inw a
    mwa a b
    inw b
    mwa b a
    inw i
    lda $14
    cmp #100
    bne loop

    jsr printf
    .by '% iterations',$9b,0
    dta a(i)

    jmp *

    .proc wait
    lda:cmp:req $14
    rts
    .endp

    .link 'printf.obx'

    Wynik identyczny jak w MadP.