VimeoVimeo
RSSRSS
5.00 / 001

Cudaram - ramdysk na karcie NVIDIA

Banner

Jakiś czas temu pokazywałem Wam, jak można wykorzystać wolną pamięć karty graficznej do stworzenia szybkiego ramdysku. Często bywa, że pod Linuksem pamięć kart graficznych nie jest w pełni wykorzystana - dlaczego więc z niej nie skorzystać? O ile w przypadku otwartoźródłowych sterowników z pomocą przychodzi MTD, to w parze z własnościowymi sterownikami NVIDIA nie zdaje on egzaminu.

Poszukując rozwiązania tego problemu, natknąłem się na ciekawy projekt Piotra Jaroszyńskiego, który do tego celu zaprzęga architekturę CUDA.

Cudaram składa się z dwóch elementów - daemona cudaramd do rezerwowania pamięci VRAM oraz modułu jądra cudaram.ko udostępniającego zarezerwowaną jako urządzenie blokowe. Do działania musimy oczywiście posiadać oprogramowanie CUDA Toolkit

Kompilacja i instalacja

Pierwsze co musimy zrobić, to pobrać źródła cudaram z repozytorium GIT, a następnie zainstalować w systemie:

  1. $ git clone https://github.com/peper/cudaram.git
  2. $ cd cudaram
  3. $ ./bootstrap
  4. $ ./configure
  5. $ make
  6. $ make install
  7. $ depmod

Uruchomienie i przygotowanie

Teraz pozostaje nam tylko załadować odpowiedni moduł jądra i uruchomić deamona,  określając rozmiar pamięci dla naszego ramdysku. Dla przykładu posłużymy się obszarem 512MB.

  1. $ modprobe cudaram
  2. $ cudaramd 0 512

Stan pamięci VRAM przed i po uruchomieniu cudaramd

Kiedy mamy utworzony nasz ramdysk, konieczne jest jego sformatowanie i podmontowanie.

  1. $ mkfs.ext4 /dev/cudaram0
  2. $ mkdir /mnt/cudaram
  3. $ mount /dev/cudaram0 /mnt/cudaram

I praktycznie tyle... możemy cieszyć się dodatkowym ramdyskiem "z odzysku" :)

Testy - czyli jak szybko?

  1. $ dd if=/dev/shm/file.test of=/mnt/cudaram/file.test bs=1048576 count=200 conv=fdatasync
  2. 200+0 records in
  3. 200+0 records out
  4. 209715200 bytes (210 MB) copied, 0.194931 s, 1.1 GB/s
  1. $ dd if=/mnt/cudaram/file.test of=/dev/shm/file.test bs=1048576 count=200 conv=fdatasync
  2. 200+0 records in
  3. 200+0 records out
  4. 209715200 bytes (210 MB) copied, 0.0780657 s, 2.7 GB/s
  1. $ dd if=/dev/shm/file.test of=/dev/shm/file2.test bs=1048576 count=200 conv=fdatasync
  2. 200+0 records in
  3. 200+0 records out
  4. 209715200 bytes (210 MB) copied, 0.0775705 s, 2.7 GB/s
  1. $ dd if=/mnt/cudaram/file.test of=/mnt/cudaram/file2.test bs=1048576 count=200 conv=fdatasync
  2. 200+0 records in
  3. 200+0 records out
  4. 209715200 bytes (210 MB) copied, 0.187056 s, 1.1 GB/s

Testy wykazują, że ramdysk na karcie graficznej jest ponad dwukrotnie wolniejszy - jjednak nie przeszkadza to w wykorzystaniu go jako pamięci swap lub przestrzeni do szybkiego uruchamiania ulubionych aplikacji.

Skomentuj

Podziel się tym wpisem: Cudaram - ramdysk na karcie NVIDIA

5.00 / 001

Logitech Unifying pod Linuksem

Banner

Technologia Unifying to bardzo dobry pomysł firmy Logitech, która postanowiła ujednolicić odbiornik USB dla swoich urządzeń bezprzewodowych. Sprowadza się to do tego, że posiadając jedno lub więcej urządzeń (maksymalnie sześć) wykorzystujących tą technologię, nie musimy posiadać do nich osobnych odbiorników - oszczędzając tym samym porty USB. Jest to bardzo rozsądne i wygodne rozwiązanie, bowiem sam odbiornik jest miniaturowy, o którym bardzo szybko zapominamy, szczególnie jeśli wykorzystujemy do codziennej pracy laptopa.

