Gość s6s Opublikowano 6 Czerwca 2015 Udostępnij Opublikowano 6 Czerwca 2015 W nawiązaniu do problemu rozsynchronizowywania się czasu systemowego w ADB5800 przy przetaktowaniu CPU i/lub przy moderate_shutdown poruszonego w wątku Graterlia OS TESTING - uwagi i błędy do wersji z gałęzi test rozważmy, apeluję, napisanie odpowiedniego skryptu czysto obliczeniowo kompensującego spowolnienia/przyspieszenia czasu. Ów skrypt korygował by czas, bez potrzeby łączenia się z Intenetem ani bez pobierania danych z transpondera. Wyłącznie obliczeniowo. Przecież już mamy potrzebne dane: - właściwą częstotliwość przy której zegar odmierza prawidłowo czas = 265.5 MHz - częstotliwość zmienioną, np. w moderate_standby = 36 MHz Jeżeli wrzucimy taki skrypt do /etc/cron/minutely wówczas system wywoła go "co minutę" - w/g swego spowolnionego czasu w stosunku = 265.5 / 36 = 7.375 czyli tak naprawdę ów skrypt zostanie wywołany co 7.375 minut (zamiast co minutę), więc co powinien ów skrypt zrobić to "popchnąć" czas o 265.5 * 60 / 36 - 60 = +382.5 sekund do przodu (nazywajmy to PRZESUNIĘCIEM), odczytać czas przy pomocy date +%s, dodać owe 382 i pół sekundy, przekonwertować za pomocą date --date="@wynik_w_sekundach" +%T i z powrotem zapisać za pomocą date hh:mm:ss Albo od razu zapisać bez konwertowania za pomocą ilości sekund "od początku epoki": date --set="@liczba_sekund" Ponieważ przy tych rachunkach otrzymujemy ułamki, a zależy nam na jak największej precyzji aby korekcja czasu okazała się jak najbardziej skuteczna, więc warto by móc zapisać jakoś czas z dokładnością mniejszą niż co do całych sekund! Jak to zrobić? Ponieważ polecenie 'date' nie oferuje takiej możliwości... Pozwala owszem odczytać nawet nanosekundach: date +%s:%N ale chyba nie ma możliwości zapisania czasu z dokładnością do nanosekundy - przynajmniej za pomocą polecenia "date", a może mozna inaczej?) Powyższe rozumowanie wydaje Wam się poprawne? Pomożecie takie coś ułożyć? ;) (Wiadomo, że dokładności perfekcyjnej tak nie osiągniemy, trzeba by zwrócić uwagę na precyzję dzielenia/mnożenia, a raczej kolejność działań, metody numeryczne kłaniają się ;) Ale i tak sprawimy, że np. po paru dniach bez Internetu w moderate_shudown jednak zegar pokaże nam cokolwiek sensownego! :)) Pytanie: co pokazują wartości: cat /proc/timer_list |grep now oraz cat /proc/uptime szczególnie uptime... mamy tam dwie wartości-liczniki, z czego tempo zmiany tej pierwszej wyraźnie zależy od stanu przetaktowania procesora... (a tej drugiej nie) EDIT: Wydawałaby się naiwnie, że taki skrypt mógłby spełnić swe zadanie: #!/bin/sh #/etc/cron/minutely/adjustClock PERIOD=60 #seconds minutely RightMHz=266 MHz PresentMHz=$(cat /proc/cpu_frequ/pll0_ndiv_mdiv |grep "SH4 "); PresentMHz=$(echo $PresentMHz | cut -d ' ' -f3); ADDsekundy=$(( $RightMHz * $PERIOD / $PresentMHz - $PERIOD )) sekundy=$(date +%s); string=$(date --date="@$sekundy" +%T); sekundy=$(($sekundy + $ADDsekundy)) string=$(date --date="@$sekundy" +%T); date $string # powyzsze po prostu mozna zastapic linijka kodu: # date --set=@$(( $ADDsekundy + $(date +%s) )) # ale rozbicie na poszczegolne kroki przydaje sie w debbug'owaniu Jednak problem powstaje gdyż przestawienie czasu przez 'date $string' wywołuje natychmiast /etc/cron/minutely i skrypt się zapętla. (Przy czym wywołuje cron/minutely przy każdym przekroczeniu pełnej minuty (przez sekundnik dwunastki na tarczy zegara) - zarówno w przód jak i w tył!) Ciekawe dlaczego nptdate nie wywołuje takiego efektu? Jakoś wysysła sygnał do cron'a? Więc albo trzeba ten skrypt puścić niezależnie od crona (polecenie sleep ?) albo wstawiać znaczniki, żeby załóżmy co drugie wywołanie wywołało rzeczywistą zmianę czasu. EDIT': Jednak poleganie na 'sleep' przynosi dobre efekty, z cronem nie ma się co bawić Więc stworzymy osobny daemon, coś na kształt: #!/bin/sh # /usr/sbin/adjustClockd PERIOD=30 # w sekundach co jaki czas uaktualnienie? (wlasnego czasu np. spowolnionego) RightMHz=26550 # wartosc w MHz pomnozona przez 100 aby przedstawic w Integer ulamki (bash operuje tylko na Integer) while true do PresentMHz=$(cat /proc/cpu_frequ/pll0_ndiv_mdiv |grep "SH4 "); PresentMHz=$(echo $PresentMHz | cut -d ' ' -f3); #wewnetrzna biezaca zmieniona czestotliwosc zagara pomnozona przez 100 PresentMHz=$(( PresentMHz * 100 )) #wartosc korekcji ADDsekundy=$(( $RightMHz * $PERIOD / $PresentMHz - $PERIOD )); #wartosc czasu podana w sekundach "od poczatku epoki" sekundy=$(date +%s); sekundy=$(($sekundy + $ADDsekundy)); #wartosc czasu po korekcie podana w sekundach teraz zapisywana z powrotem do systemu date --set="@$sekundy" #mozna krocej: # date --set=@$(( $ADDsekundy + $(date +%s) )) # ale tamto przydaje sie do debbug'owania #Czekanie do kolejnej iteracji sleep $PERIOD done Proszę o wsparcie, jak dostosować tę procedurę do formatu deamonów Graterlii? ------------------------------------------------------------------------ Więc skrypt główny (nazwany adjustClockd) wrzucam do /usr/sbin i system startuje go za pomocą skryptu w /etc/init.d/adjustClock o takiej (baardzo szkicowej jeszcze) formie: #!/bin/sh . /etc/sysconfig/gfunctions #wczytanie funkcji wsp??lnych dla skrypt??w Graterlia scriptname="adjustClock" #nazwa uruchamianego czego?. runname=/var/grun/runAdjustClock #plik informuj?.cy czy uruchomiono, czy nie msginfo="start, stop, restart, status" #informacja o mo??liwych parametrach PATH=/sbin:/bin:/usr/sbin:/usr/bin #deklaracja ?.cie??ek gstart() { /usr/sbin/adjustClockd & echo "adjustClock wlaczony" # touch $runname } gstop() { echo "still running" } case "$1" in 'start') startapp ;; 'stop') stopapp ;; 'status') checkapp ;; 'restart') # stopapp # sleep 1 # startapp ;; *) infoparm ;; esac Cytuj Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
mickey Opublikowano 7 Czerwca 2015 Udostępnij Opublikowano 7 Czerwca 2015 Nie nadążam za tym skryptem :) Ale tak ogólnie, to wydaje mi się, że: RightMHz=265 a nie 256? Powinno być chyba 266, ale akurat taką wartość podaje mi cpu_freq. Co do numerków w /proc/uptime: https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-uptime.html. I taki prosty skrypt powinien wystarczyć: while true do if moderate_standby_on sleep PresentMHz zmien_czas_o RightMHz-PresentMHz else nie_rob_nic fi done Jakoś nie mam głowy do zamieniania tego na komendy. Żeby było naprawdę dokładnie, to ntpdate musi się odpalić co jakiś czas. A nagrania planowane z dużym wyprzedzeniem trzeba by z dużym zapasem robić. Można by to jeszcze poprawić tak: licznik=0 while true do if moderate_standby_on licznik=(licznik+1) % korekta sleep PresentMHz zmien_czas_o RightMHz-PresentMHz if licznik==0 skoryguj_czas fi else nie_rob_nic_a_najlepiej_wylacz_skrypt fi done Zmienna korekta jest do dobrania doświadczalnie po jakimś pomiarze, który pokaże o ile sekund, w którą stronę i co ile okresów zmian należy skorygować czas. Cytuj Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Gość s6s Opublikowano 9 Czerwca 2015 Udostępnij Opublikowano 9 Czerwca 2015 Wielkie dzięki za uwage i podpowiedź! Jasne, pomyłka, właściwa częstotliwość = 265.50 MHz, pokazywana chyba przez: cat /proc/clocks | grep st40_clk (?) Problem tutaj z precyzją obliczeń polega na tym, że w skryptach basha nie ma liczb zmiennoprzecinkowych, jedynie integer. Więc jak mam ułamki to mnożę przez jakiś współczynnik ($PMULTI, aby po pomnożeniu mieć integer) i na tym "poziomie" operować, ale potem i tak muszę podać czas zaokrąglony co do pojedynczej sekundy... A, jeszcze dodam, że nie tylko w stanie moderate_shutdown ten skrypt powinien działać, także przecież przy włączeniu kiedy mamy przetaktowany procesor (wówczas wewnętrzny czas begnie za szybko i skrypt spowalnia go co zadany PERIOD, a przy moderate_shutdow czas biegnie za wolno i skrypt przyspeisza) Jeszcze: po włączeniu po półtora doby, czas jednak uaktualnił się przez dongle DVBT... A wcześniej nie chciał, dziwne... Widocznie robi to bardzo kapryśnie, "od święta" ;) Ważna kwestia: /proc/uptime is quite minimal: 350735.47 234388.90 The first number is the total number of seconds the system has been up. The second number is how much of that time the machine has spent idle, in seconds Więc czemu tempo zmian tego drugiego parametru zdaje się nie przyspieszać ani nie spowalniać przy przetaktowaniu procesora, ani w moderate_shutdown? Czyży korzystał z innego jakiegoś zegara systemowego, a może sprzętowego? (Jak nie wierzycie to proszę oto odczyty z mojego ADB po tej półtora doby w moderate_shutdown: cat /proc/uptime 2547.80 8226.87 Jak widać czas spędzony w idle przekracza kilkakrotnie czas uptime! Również ciekawostka: ani przestawienie czasu w tył ani w przód nie wpływa na żadną wartość w /proc/uptime) Ponieważ jeżeli idle korzysta z zegara niezależnego i odpornego na przetaktowanie więc może by wykorzystać go do korekcji czasu w warunkach każdej zmiany w taktowaniu procesora... P.S. Jeszcze, z czystej ciekawości: jak to dzieje się przy "oryginalnym" rozwiązaniu, kiedy nptdate wrzucono do /etc/cron/minutely? Wówczas kiedy zmiana czasu przeskoczy przez pełną minutę - nie ważne czy w przód czy w tył - wtedy cokolwiek znajduje się w /etc/cron/minutely wywoła się ponownie - więc przy każdej procedurze zmiany czasu wewnętrznego może nastąpić zapętlenie! Więc albo npt serwer broni się jakoś przed ponownym wywołaniem co parę sekund, albo klient pezkazuje jakis sygnał do crond? ---------------------------------------------------------------- I taki prosty skrypt powinien wystarczyć: while true do if moderate_standby_on sleep PresentMHz zmien_czas_o RightMHz-PresentMHz else nie_rob_nic fi done Czyli podobnie, lecz z tym, że Ty przyjąłeś "na sztywno" ów PERIOD=PresentMHz. W ten sposób chciałeś uniknąć ułamków. Ale skoro samo RightMHz=265.5 okazało się ułamkiem to co teraz? (Wtedy, uaktualnienie następowałoby co około 4.4 minuty, a jak pomnożyłbyś przez 2 częstotliwości RightMHz i PresentMHz to co prawie 9 minut - czy to nie za duży "zapas" potrzebny do timer'a?) W każdym razie, po przełożeniu na polecenia bash'a powyższego skrypt wygląda następująco: /usr/sbin/adjustClockd #!/bin/sh RightMHz=265 # 265 wartosc w MHz while true do # wewnetrzna biezaca zmieniona czestotliwosc zagara PresentMHz=$(cat /proc/cpu_frequ/pll0_ndiv_mdiv |grep "SH4 "| /usr/bin/awk '{print $3}') # wartość przesunięcia ADDsek=$(( $RightMHz - $PresentMHz )) date --set=@$(( $ADDsek + $(date +%s) )) sleep $PresentMHz # czekamy PERIOD=PresentMHz done Ale, żeby uaktualnienia następowały częściej, np. co minutę, przy szacowaniu wartości przesunięcia co okres "period" jak najdłuższy, rozbijmy te sprawy na osobne pętle: ITERATIONS=11 # wyznaczmy rozsądną wartość, w sumie dowolną while true do wyznacz ADDsek = RightMHz - PresentMHz kwantADD = ADDsek / ITERATIONS kwantPERIOD = PresentMHz / ITERATONS i=ITERATIONS while [ $(( --i )) -gt 0 ]. do if czestotliwosc wlasnie zmienila sie to wyznaczamy wartosci zmian od nowa! break fi Skorygowany Czas = Czas + $kwantADD sleep $kwantPeriod done done Pełny skrypt wygląda następująco: /usr/sbin/adjustClockd #!/bin/sh ITERATIONS=6 PMULTI=3 # Wielokrotnosc MHz. RightMHz=265 # 265 wartosc w MHz. rightM=$(( $RightMHz * $PMULTI )) # ...pomnozona przez PMULTIa while true do PresentMHz=$(cat /proc/cpu_frequ/pll0_ndiv_mdiv |grep "SH4 "| /usr/bin/awk '{print $3}') # period = wewnetrzna biezaca zmieniona czestotliwosc zagara pomnozona przez PMULTIa # Jezeli obecna czstotliwosc jest normalna to nic ni rob while [ $PresentMHz -gt 250 ] && [ $PresentMHz -lt 270 ] do echo "Idling now as current frequency is intact" sleep 49; done period=$(( $PresentMHz * $PMULTI )) ADDsek=$(( $rightM - $period )); # kwant Sekund i Period'a quaSec=$(( $ADDsek / $ITERATIONS )) quaPer=$(( $period / $ITERATIONS )) # Poczatkowa wartosc = Reszta z dzielenia resSec=$(( $ADDsek % $ITERATIONS )) resPer=$(( $period % $ITERATIONS )) # Skorygowany Czas = Czas + Resza z dzielenia date +%T --set=@$(( $(date +%s) + $resSec )) # Pierwsze sleep = Reszta z dzielenia sleep $resPer; i=$(( $ITERATIONS + 1 )) while [ $(( --i )) -gt 0 ] do # Jezeli czestotliwosc wlasnie zmienila sie to wyznaczamy wartosci zmian od nowa! if [ -z "$(/bin/cat /proc/cpu_frequ/pll0_ndiv_mdiv | /bin/grep "SH4 "| /bin/grep $PresentMHz)" ]; then echo PresentMHz changed!!!!!! $(cat /proc/cpu_frequ/pll0_ndiv_mdiv |grep "SH4 ") break fi # Skorygowany Czas = Czas + Kwant sekund date +%T --set=@$(( $(date +%s) + $quaSec )) sleep $quaPer done done Ważna kwetsia Próbuję różnych kodów, w tym takiego najprostszego zasugerowanego przez mickey'a. Ale za każdym razem zegar spieszy się mocno! Przykładowo o godzinę po ponad pół doby. Podczas gdy poprzednio kiedy omyłkowo RightMHz=256, zegarek systemowy wskazywał czas bez porównania dokładniej, po półtora doby z dokładnością do minuty! Jak to? Albo coś źle pokazuje częstotliwość, albo polecenie sleep ma jakiś "dryft" (subtelny) przy przetaktowaniu, albo w ogóle zależności czasu przy przetaktowaniu mają charakter nieliniowy? EDIT': Po ponad tygodniu prób i błędów wygląda na to, że "optymalna" częstotliwość "normalna" jaką należy zadać jako punkt odniesienia to... 255 i 1/3 :P Więc ułamek! Aby poradzić sobie z tym w bash'u (który przyjmuje jedynie liczby Integer) korzystam ze współczynnika PMULTI=3 i na sztywno od razu mnożę rightM=766 = 255.33... * 3. Więc obecnie /usr/sbin/adjustClockd wygląda następująco: #!/bin/sh ITERATIONS=17 PMULTI=3 # Wielokrotnosc MHz ###RightMHz=255.33... # 265 wartosc w MHz ###rightM=$(( $RightMHz * $PMULTI )) # ...pomnozona przez $PMULTIa Integer rightM=766 # 255.33... * 3 while true do PresentMHz=$(cat /proc/cpu_frequ/pll0_ndiv_mdiv |grep "SH4 "| /usr/bin/awk '{print $3}') # period = wewnetrzna biezaca zmieniona czestotliwosc zagara pomnozona przez... # przy narmalnej częstotliwości nic nie rób, czekaj while [ $PresentMHz -gt 250 ] && [ $PresentMHz -lt 270 ] do echo "Idling now as current frequency is intact" sleep 49; done period=$(( $PresentMHz * $PMULTI )) ADDsek=$(( $rightM - $period )); # kwant Sekund i Period'a quaSec=$(( $ADDsek / $ITERATIONS )) quaPer=$(( $period / $ITERATIONS )) # Poczatkowa wartosc = Reszta z dzielenia resSec=$(( $ADDsek % $ITERATIONS )) resPer=$(( $period % $ITERATIONS )) # Skorygowany Czas = Czas + Resza z dzielenia date +%T --set=@$(( $(date +%s) + $resSec )) # Peirwsze sleep = Reszta z dzielenia sleep $resPer; i=$(( $ITERATIONS + 1 )) while [ $(( --i )) -gt 0 ] do # Jezeli czestotliwosc wlasnie zmienila sie to wyznaczamy wartosci zmian od nowa! if [ -z "$(/bin/cat /proc/cpu_frequ/pll0_ndiv_mdiv | /bin/grep "SH4 "| /bin/grep $PresentMHz)" ]; then break fi # Skorygowany Czas = Czas + Kwant sekund date +%T --set=@$(( $(date +%s) + $quaSec )) sleep $quaPer done done Więc jak widać, różni od poprzedniej wersji tylko początkiem, czyli wyznaczeniem na sztywno PMULTI powiązanej z rightM! P.S. Jak móc przerwać pętlę w dowolnej chwili kiedy głównie ona stoi na poleceniu sleep? Skomponować własne MySleep() które odczytuje co sekundę czy częstotliwość zegara właśnie nie zmieniła się? Czyli coś takiego: # Wywolywana: MySleep ilosc_sekund $PresentMHz MySleep() { i=$(( ${1} + 1 )) while [ $(( --i )) -gt 0 ] do # Jezeli czestotliwosc wlasnie zmienila sie to... if [ -z "$(/bin/cat /proc/cpu_frequ/pll0_ndiv_mdiv | /bin/grep "SH4 "| /bin/grep ${2}" ]; then return 1 fi sleep 1 done return 0 } Wówczas zamiast pisać sleep $quaPer wywoływanoby (wewnątrz wewnętrznej pętli 'while'): MySleep $quaPer $PresentMHz [ $? -ne 1 ] || break Ale czy tak częste sprawdzanie owego cat /proc/cpu_frequ/pll0_ndiv_mdiv | grep "SH4 "| grep ${2}" nie szkodzi jakoś systemowi (sprzętowi??), a w szczególności jak długo trwa (czy nie porównywalnie do tejże sekundy)? Ewentualnie można jakoś rozważyć reagowanie na innego typu sygnały niż zmiana częstotliwości zegara, w szczególności jak zastopować deamon w dowolnej chwili poleceniem: '/etc/init.d/adjustClock stop'? Czy sprawdzanie co sekundę pliku $runname kosztuje coś system? # Wywolywana: MySleep ilosc_sekund $runname MySleep() { i=$(( ${1} +1 )) while [ $(( --i )) -gt 0 ] do # Jezeli np. plik runname=/var/grun/runAdjustClock właśnie znikł to przerwanie... if [ ! -e ${2} ]; then exit; fi sleep 1 done } Wówczas w skrypcie /etc/cron/moderatestandby_on/70cpu_frequ i /etc/cron/moderatestandby_off/10cpu_frequ trzeba by wstawić: /etc/init.d/adjustClock restart -------------------EDIT'': Eee, jednak w przypadku kiedy daemon /usr/sbin/adjustClockd sam nie ma reagować natychmiastowo na zmianę częstotliwości, wówczas zamiast bawić z MySleep() reagującą na sygnał od np. "/etc/init.d/adjustClock restart" więc zamiast robić własny mechanizm sygnałów to lepiej już wykorzystać istniejący systemowy. Więc niczego nie zmieniajmy w /usr/sbin/adjustClockd ale zamiast tego zróbmy odpowiednią funkcję gstop() w /etc/init.d/adjustClock: #!/bin/sh # Graterlia OS . /etc/sysconfig/gfunctions #wczytanie funkcji wspolnych dla skryptow Graterlia runname=/var/grun/runAdjustClock #plik informujacy czy uruchomiono, czy nie scriptname="adjustClock" #nazwa uruchamianego czegos msginfo="start, stop, restart, status" #informacja o mozliwych parametrach PATH=/sbin:/bin:/usr/sbin:/usr/bin # execname="adjustClockd" gstart() { /usr/sbin/$execname & echo "adjustClock wlaczony" touch $runname } gstop() { while true do runPID=$(ps -A |grep $execname | /usr/bin/awk '{print $1}') if [ -n "$runPID" ]; then kill -9 $runPID; fi if [ -z "$runPID" ]; then rm -f $runname; break fi done } case "$1" in 'start') startapp ;; 'stop') stopapp ;; 'status') checkapp ;; 'restart') stopapp sleep 1 startapp ;; *) infoparm ;; esac Spieszę donieść, że taka para - skrypt uruchomieniowy /etc/init.d/adjustClock i daemon /usr/sbin/adjustClockd wraz z wpisami w skryptach: /etc/cron/moderatestandby_on/70cpu_frequ i /etc/cron/moderatestandby_off/10cpu_frequ następującymi: if [ $rcstype == "ADB5800" ] || [ $rcstype == "ArivaLink200" ]; then /etc/init.d/adjustClock restart fi (w załaczniku komplet :) ) bardzo dobrze mi działają, czas trzyma się co do minuty, pomimo kapryśnego dostępu do Internetu kiedy tuner włączony, oraz żadnego dostępu kiedy przez ponad półtora doby tuner znajduje się w moderate_shutdown. Całkowicie mozna polegać w kwestii timer'ów! Przy czym podczas włączenia mam przetaktowany procesor do 360MHz, co sprawia że BSKA działa niewiele wolniej niż ESI ;) ------------------EDIT: W Plejerze systemowym trzeba przestawić w 'settings' na "player3" (z "Gstreamer"), albo używać MPlayer a nie MPlayer2, a najlepiej FREEplayer! Przy odtwarzaniu nagrań Player z Gstreamer przy overclocking występują jakies problemy z synchronizacją głosu lektora albo przeskakiwanie klatek. Jednak przy przestawieniu w 'settings' na "player3" działa lepiej (Widocznie Gstreamer polega zbytnio na zegarze systemowym, a player3 na czymś innym?) choć nadal wydaje się że występują drobne błędy w synchronizacji głosu i obrazu (przez spostrzegawczych zauważalne). Ale najlepiej działa FreePlayer, nie wiem dlaczego wydał sie odporny na przetaktowanie zegara... Przydałoby się jakoś zrobić, żeby przy zaczynaniu pracy Mplajera taktowanie cpu wracało do normalnej częstotliwości, jedynie na czas odtwarzania filmu, potem niech wraca do przetaktowanej prędkości... Póki co, przynajmnniej przyda się niniejsze narzędzie do korekcji czasu przy moderate_shutdown. Paczka w załączniku poprawiona żeby nic nie robiła podczas normalnej częstotliwości ;) adjustClock.tar.gz Cytuj Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
Dołącz do dyskusji
Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.