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/null
uruchamiają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.