Parowanie urządzeń zgodnych odbiornikiem Unifying

Chcąc mieć możliwość korzystania z jednego odbiornika przy więcej niż jednym urządzeniu, należy najpierw takie urządzenie sparować z odbiornikiem za pomocą specjalnego oprogramowania, dostarczonego przez producenta - niestety, jak to w naszym życiu bywa, o Linuksie zapomniano. Można to zrobić "na około" parując nowe urządzenie pod Windowsem (np. w wirtualnej maszynie lub zwykłej instalacji). My tego nie lubimy i poszukamy szybszego rozwiązania.

Jądro Linux 3.2 częściowo rozwiązuje problem

Przede wszystkim możemy poczekać na wydanie jądra w wersji 3.2, gdzie dodano pełną obsługę odbiorników Unifying (drivers/hid/hid-logitech-dj).

Device Drivers -> HID Devices -> Special HID Drivers

Moduł ten dodaje jedynie poprawną obsługę już sparowanych urządzeń i rozwiązuje problem podłączenia dwóch urządzeń tego samego typu, na przykład dwóch klawiatur. Moduł ten potrafi zatem rozdzielić dwie lub więcej klawiatur na wydzielone węzły /input/dev.

W starszych wersjach jądra <3.2 wszystkie klawiatury i myszy korzystające z tej technologii widoczne są jako pojedyncza warstwa HID - nie ma więc możliwości  rozdzielenia jednej klawiatury np. do wprowadzania danych, a na drugiej do gier (np. w konfiguracjach typu Home Theater PC). 

Zobaczmy co nam powie dmesg:

usb 5-1: new full-speed USB device number 2 using uhci_hcd
usb 5-1: New USB device found, idVendor=046d, idProduct=c52b
usb 5-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 5-1: Product: USB Receiver
usb 5-1: Manufacturer: Logitech
logitech-djreceiver 0003:046D:C52B.0003: hiddev0,hidraw0: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:1d.0-1/input2
input: Logitech Unifying Device. Wireless PID:1017 as /devices/pci0000:00/0000:00:1d.0/usb5/5-1/5-1:1.2/0003:046D:C52B.0003/input/input10
logitech-djdevice 0003:046D:C52B.0004: input,hidraw1: USB HID v1.11 Mouse [Logitech Unifying Device. Wireless PID:1017] on usb-0000:00:1d.0-1:1

Jak widzimy, zostało określone jedno urządzenie, które w moim przypadku stanowi mysz Logitech Anywhere MX. Nie odnaleziono klawiatury Wireless Illuminated Keyboard K800, ponieważ nie zostało ono jeszcze sparowane z odbiornikiem pochodzącym z zestawu z myszką.

Parowanie nowych urządzeń pod Linuksem?

No dobrze, a jak sparować nowe urządzenia? Przecież nie będziemy sprzęgali do tego zadania Windowsa! W tym celu możemy posłużyć się programem pairing-tool.c autostwa Benjamina Tissoiresa:

  1. /*
  2.  * Copyright 2011 Benjamin Tissoires <benjamin.tissoi...@gmail.com>
  3.  *
  4.  * This program is free software: you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation, either version 3 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16.  */
  17.  
  18. #include <linux/input.h>
  19. #include <linux/hidraw.h>
  20. #include <sys/ioctl.h>
  21. #include <fcntl.h>
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <errno.h>
  25.  
  26. #define USB_VENDOR_ID_LOGITECH                  (__u32)0x046d
  27. #define USB_DEVICE_ID_UNIFYING_RECEIVER         (__s16)0xc52b
  28. #define USB_DEVICE_ID_UNIFYING_RECEIVER_2       (__s16)0xc532
  29.  
  30. int main(int argc, char **argv)
  31. {
  32.         int fd;
  33.         int res;
  34.         struct hidraw_devinfo info;
  35.         char magic_sequence[] = {0x10, 0xFF, 0x80, 0xB2, 0x01, 0x00, 0x00};
  36.  
  37.         if (argc == 1) {
  38.                 errno = EINVAL;
  39.                 perror("No hidraw device given");
  40.                 return 1;
  41.         }
  42.  
  43.         /* Open the Device with non-blocking reads. */
  44.         fd = open(argv[1], O_RDWR|O_NONBLOCK);
  45.  
  46.         if (fd < 0) {
  47.                 perror("Unable to open device");
  48.                 return 1;
  49.         }
  50.  
  51.         /* Get Raw Info */
  52.         res = ioctl(fd, HIDIOCGRAWINFO, &info);
  53.         if (res < 0) {
  54.                 perror("error while getting info from device");
  55.         } else {
  56.                 if (info.bustype != BUS_USB ||
  57.                     info.vendor != USB_VENDOR_ID_LOGITECH ||
  58.                     (info.product != USB_DEVICE_ID_UNIFYING_RECEIVER &&
  59.                      info.product != USB_DEVICE_ID_UNIFYING_RECEIVER_2)) {
  60.                         errno = EPERM;
  61.                         perror("The given device is not a Logitech "
  62.                                 "Unifying Receiver");
  63.                         return 1;
  64.                 }
  65.         }
  66.  
  67.         /* Send the magic sequence to the Device */
  68.         res = write(fd, magic_sequence, sizeof(magic_sequence));
  69.         if (res < 0) {
  70.                 printf("Error: %d\n", errno);
  71.                 perror("write");
  72.         } else if (res == sizeof(magic_sequence)) {
  73.                 printf("The receiver is ready to pair a new device.\n"
  74.                 "Switch your device on to pair it.\n");
  75.         } else {
  76.                 errno = ENOMEM;
  77.                 printf("write: %d were written instead of %ld.\n", res,
  78.                         sizeof(magic_sequence));
  79.                 perror("write");
  80.         }
  81.         close(fd);
  82.         return 0;
  83. }

Wystarczy skompilować i uruchomić gotowy program, wskazując odpowiednią ścieżkę urządzenia hidraw:

  1. bash-4.1# gcc -o pairing_tool pairing_tool.c
  2. bash-4.1# ./pairing_tool /dev/hidraw2
  3. The receiver is ready to pair a new device.
  4. Switch your device on to pair it.

Odbiornik jest teraz gotowy do sparowania z nowym urządzeniem, które należy teraz włączyć. I tyle :) Rzućmy jeszcze raz okiem na wynik dmesg:

usb 5-1: new full-speed USB device number 2 using uhci_hcd
usb 5-1: New USB device found, idVendor=046d, idProduct=c52b
usb 5-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 5-1: Product: USB Receiver
usb 5-1: Manufacturer: Logitech
logitech-djreceiver 0003:046D:C52B.0003: hiddev0,hidraw0: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:1d.0-1/input2
input: Logitech Unifying Device. Wireless PID:1017 as /devices/pci0000:00/0000:00:1d.0/usb5/5-1/5-1:1.2/0003:046D:C52B.0003/input/input10
logitech-djdevice 0003:046D:C52B.0004: input,hidraw1: USB HID v1.11 Mouse [Logitech Unifying Device. Wireless PID:1017] on usb-0000:00:1d.0-1:1
input: Logitech Unifying Device. Wireless PID:2010 as /devices/pci0000:00/0000:00:1d.0/usb5/5-1/5-1:1.2/0003:046D:C52B.0003/input/input11
logitech-djdevice 0003:046D:C52B.0005: input,hidraw2: USB HID v1.11 Keyboard [Logitech Unifying Device. Wireless PID:2010] on usb-0000:00:1d.0-1:2

Jeszcze dla pewności wyniki polecenia xinput:

⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=13   [slave  pointer  (2)]
⎜   ↳ Logitech Unifying Device. Wireless PID:2010       id=11   [slave  pointer  (2)]
⎜   ↳ Logitech Unifying Device. Wireless PID:1017       id=10   [slave  pointer  (2)]
⎣ Virtual core keyboard                         id=3    [master keyboard (2)]

Co jeszcze?

Oczywiście, aby sparować nowe urządzenia nie potrzebujemy jądra 3.2. Program doskonale działa również z starszymi jego wersjami, gdyż służy jedynie do przygotowania odbiornika do parowania z nowym urządzeniem. Posiadanie wersji jądra 3.2 wiąże się jedynie z udogodnieniami, gdybyśmy chcieli posiadać więcej niż jedną klawiaturę lub myszkę z naciskiem na ich rozróżnienie w systemie.

Program nie pozwala jednak na usunięcie urządzenia z odbiornika. Ale to w sumie mało istotne, gdyż taka funkcja powinna zostać niedługo dopisana.

Skomentuj

Podziel się tym wpisem: Logitech Unifying pod Linuksem

5.00 / 001

Uruchamiamy OnLive pod Wine

Banner

Wciąż niewiele wiadomo w sprawie wypuszczenia natywnego klienta OnLive dla Linuksa, usługi która pozwoliłby na granie w popularne gry pod pingwinem. Wczoraj morsik doniósł, że jest to już możliwe z wykorzystaniem najnowszego Wine 1.3.27 oraz specjalnej łatki  dodającej obsługę części WinAPI - Raw Input.

Brak obsługi tego elementu skutecznie blokowała poprawne działanie klienta OnLive pod Wine, gdyż umożliwia on na zarządzanie komunikatami WM_INPUT pochodzącymi od podłączonych do komputera myszek, klawiatur i innych urządzeń sterujących.

Instalacja Wine 1.3.27 + patch

Oryginalną instrukcję jak skompilować Wine 1.3.27 z odpowiednią latką znadziecie tutaj. Dla leniwych tłumaczenie w pigułce poniżej. W odróżnieniu od oryginału posłużymy się wydaniem 1.3.27 zamiast klonowania repozytorium GIT.

  1. wget http://ibiblio.org/pub/linux/system/emulators/wine/wine-1.3.27.tar.bz2
  2. tar -xvjf wine-1.3.27.tar.bz2
  3. cd wine-1.3.27
  4. wget http://santyago.pl/files/wine_rawinput_8_8_2011.patch
  5. patch -p1 < wine_rawinput_8_8_2011.patch
  6. autoreconf && ./configure --prefix=/usr && make depend && make -j2
  7. make install

Instalacja klienta OnLive

  1. wget http://www.onlive.com/d/windows -O OnLive_Setup.exe
  2. wine OnLive_Setup.exe

Na koniec pozostaje już nam tylko uruchomienie i przyjemna (w zależności od posiadanego łącza) gra.

  1. wine ~/.wine/drive_c/Program\ Files/OnLive/OnLive.exe

8Mbit w sam raz?

Muszę przyznać, że jak na Wine i 8Mbit łącze da się całkiem przyjemnie pograć. Kto wie, czy natywny klient jest nam jeszcze potrzebny?

Skomentuj

Podziel się tym wpisem: Uruchamiamy OnLive pod Wine

5.00 / 001

Naprawiamy aktywator w KDE 4.7.0

Banner

Aktywatory to jedna z moich ulubionych cech, która zagościła wraz z wydaniem KDE 4.6. W kwestii przypomnienia - Aktywator to specjalna ikona umieszczona na pasku zadań, która znika w momencie uruchomienia interesującego nas programu i jednocześnie pojawiająca się, gdy dany program nie jest uruchomiony. Dzięki takiemu rozwiązaniu oszczędzamy cenne miejsce, pozwalając na umieszczenie większej ilości skrótów do ulubionych pozycji.

Niestety wraz z pojawieniem się najnowszego KDE 4.7.0 aktywatory przestały działać, a konkretnie nie pojawiają się ponownie po zamknięciu programu. Pomaga jednynie przelogowanie się do KDE. Przyznam się, że w głębi siebie wkurzałem się na taki stan rzeczy, który doporowadził do wypuszczenia w obieg błędu, który nie oszukujmy się - nie jest trudno zawuażalny. Na szczęście błąd już usunięto i wszystko wróci do normy wraz z wydaniem KDE 4.7.1. Jednak tym, którzy nie mogą się doczekać, przygotowałem zbiorczą łatkę dotyczącą tego problemu.

http://www.santyago.pl/files/kde-workspace-4.7.0-launcher.patch

Wystarczy tylko nanieść powyższą łatkę na pakiet kde-worspace-4.7.0 i przekompilować :)

Skomentuj

Podziel się tym wpisem: Naprawiamy aktywator w KDE 4.7.0

5.00 / 001

Sprawiedliwa kolejka odświeżania w PHP

Banner

Kolejki to bardzo fajna rzecz dopóki zasada jej działania opiera się na znanych i przetartych już wcześniej rozwiązaniach. Problem pojawia się, gdy istnieje potrzeba specyficznego jej zastosowania. Takim przykładem może być kolejka sprawiedliwego odświeżania (tak ją sobie roboczo nazwałem).

O co konkretnie chodzi?

Wyobraźmy sobie skrypt działający w tle, który ma za zadanie odświeżać co jakiś czas informacje konkretnego procesu. Musimy również zadbać, aby odświeżanie wszystkich zadań występowało w równych odstępach czasu -  powiedzmy co 15minut, niezależnie od ilości zadań w kolejce.

Sprawa pozornie wydaje się być prosta, ale jak o to zadbać, gdy wykonanie fragmentu programu odpowiedzialnego za aktualizację zadania nie ma ściśle określonego czasu lub kolejka jest na tyle długa bądź krótka, że kolejny cykl odświeżania nastąpi za wcześnie lub za późno. Reasumując, cykl odświezania może nastąpić dla niego po upływie zarówno 7 minut jak i 25 minut.

Przypadek idealny

Najbardziej optymalnym wariantem jest 15 zadań, które wykonują się równo jedną minutę. Wtedy nie ma najmniejszego problemu, gdyż każde z zadań zostanie wykonane co 15 minut.

Za dużo lub za mało zadań

Nie jest jednak nigdzie powiedziane, że zadań musi być dokładnie 15. Nawet zakładając, że każde z nich wykona się dokładnie w jedną minutę, kolejka zacznie powtarzać się za wcześnie lub za późno - nie gwarantując nam 15-minutowego cyklu odświeżania.

Łatwo zauważyć, że w przypadku trzynastu zadań pośpieszymy się z cyklem o dwie minuty, natomiast z szesnastoma zadaniami, każde z nich będzie miało jednominutowe opoźnienie.

Coś mnie zatrzymało / pogoniło

Sprawa jeszcze bardziej się komplikuje, gdy zadanie wykona się w czasie krótszym lub dłuższym niż deklarowana minuta. Nie dość, że pełny cykl nie zakończy się w wyznaczonych 15 minutach -  to każde z zadań może wykonać się w pełnym przebiegu wcześniej lub później. Totalny chaos!

Planowane zadania

Pierwsze co musimy zrobić, to wyznaczyć maksymalny czas, potrzebny na wykonanie pojedynczego zadania. Załóżmy, że jest to typowo 30 sekund. Oczywiście może zdarzyć się, że zadanie zostanie wykonane w czasie krótszym lub dłuższym. Dlatego dajmy sobie zapas w postaci kolejnych 30 sekund. Tak więc, dopuszczalny
przedział czasowy na pojedyńcze zadanie wyniesie 60 sekund.

Jeśli chcemy, aby pełny cykl wynosił 15 minut (900sekund), musimy obliczyć ile zadań możemy bezpiecznie wpuścić do naszej kolejki. Obliczając 900:60 wychodzi nam okrągłe 15 zadań w kolejce. Sprawa jest już nieco prostsza - każde zadanie musi zacząć się o pełnej minucie, niezależnie od tego, ile trwało poprzednie zadanie.

Obliczenie czasu do odczekania po wykonaniu zadania jest banalnie proste 60-(czas trwania zadania).  Sprawa nieco komplikuje się, gdy dane zadanie z jakiegoś powodu przekroczy limit jednej minuty. Cykl nie będzie trwał piętnastu minut, a kolejne zadania będą spoźnione względem zaplanowanych przedziałów.

Można temu zaradzić poprzez natychmiastowe wykonanie kolejnego zadania i skrócenie czasu oczekiwania na kolejne zadanie, niezależnie od tego, jak krócej ono trwało względem dopuszcalnych 60 sekund.

Analogicznie postępujemy, gdy krytyczne zadania następują zaraz po sobie, a czasy opóźnień sumują się.

Wszystko jasne - czas wprawić to w ruch

Stworzymy sobie testową, 30-sekundową kolejkę z maksymalnym czasem 5 sekund na pojedyńcze zadanie. Symulacją będzie funkcja randomSleep() zatrzymująca losowo działanie na czas od 1 do 6 sekund, aby sprawdzić ją również w warunkach przekorczenia dopuszczalnego czasu.

  1. <?php
  2.  
  3.     set_time_limit(0);
  4.  
  5.     require_once 'fairRefreshQueue.php';
  6.  
  7.     function randomSleep()
  8.     {
  9.         usleep((rand(1, 5) * 1000000) + (rand(0, 9) * 100000));
  10.     }
  11.  
  12.     // 30 sekundowa kolejka, maksymalny czas na zadanie 5 sekund
  13.     $timeQueue = new FairRefreshQueue(30, 5, true);
  14.    
  15.     for ($i = 1; $i <= $timeQueue->getMaxJobs(); $i++)
  16.     {
  17.         $timeQueue->addTask('randomSleep');
  18.     }
  19.    
  20.     $timeQueue->run();   
  21.  
  22. ?>

Wyniki dwóch przebiegów kolejki:

  • Start: Sekunda rozpoczęcia wykonywania zadania
  • Except: Planowany czas rozpoczęcia wykonywania zadania
  • Delay: Opóźnienie względem planowanego czasu rozpoczęcia wykonywania zadania
  • Work: Czas wykonywania zadania
  • Idle: Czas wolny
  • Exceeded: Czas przekroczony powyżej 5 sekund

Job #1, Start: 0.000s, Expect: 0.000s, Delay 0.000s, Work: 1.900s, Idle: 3.100s
Job #2, Start: 5.000s, Expect: 5.000s, Delay 0.000s, Work: 5.300s, Exceeded: 0.300s
Job #3, Start: 10.301s, Expect: 10.000s, Delay 0.301s, Work: 5.500s, Exceeded: 0.500s
Job #4, Start: 15.801s, Expect: 15.000s, Delay 0.801s, Work: 1.400s, Idle: 2.799s
Job #5, Start: 20.000s, Expect: 20.000s, Delay 0.000s, Work: 4.600s, Idle: 0.399s
Job #6, Start: 25.000s, Expect: 25.000s, Delay 0.000s, Work: 3.300s, Idle: 1.700s
Job #1, Start: 30.000s, Expect: 30.000s, Delay 0.000s, Work: 4.400s, Idle: 0.599s
Job #2, Start: 35.000s, Expect: 35.000s, Delay 0.000s, Work: 1.200s, Idle: 3.799s
Job #3, Start: 40.000s, Expect: 40.000s, Delay 0.000s, Work: 2.600s, Idle: 2.399s
Job #4, Start: 45.000s, Expect: 45.000s, Delay 0.000s, Work: 5.700s, Exceeded: 0.700s
Job #5, Start: 50.701s, Expect: 50.000s, Delay 0.701s, Work: 1.900s, Idle: 2.399s
Job #6, Start: 55.000s, Expect: 55.000s, Delay 0.000s, Work: 3.700s, Idle: 1.299s

Jak widać, drugi przebieg cyklu pomimo opóźnień rozpoczął się w planowanym terminie, a wszystkie opóźnienia zostały wyrównane kosztem wolnego czasu pozostałych zadań.

Zobaczmy jeszcze wariant zapchania kolejki, narzucając kolejno czasy:

1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 1, 1, 2 sekundy

Wyniki:

Job #1, Start: 0.000s, Expect: 0.000s, Delay 0.000s, Work: 1.000s, Idle: 4.000s
Job #2, Start: 5.000s, Expect: 5.000s, Delay 0.000s, Work: 2.000s, Idle: 2.999s
Job #3, Start: 10.000s, Expect: 10.000s, Delay 0.000s, Work: 3.000s, Idle: 1.999s
Job #4, Start: 15.000s, Expect: 15.000s, Delay 0.000s, Work: 4.000s, Idle: 0.999s
Job #5, Start: 20.000s, Expect: 20.000s, Delay 0.000s, Work: 5.000s, Exceeded: 0.000s
Job #6, Start: 25.001s, Expect: 25.000s, Delay 0.001s, Work: 6.000s, Exceeded: 1.000s
Job #1, Start: 31.001s, Expect: 30.000s, Delay 1.001s, Work: 7.000s, Exceeded: 2.000s
Job #2, Start: 38.001s, Expect: 35.000s, Delay 3.001s, Work: 8.000s, Exceeded: 3.000s
Job #3, Start: 46.002s, Expect: 40.000s, Delay 6.002s, Work: 7.000s, Exceeded: 2.000s
Job #4, Start: 53.002s, Expect: 45.000s, Delay 8.002s, Work: 6.000s, Exceeded: 1.000s
Job #5, Start: 59.002s, Expect: 50.000s, Delay 9.002s, Work: 5.000s, Exceeded: 0.000s
Job #6, Start: 64.003s, Expect: 55.000s, Delay 9.003s, Work: 4.000s, No idle
Job #1, Start: 68.003s, Expect: 60.000s, Delay 8.003s, Work: 3.000s, No idle
Job #2, Start: 71.003s, Expect: 65.000s, Delay 6.003s, Work: 2.000s, No idle
Job #3, Start: 73.004s, Expect: 70.000s, Delay 3.004s, Work: 1.000s, Idle: 0.996s
Job #4, Start: 75.000s, Expect: 75.000s, Delay 0.000s, Work: 1.000s, Idle: 4.000s
Job #5, Start: 80.000s, Expect: 80.000s, Delay 0.000s, Work: 1.000s, Idle: 4.000s
Job #6, Start: 85.000s, Expect: 85.000s, Delay 0.000s, Work: 2.000s, Idle: 2.999s

