eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronika › Zagwozdka w C Keil.
Ilość wypowiedzi w tym wątku: 84

  • 51. Data: 2019-02-14 11:59:24
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: q...@t...no1 (Queequeg)

    J.F. <j...@p...onet.pl> wrote:

    > Cos w tym jest, ale z drugiej strony - skoro uzywamy volatile, to
    > wiadomo ze zmienna moze sie zmieniac w przerwaniach czy w inny
    > niekontrolowany sposob, i co - kompilator to olewa ?

    Ale co kompilator może zrobić, jak sam procesor nie obsługuje atomicznego
    dostępu do tej zmiennej (bo np. jest 8-bitowy, a zmienna 16-bitowa)?
    Zresztą nawet w przypadku zmiennych o rozmiarze równym szerokości
    magistrali danych nie ma gwarancji chociażby w przypadku operacji
    read-modify-write. Przykład:

    #v+ test.c
    volatile int i;
    void fn(void) { ++i; }
    #v-

    #v+ test.s
    ldr r3, [r2] ; odczyt zmiennej z pamięci do rejestru r3
    add r3, r3, #1 ; dodanie do rejestru r3 liczby 1
    str r3, [r2] ; zapis rejestru r3 z powrotem do pamięci
    #v-

    Zmienna może się zmienić między każdą z tych instrukcji.

    Bardziej realny przykład, AVR. Chcemy zmienić stan bitu 2 w porcie na
    przeciwny.

    #v+ avr.c
    #include <avr/io.h>
    void fn(void) { PORTB ^= _BV(2); }
    #v-

    Kompilacja: avr-gcc -mmcu=atmega8 -O2 -S avr.c

    #v+ avr.s
    in r24,0x18 ; załadowanie adresu portu do r24
    ldi r25,lo8(4) ; załadowanie wartości _BV(2) do r25
    eor r24,r25 ; wykonanie r24 xor r25, zapis do r24
    out 0x18,r24 ; wysłanie wartości z r24 do portu
    #v-

    Między każdą z tych instrukcji również może wystąpić przerwanie, które np.
    ustawi inny bit w tym porcie, który to bit zostanie ładnie wyczyszczony
    podczas otatniej operacji (zapisu r24 do portu).

    > No coz, przejsc na ARM i zapomniec o problemie ...

    Czemu? Co ma do tego ARM? Chodzi o szerokość magistrali danych? To
    rozwiązuje tylko jeden problem, ale inne (chociażby ten pierwszy
    przykład wyżej) pozostają.

    --
    Eksperymentalnie: http://facebook.com/groups/pl.misc.elektronika


  • 52. Data: 2019-02-14 12:14:16
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: q...@t...no1 (Queequeg)

    J.F. <j...@p...onet.pl> wrote:

    >>.L2:
    >> cmp r3, #42 ; tu porównuje rejestr
    >> bne .L2 ; tu skacze z powrotem do porównania
    >
    > kiepski optymalizator ... czemu porownuje w petli ?

    Tak... też nie rozumiem tej logiki. Albo jedno albo drugie, a tu jest
    takie pół na pół :)

    >>Dlaczego tak? Bo kompilator wie, że inna jednostka kompilacji nie zmieni
    >>wartości tej zmiennej (bo jest statyczna, widoczna tylko w obrębie danej
    >>jednostki kompilacji), więc nie ma sensu żadne sprawdzanie, bo zmienna i
    >>tak jest zero (bo zmienne globalne są inicjalizowane zerami; spróbuj
    >>zamiast 42 wstawić 0 i zobacz, jaki kod wtedy kompilator wygeneruje).
    >
    > wstaw 41.

    Będzie to samo, bo 41 to nie 0.

    > Albo w jakiejs funkcji wpisz i=40 ...

    Ok, robimy:

    #v+ test.c
    int i;
    void fn1(void) { while (i != 42) ; }
    void fn2(void) { i = 40; }
    #v-

    gcc -O2 -S test.c

    #v+ test.s, fn1
    ldr r3, .L5 ; ładuje do r3 adres zmiennej
    ldr r3, [r3] ; ładuje do r3 wartość zmiennej
    .L2:
    cmp r3, #42 ; porównuje zapamiętaną wartość z 42
    bne .L2 ; skacze do porównania
    #v-

    #v+ test.s, fn2
    ldr r3, .L8 ; ładuje do r3 adres zmiennej
    mov r2, #40 ; ładuje do r2 wartość 40
    str r2, [r3] ; zapisuje wartość r2 pod adresem zmiennej
    #v-

    Możemy sprawdzić to empirycznie. Program:

    #v+
    #include <signal.h>
    #include <unistd.h>
    #include <stdio.h>

    static int g_signo;

    static void sighnd(int signo)
    {
    printf("Wywolano sighandler\n");
    g_signo = signo;
    }

    int main(void)
    {
    signal(SIGALRM, sighnd);
    alarm(2);

    printf("Czekanie na sygnal\n");
    while (!g_signo) ;
    printf("Odebrano sygnal\n");

    return 0;
    }
    #v-

    Kod bez optymalizacji (gcc -O0) widzi zmianę w g_signo. Kod z -O1 i -O2
    nie widzi. Dodanie `volatile` do definicji zmiennej sprawia, że kod nawet
    z optymalizacjami widzi zmianę.

    Testowane na raspberry (Raspbian), gcc 4.9.2.

    --
    Eksperymentalnie: http://facebook.com/groups/pl.misc.elektronika


  • 53. Data: 2019-02-14 13:07:00
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: "J.F." <j...@p...onet.pl>

    Użytkownik "Queequeg" napisał w wiadomości grup
    dyskusyjnych:4217c591-37b4-4703-974b-66fbe15cdae0@tr
    ust.no1...
    J.F. <j...@p...onet.pl> wrote:
    >>>Dlaczego tak? Bo kompilator wie, że inna jednostka kompilacji nie
    >>>zmieni
    >>>wartości tej zmiennej (bo jest statyczna, widoczna tylko w obrębie
    >>>danej
    >>>jednostki kompilacji), więc nie ma sensu żadne sprawdzanie, bo
    >>>zmienna i
    >>>tak jest zero (bo zmienne globalne są inicjalizowane zerami;
    >>>spróbuj
    >>>zamiast 42 wstawić 0 i zobacz, jaki kod wtedy kompilator
    >>>wygeneruje).
    >
    >> wstaw 41.

    >Będzie to samo, bo 41 to nie 0.

    ale bylo
    void fn(void) { do { } while (i != 42); }


    >> Albo w jakiejs funkcji wpisz i=40 ...

    >Ok, robimy:

    >#v+ test.c
    >int i;

    ale jeszcze static

    >void fn1(void) { while (i != 42) ; }
    >void fn2(void) { i = 40; }
    >#v-

    >gcc -O2 -S test.c

    >#v+ test.s, fn1
    > ldr r3, .L5 ; ładuje do r3 adres zmiennej
    > ldr r3, [r3] ; ładuje do r3 wartość zmiennej
    >.L2:
    > cmp r3, #42 ; porównuje zapamiętaną wartość z 42
    > bne .L2 ; skacze do porównania
    >#v-

    >#v+ test.s, fn2
    > ldr r3, .L8 ; ładuje do r3 adres zmiennej
    > mov r2, #40 ; ładuje do r2 wartość 40
    > str r2, [r3] ; zapisuje wartość r2 pod adresem zmiennej
    >#v-

    W sumie poprawnie - jeszcze nie wie ktore funkcje beda uzyte, to musi
    skompilowac poprawnie.
    Ale trzeba bylo sprawdzic ze static.

    A potem ...

    static void fn2(void) { i = 40; }

    i jej nie wywolywac.

    Tudziez

    static void fn2(void) { i = 40; }

    main()
    {
    fn() ;
    fn2();
    }

    No i ciekawe, na ile dobrze zoptymalizuje :-)

    J.


  • 54. Data: 2019-02-14 13:11:16
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: "J.F." <j...@p...onet.pl>

    Użytkownik "Queequeg" napisał w wiadomości grup
    dyskusyjnych:c6cda8fa-82c3-48a0-a47d-aba030a5831b@tr
    ust.no1...
    J.F. <j...@p...onet.pl> wrote:
    >> Cos w tym jest, ale z drugiej strony - skoro uzywamy volatile, to
    >> wiadomo ze zmienna moze sie zmieniac w przerwaniach czy w inny
    >> niekontrolowany sposob, i co - kompilator to olewa ?

    >Ale co kompilator może zrobić, jak sam procesor nie obsługuje
    >atomicznego
    >dostępu do tej zmiennej (bo np. jest 8-bitowy, a zmienna 16-bitowa)?

    To samo, co programista ma zrobic :-)

    >Zresztą nawet w przypadku zmiennych o rozmiarze równym szerokości
    >magistrali danych nie ma gwarancji chociażby w przypadku operacji
    >read-modify-write. Przykład:

    >#v+ test.c
    >volatile int i;
    >void fn(void) { ++i; }
    >#v-

    >#v+ test.s
    >ldr r3, [r2] ; odczyt zmiennej z pamięci do rejestru r3
    >add r3, r3, #1 ; dodanie do rejestru r3 liczby 1
    >str r3, [r2] ; zapis rejestru r3 z powrotem do pamięci
    >#v-
    >Zmienna może się zmienić między każdą z tych instrukcji.

    Cos w tym jest.

    >> No coz, przejsc na ARM i zapomniec o problemie ...

    >Czemu? Co ma do tego ARM? Chodzi o szerokość magistrali danych? To
    >rozwiązuje tylko jeden problem,

    Tak, problemu z int nie bedzie :-)

    >ale inne (chociażby ten pierwszy przykład wyżej) pozostają.

    Ciezkie jest zycie programisty.

    I co sie dziwic, ze MS w C# zrobil stringi niemodyfikowalne ...

    J.


  • 55. Data: 2019-02-14 13:15:09
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: "J.F." <j...@p...onet.pl>

    Użytkownik "Grzegorz Niemirowski" napisał w wiadomości grup
    dyskusyjnych:q43h41$kh6$...@n...news.atman.pl...
    J.F. <j...@p...onet.pl> napisał(a):
    >> Cos w tym jest, ale z drugiej strony - skoro uzywamy volatile, to
    >> wiadomo ze zmienna moze sie zmieniac w przerwaniach czy w inny
    >> niekontrolowany sposob,
    >> i co - kompilator to olewa ?

    >Nie olewa przecież, bo przestaje względem niej wykonywać
    >optymalizacje. Natomiast nie robi nadgorliwych przeróbek, które
    >spowodowałyby niekontrolowane zachowanie programu. Naprawdę chciałbyś
    >żeby kompilator gdzieś po cichu włączał albo wyłączał Ci przerwania?

    Na kilka instrukcji ... czemu nie.

    Szczegolnie, ze ... sam musze je wylaczyc, jesli nie chce takich
    niespodzianek.
    To co przyniesie wiecej szkody - jak kompilator bedzie je wylaczal
    automatycznie, czy jak ja zapomne ? :-)

    Natomiast na niektorych procesorach moze byc problem z odtworzeniem
    stanu przerwan,
    no i kwestia robienia tego w procedurze obslugi przerwania czy
    zagniezdzania przerwan.

    J.


  • 56. Data: 2019-02-14 13:25:23
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: q...@t...no1 (Queequeg)

    J.F. <j...@p...onet.pl> wrote:

    > Na kilka instrukcji ... czemu nie.

    Ale skąd kompilator ma wiedzieć, że dana zmienna jest akurat modyfikowana
    w przerwaniu?

    --
    Eksperymentalnie: http://facebook.com/groups/pl.misc.elektronika


  • 57. Data: 2019-02-14 13:36:34
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: "Grzegorz Niemirowski" <g...@p...onet.pl>

    J.F. <j...@p...onet.pl> napisał(a):
    > Na kilka instrukcji ... czemu nie.

    Których instrukcji? Wszystkich odwołujących się do tej zmiennej? Nadmierna,
    ukryta ingerencja w kod. Efektem będzie np. niepożądany jitter. Kod robi się
    mniej przewidywalny.

    > Szczegolnie, ze ... sam musze je wylaczyc, jesli nie chce takich
    > niespodzianek.

    Albo przepisać tak, żeby wyłączanie nie było konieczne.

    > To co przyniesie wiecej szkody - jak kompilator bedzie je wylaczal
    > automatycznie, czy jak ja zapomne ? :-)

    Zdecydowanie jak kompilator będzie wyłączał automatycznie. Ty sobie
    przypomnisz i będzie OK. A miliony programistów będą się męczyć z dziwnym,
    nieprzewidywalnym zachowaniem kompilatora, który próbuje być mądrzejszy od
    nich.

    --
    Grzegorz Niemirowski
    https://www.grzegorz.net/


  • 58. Data: 2019-02-14 13:52:28
    Temat: Re: Zagwozdka w C Keil - wyja?nienie.
    Od: a...@m...uni.wroc.pl

    Grzegorz Niemirowski <g...@p...onet.pl> wrote:
    > Janusz <j...@o...pl> napisa?(a):
    > > A to " (czyli ?e wy??czy wszystko inne, co mo?e zmieni? jej
    > >>>> warto?? w trakcie dost?pu -- czy to w?tki, czy przerwania, czy
    > > zewn?trzny
    > >>>> sprz?t)."
    > > nic takiego kompilator nie robi.
    >
    > A to "`volatile` nie oznacza, ?e kompilator gwarantuje atomiczny dost?p do
    > zmiennej (czyli ?e wy??czy"?
    > Nie do??, ?e masz problem z czytaniem ze zrozumieniem, to jeszcze wyci??e?
    > kluczowy fragment, kt?ry pokazuje, ?e czepiasz si? bez sensu.

    Januszowi wlasnie chodzilo o to ze nie: 'volatile' w intencji sluzy
    do obsugi sprzetu: jak np. urzadzenie zlicza ile razy byl zrobiony
    zapis to wynik ma byc taki jak wynika jak napisal programista,
    nic mniej, nic wiecej. Sprzet zwykle nie wymaga atomicznego
    zapisu wiec 'volatile' nie daje takiej gwarancji. 'volatile'
    moze tez byc uzyte do innych celow, dlatego standard zawiera
    bardzo ogolne sformulowanie. Ale _nie_ ma zadnej gwarancji
    atomicznosci.

    --
    Waldek Hebisch


  • 59. Data: 2019-02-14 13:59:28
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: q...@t...no1 (Queequeg)

    J.F. <j...@p...onet.pl> wrote:

    >>Ale co kompilator może zrobić, jak sam procesor nie obsługuje
    >>atomicznego dostępu do tej zmiennej (bo np. jest 8-bitowy, a zmienna
    >>16-bitowa)?
    >
    > To samo, co programista ma zrobic :-)

    Programista ma kontekst, którego nie ma kompilator. Programista wie, kiedy
    chce mieć sekcję krytyczną (która nie musi obejmować wyłącznie atomicznego
    dostępu do zmiennej szerszej niż magistrala adresowa).

    >>Zmienna może się zmienić między każdą z tych instrukcji.
    >
    > Cos w tym jest.

    Jest jest... po to są sekcje krytyczne.

    >>Czemu? Co ma do tego ARM? Chodzi o szerokość magistrali danych? To
    >>rozwiązuje tylko jeden problem,
    >
    > Tak, problemu z int nie bedzie :-)

    Z odczytem int nie, ale np. z read-modify-write już tak.

    >>ale inne (chociażby ten pierwszy przykład wyżej) pozostają.
    >
    > Ciezkie jest zycie programisty.

    A to swoją drogą... ale raczej przez ludzi a nie przez komputery :)

    Trzeba po prostu pamiętać, że (przynajmniej w przypadku C i C++)
    kompilator nie tłumaczy kodu na język maszynowy jeden do jednego. Kod to
    tylko pewien abstrakcyjny opis, który kompilator może traktować z dosyć
    dużą dowolnością. Dochodzą do tego chociażby zagadnienia związane z
    reorderingiem.

    Przykładowo:

    https://www.nongnu.org/avr-libc/user-manual/optimiza
    tion.html

    1. Dzielimy (powolna operacja)
    2. Wyłączamy przerwania cli
    3. Zapisujemy wynik dzielenia do zmiennej (szybka operacja)
    4. Włączamy przerwania

    A optymalizator twierdzi, że wyłączy sobie przerwania przed dzieleniem, bo
    tak mu mnieszy kod wychodzi :)

    Gdy zagłębimy się w optymalizowanie "undefined behavior", to robi się
    jeszcze ciekawiej. Przykładowo:

    #v+
    void fn(int *p)
    {
    int a = *p; // martwy kod
    if (p == 0) return; // nadmiarowe sprawdzenie
    *p = 1;
    }
    #v-

    Spodziewalibyśmy się, że `if (p == 0) return;` nie zostanie usunięte, ale
    ponieważ programista wcześniej dokonał dereferencji, a dereferencja null
    pointera jest UB, to kompilator może usunąć ten drugi, nadmiarowy test bo
    zakłada, że nie ma UB (czyli że p nie może być 0). Moje gcc nie usuwa, bo
    najpierw usuwa martwy kod, ale wcale nie musi -- inna wersja lub inny
    kompilator może zachowywać się inaczej i najpierw usunąć nadmiarowe
    sprawdzenie, a dopiero potem martwy kod.

    Kolejny przykład.

    #v+
    #include <limits.h>
    #include <stdio.h>

    int fn(int i)
    {
    if (i + 1 > i)
    printf("Nie ma integer overflow\n");
    else
    printf("Uwaga: integer overflow\n");
    }

    int main(void)
    {
    fn(INT_MAX);
    return 0;
    }
    #v-

    Kompilujemy z -O0, dostajemy wynik, że jest integer overflow. Kompilujemy
    z -O2, optymalizator stwierdza, że przepełnienie typu ze znakiem jest UB,
    więc usuwa nam ten warunek (ustawia go na true).

    > I co sie dziwic, ze MS w C# zrobil stringi niemodyfikowalne ...

    W C# pisałem coś tylko raz i tylko dlatego, że musiałem :) Zupełnie nie
    moja działka.

    --
    Eksperymentalnie: http://facebook.com/groups/pl.misc.elektronika


  • 60. Data: 2019-02-14 14:01:44
    Temat: Re: Zagwozdka w C Keil - wyja?nienie.
    Od: "Grzegorz Niemirowski" <g...@p...onet.pl>

    a...@m...uni.wroc.pl <a...@m...uni.wroc.pl> napisał(a):
    > Januszowi wlasnie chodzilo o to ze nie: 'volatile' w intencji sluzy
    > do obsugi sprzetu: jak np. urzadzenie zlicza ile razy byl zrobiony
    > zapis to wynik ma byc taki jak wynika jak napisal programista,
    > nic mniej, nic wiecej. Sprzet zwykle nie wymaga atomicznego
    > zapisu wiec 'volatile' nie daje takiej gwarancji. 'volatile'
    > moze tez byc uzyte do innych celow, dlatego standard zawiera
    > bardzo ogolne sformulowanie. Ale _nie_ ma zadnej gwarancji
    > atomicznosci.

    Ależ czy ktoś pisał inaczej?

    PS. tin nie obsługuje polskich liter?

    --
    Grzegorz Niemirowski
    https://www.grzegorz.net/

strony : 1 ... 5 . [ 6 ] . 7 ... 9


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: