Co jest szybsze?

0

Czy szybsze jest wywołanie bramki procedury, wywołanie przerwania systemu operacyjnego czy:

  1. Pobranie numeru procedury do rejestru
  2. Pobranie adresu procedury do rejestru z tablicy o indeksie pobranym wcześniej numerze
  3. Wywołanie takiej procedury

Piszę, bo się zastanawiam nad wprowadzeniem maszyny wirtualnej do jądra pewnego systemu operacyjnego. Aplikacja by ładowała pod pewien adres adres i rozmiar bufora komend, następnie by wypełniała bufor komend. Jeżeli bufor komend byłby wypełniony do końca, to wywoływałaby funkcję systemu operacyjnego. Jeżeli aplikacji skończyłby się czas, jak również przy poprzednio wspomnianym wywołaniu, to system kopiowałby zawartość bufora do własnego bufora, wstrzymywał zadanie, przełączał zadania, a w momencie, gdy wszystkie zadania byłby wstrzymane, to wykonywałby bufory. Planuję też możliwość wykonywania pętli, więc wzrost szybkości powinien być znaczący.

0

Unix wykorzystuje do wywołań systemu INT 0x80, ale nie wiem czy dobrze przeanalizowałeś swój problem.
Jesteś pewien że przy obsłudze linii komend ważna jest szybkość wywołania?

0

Nie zrozumiałeś tematu. Nie chodzi o obsługę linii komend, a o obsługę wywołań systemowych. Zamiast wywoływać przerwanie Linuksa(int 86 chyba) za każdym razem, to możemy przekazać bufor poleceń jądru.

2

Przełączanie się między trybem jądra, a użytkownika długo trwa, więc lepiej go w miarę możliwości unikać. Niem wiem czy przerwanie od razu przenosi w tryb jądra, ale wydaje mi się, że tak.

Poza tym, znalazłem coś w Google po 5 sekundach szukania: http://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall

3

Zacznijmy od tego, że całkowity czas system calla to czas przejścia w tryb jądra + czas obsługi samego wywołania wewnątrz kernela. Założyłeś, że całkowity czas zostanie zdominowany przez pierwszy czynnik i dlatego warto go zoptymalizować. Jest to IMO założenie dość odważne. Czas przejścia w tryb jądra <= 100ns [1] co daje max. kilkaset cyklów zegara CPU. Serio chcesz to poprawiać? To może mieć sens dla najlżejszych wywołań typu gettid/getpid, które kernel jest w stanie obsłużyć w kilku instrukcjach języka C, ale NIE będzie miało sensu dla wywołań związanych np. z alokacją pamięci, forkowaniem (fork od kuchni: [2]), siecią.

Weźmy np. takiego send/recv, wg mojej wiedzy koszt takiego calla to ok ~1us, wierz mi tam jest cały ogrom rzeczy do zrobienia. Trzeba przepchnąć ramkę przez wszystkie 4 warstwy sieci, poobliczać checksumy, zwalidować adresy IP, wykonać routing, pozakładać locki, wrzucić do ring buffer-a NIC-a. To jak będziesz triggerował cały ten proces jest naprawdę nieistotne.
System calle są bolesne ze względu na sam koszt obsługi wewnątrz jądra a nie ze względu proces przejścia w tryb jądra.
Nie mówię że to co chcesz zrobić jest bez sensu, ale że bez porządnego researchu i benchmarkowania napracujesz się na darmo.

[1] http://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html
[2] http://students.mimuw.edu.pl/SO/Linux/Temat02/fork.html

3

Czas przejścia w tryb jądra <= 100ns [1] co daje max. kilkaset cyklów zegara CPU. Serio chcesz to poprawiać? To może mieć sens dla najlżejszych wywołań typu gettid/getpid, które kernel jest w stanie obsłużyć w kilku instrukcjach języka C, ale NIE będzie miało sensu dla wywołań związanych np. z alokacją pamięci, forkowaniem (fork od kuchni: [2]), siecią.

ZTCW to typowe stdliby minimalizują ilość odwołań do jądra przy alokacji pamięci. Alokują pamięć z wyprzedzeniem, np jednego megabajta i wszystkie małe alokacje są przetwarzane z użyciem tego bufora ze sporadycznymi odwołaniami do jądra, by zaalokować kolejny bufor, gdy wcześniejszy się przepełnia. Dealokacja też jest z opóźnieniem - dlatego np mimo zwolnienia całej zaalokowanej pamięci stdlib może trzymać sobie nadal kilka buforów.

Czas przejścia w tryb jądra <= 100ns [1]

W teście który pokazuje <= 100ns są takie uwagi:

My first idea was to make a cheap system call many times in a row, time how long it took, and compute the average time spent per syscall. The cheapest system call on Linux these days seems to be gettid. Turns out, this was a naive approach since system calls don't actually cause a full context switch anymore nowadays, the kernel can get away with a "mode switch" (go from user mode to kernel mode, then back to user mode). That's why when I ran my first test program, vmstat wouldn't show a noticeable increase in number of context switches.

Kolejne testy pokazują zgoła coś innego:

  • przełączanie się bez blokowania się na dany rdzeń trwa >= 3000 ns,
  • przełączenie się z blokowaniem na dany rdzeń trwa > 1000 ns,
  • powyższe testy prawie nic nie robiły oprócz przełączania, więc nie było kosztu przeładowania pamięci podręcznej,
  • przełączanie z przeładowaniem pamięci podręcznej bez blokowania się na dany rdzeń trwa jakieś 5000ns/ 1 KB przeładowanej pamięci,
  • przełączanie z przeładowaniem pamięci podręcznej z blokowaniem na dany rdzeń trwa > 2000 ns,
  • przeładowanie pamięci wynika z tego, że procedury rzeczywiście coś robią i korzystają ze struktur danych, które zajmują wiele kilobajtów pamięci,

int 80h (jak i każde inne przerwanie) ZTCW wymusza przełączenie w tryb jądra, więc tutaj system nie może "get away with", tylko przełączenie następuje na pewno i mamy tysiące nanosekund opóźnienia na jedno takie wywołanie.

0

W tym temacie:
http://stackoverflow.com/questions/12806584/what-is-better-int-0x80-or-syscall

Zanalazłem coś o VDSO. Mógłby ktoś mi przybliżyć, czym to jest? Jest to jakiś bufor, który eliminuje konieczność przełączania się w tryb jądra(przynajmniej tak zrozumiałem).

0

Masz racje Lachu. Dzięki VDSO nie ma konieczności przechodzenia w tryb jądra (w 90% przypadków).

0

A jak to działa? Być może wymyśliłem ponownie koło.

0

Przeczytałem stronę z poniższym adresem, ale jako u mnie z angielskim kiepsko, to nadal nie rozumiem o co chodzi.
http://man7.org/linux/man-pages/man7/vdso.7.html

Wydaje się, że te całe VDSO to po prostu cache na wyniki wywołania, ale jest to obszar pamięci dostępny jednocześnie dla procesów, jak i jądra, więc sam już nie wiem.

1

Nie wgryzałem się, ale wydaje mi się że VDSO to obszar pamięci służący do dwustronnej komunikacji. A więc nie tylko pamięć podręczna na wyniki wywołań, ale także kolejka żądań do jądra. Wtedy by to miało dla mnie sens. Ale mogę się mylić.

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