Program jest ZNACZNIE wolniejszy, gdy jest używany z TTY


4

Mam więc program napisany w C ++.

Może mi powiedzieć, ile czasu zajęło wykonanie wszystkich obliczeń, i wykonuje wiele dość ciężkich obliczeń wielowątkowych.

Właśnie zauważyłem, że jeśli uruchomię program na tej samej maszynie, wykonanie wszystkich obliczeń zajmie około 20-21 sekund, jeśli uruchomię je z TTY, i tylko około 0,2 sekundy, jeśli uruchomię go z terminala GNOME.

Co to powoduje? To dosłownie ten sam plik na tym samym komputerze.


Co rozumiesz przez CLI (wiem, co to oznacza, mam na myśli, jak go uruchamiasz, jeśli nie z terminala)? Domyślam się, że uruchamiająca się powłoka ma pewne problemy - być może nie jest zoptymalizowana pod kątem wielowątkowości.
Darren

rzeczy, które pojawiają się, gdy naciskam CTRL + ALT + F1
Mac B

1
OK, to się nazywa TTY. Mogą to być różne domyślne powłoki (echo $ SHELL).
Darren,

Odpowiedzi:


4

Niektóre teorie tła

Cóż, zarówno to, z czym pracujesz po CTRL+ ALT+, jak F1i GNOME Terminal, to różne implementacje tej samej koncepcji: emulowanie tak zwanego terminalu pełnoekranowego.

To pierwsze nazywa się w Linuksie terminalem wirtualnym (VT) lub zwykle „konsolą”. Korzysta ze specjalnego trybu wideo „tylko tekst”, który jest nadal zapewniany przez sprzętowe karty graficzne na platformach zgodnych z architekturą x86 (tj. Tych z „IBM PC”). Ten ostatni jest aplikacją GUI.

Obie zapewniają aplikacjom działającym z ich pomocą zestaw udogodnień, których aplikacja oczekuje od „urządzenia końcowego” (więcej szczegółów i dalsze wskazówki - tutaj ).

Problem na wyciągnięcie ręki

OK, przejdźmy teraz do postrzeganej powolności.

Jestem pewien, że sedno twojego problemu polega na tym, że twój program wykonuje tak zwane „blokowanie” I / O. Oznacza to, że za każdym razem, gdy robisz coś takiego

std::cout << "Hello, world" << endl;

w twoim kodzie najpierw uruchamia się kod standardowej biblioteki C ++ połączonej z twoją aplikacją i obsługuje wysyłanie rzeczy wysłanych do wskazanego strumienia.

Po pewnym przetworzeniu (i najczęściej buforowaniu) dane te muszą faktycznie opuścić działający program i uzyskać dane wyjściowe na dowolny nośnik, na który wysyłane są programy. W Linuksie (i innych systemach kompatybilnych z Uniksem) wymaga to wywołania do jądra - poprzez dedykowane wywołanie systemowe (lub w skrócie syscall ) write().

Zatem stdlib w C ++ ostatecznie wykonuje to wywołanie systemowe, write()a następnie czeka na jego zakończenie - to znaczy, że jądro powie „OK, odbiorca danych powiedział, że go pozyskał”.

Jak można wywnioskować, odbiornikiem danych, które wyprowadza Twój program, jest terminal (emulator), na którym działa Twój program - Linux VT lub instancja GNOME Terminal w twoich testach. (Pełny obraz jest bardziej skomplikowany, ponieważ jądro nie wyśle ​​danych bezpośrednio do działającego emulatora terminala, ale nie komplikujmy opisu).

A zatem szybkość, z jaką write()syscall się kończy, zależy w dużej mierze od tego, jak szybko odbiorca danych go obsługuje! W twoim przypadku GNOME Terminal po prostu robi to znacznie szybciej.

Uważam, że różnica polega na tym, że sterownik VT sumiennie renderuje wszystkie przesyłane do niego dane, przewija je itp., Podczas gdy GNOME Terminal optymalizuje impulsy przychodzących danych, wyświetlając tylko jego tylną część (cokolwiek pasuje do wielkości ekranu terminala) i umieszcza spoczywają w tak zwanym „buforze przewijania”, który ma większość emulatorów terminali GUI.

Na wynos do zrobienia

Kluczową rzeczą, którą należy to odrzucić, jest to, że gdy tylko program wykona dowolne operacje wejścia / wyjścia wraz z obliczeniami i zmierzysz prędkość obliczeń programu za pomocą timera „zegara ściennego”, zazwyczaj możesz dobrze zmierzyć szybkość tego wejścia / wyjścia O, nie szybkość obliczeń.

Należy zauważyć, że I / O jest trudne: Twój proces może być wywłaszczony (zatrzymany z jego zasobów przekazanych do innego procesu) przez system operacyjny w każdej chwili jest to około czekać na jakiś I / O zasobów stanie się dostępny do pisania, takich jak dysk twardy .

Tak więc pewnym sposobem pomiaru „surowej” wydajności obliczeń jest posiadanie pewnej ułatwienia w programie, aby wyłączyć wszystkie operacje we / wy. Jeśli nie jest to możliwe lub byłoby zbyt brzydkie do wdrożenia, przynajmniej spróbuj skierować wszystkie dane wyjściowe do tak zwanego „zerowego urządzenia”, /dev/nulluruchamiając program jak

$ ./program >/dev/null

Urządzenie zerowe po prostu odrzuca wszystkie przekazane do niego dane. Więc tak, wciąż każda runda we / wy wykonywana przez stdlib C ++ uderzy w jądro, ale przynajmniej będziesz mieć prawie stałą (i prawie natychmiastową) prędkość pisania.

Jeśli potrzebujesz zarówno miar, jak i wygenerowanych danych, rozważ utworzenie tak zwanego dysku RAM i przekierowanie danych wyjściowych do pliku tam zlokalizowanego.

Jeszcze jeden pomiar: zwróć uwagę, że nawet na pozornie bezczynnym systemie z podstawowym systemem operacyjnym (takim jak Ubuntu lub cokolwiek innego), procesor nigdy nie śpi - zawsze w tle wykonywane są pewne zadania. Oznacza to, że pomiar wydajności obliczeń nawet bez żadnego We / Wy lub z rodzajem „wyłączonych” We / Wy (jak wyjaśniono powyżej) nadal będzie generował różne wyniki dla każdego uruchomienia.

Aby to zrekompensować, dobry test porównawczy oznacza przeprowadzenie obliczeń z tymi samymi danymi wejściowymi kilka tysięcy razy i uśrednienie wyników na podstawie liczby przebiegów.


1
Nie wiedziałem, że konsola Linuksa działa tak wolno. OP zgłasza 100-krotną różnicę, zmierzyłem współczynnik prawie 200 (z nowszym i szybszym terminalem gnome), używając mojego ulubionego pliku testowego (42 MB, 660 tys. Linii kolorowego wyjścia „ls-lR”): terminal gnome 3,8s vs konsola 11m56s. Jeśli przełączę się na inny VT iz powrotem, konsola kończy się w 2 sekundy. Wąskim gardłem jest najwyraźniej jądro rozmawiające ze sterownikiem wideo.
egmont
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.