Zapychanie kolejki następuje wraz z 6 zadaniem, a opóźnienie nawarstwia się wraz z kolejnymi zadaniami. Kiedy jednak sytuacja się zmienia i pozostaje czas wolny, zostaje on wykorzystany do wyrównania kolejki do pierwotnego stanu.

Podsumowanie

Całkiem możliwe, że wynalazłem koło na nowo. Wychodzę jednak z założenia, że komuś może się ten opis przydać. Ja natomiast miałem wielką frajdę w rozgryzieniu tego problemu samodzielnie :)

Żrodełka do pobrania tutaj: fairrefreshqueue.tar.gz

Skomentuj

Podziel się tym wpisem: Sprawiedliwa kolejka odświeżania w PHP

Podstrony

Blog Fotografia Czytelnicy Kontakt Changelog Geolokalizacja TrackIP

Z prawej strony

  • 26 kwi 2012Paczki KDE 4.8.2 dla Slackware

    Dostępne są paczki KDE 4.8.2 dla Slackware 13.37. Źródła i binarki można pobarć z tego miejsca.

  • 29 wrz 2011Paczki KDE 4.6.5 dla Slackware

    Dostępne są paczki KDE 4.6.5 dla Slackware 13.37. Źródła i binarki można pobarć z tego miejsca.

  • 29 wrz 2011GNOME 3.2 już dostępny

    Informacje o wydaniu GNOME 3.2

Reklama

Ostatnie komentarze

Gravatar

Ekspertyza sądowa pamięci BS Sport

unfa / 10 maj 2012 / 11:33

7 dni temu.

Kryminał informatyczny - i to z życia wzięty oraz mający miejsce w polskich realiach! Cud miód! :D A poważniej: nie ...

Gravatar

Apple 10 lat za Microsoftem

Paweł / 09 maj 2012 / 19:13

8 dni temu.

Podchodziłbym do tego z rezerwą. Kiedyś cwaniaczki z Lamersky lab chciały nam wmówić, że potrzebujemy ich produktów na Linuksa. Może ...

Gravatar

Rozwój DreamDesktop

lucas / 03 maj 2012 / 18:48

14 dni temu.

@mentorious Jak to sobie wyobrażasz? I które GNOME masz na myśli? GNOME Shell, Unity, Cinamoon, Pantheon, Mate? Chyba lepiej wspierać ...

Gravatar

Rozwój DreamDesktop

mentorious / 30 kwi 2012 / 18:16

17 dni temu.

Pomysł i sam program jest genialny! Będzie to dało radę zastosować używając Gnome bez dociągania połowy zależności KDE?

Popularne wpisy (ostatnie 7 dni)

Kategorie wpisów

Nuta tygodnia

Nuta tygodnia #9

Poprzednie nuty

Facebook

GooglePlus

Lubię odwiedzać

Warte odnotowania

Software monitor

2012-05-12 : Kernel (3.x) 3.3.6 75,3 MB 2012-05-11 : Wine 1.5.4 19,3 MB 2012-04-15 : Apache 2.4.2 3,9 MB 2011-08-04 : Kernel (2.6) 2.6.39.4 72,6 MB

Czytelnicy online

  • Aktualna liczba czytelników : 9