Jak uruchomić program Java z precyzyjnie kontrolowanym czasem wykonania?

Jak wiem JVM przed uruchomieniem aplikacji Java przydziela do niej kawałek pamięci RAM, a ta pamięć może być kontrolowana przez użytkownika przed uruchomieniem. Ale jest inny problem, gdy uruchamiam aplikację ma inny czas wykonania za każdym razem.

Oto bardzo prosty przykład z pętlą for:

package timespent;

public class Main {

    public static void main(String[] args) {

        long startTime = System.nanoTime();

        int j = 0;

        for (int i = 0; i < 1.E6; i++) {
            j = i + 1;
        }

        long endTime = System.nanoTime();

        long duration = (endTime - startTime);

        System.out.println("duration = " + duration);
    }
}

Wyświetla różne wyniki:

duration = 5720542
duration = 7331307
duration = 7737946
duration = 6899173

Powiedzmy, że chcę, aby została wykonana dokładnie 10,000,000 nanosekund lub 10 milisekund.

Co ja chcesz?

Chcę, aby aplikacja java była wykonywana z dokładnym czasem wykonania.

Po co mi to?

Po uruchomieniu aplikacji chcę pokazać dokładny czas wykonania pozostałego w oknie uruchamiania aplikacji przed załadowaniem wszystkich komponentów.

Przypuszczam, że jest to rodzaj manipulacji procesorem i chciałem wiedzieć, czy jest to możliwe, czy nie.

Q1: czy jest to możliwe w Javie?
Q2: Jeśli nie jest to możliwe w Javie, to czy jest jakiś sposób osiągnięcia tego przez dostęp do natywnych metod systemu operacyjnego. np. poprzez nadanie priorytetu aplikacji Java czy coś innego?
Q3: a co powiesz na zapisanie stanu aplikacji do pliku i załadowanie go do pamięci?

Author: Paolo Forgia, 2017-11-09

7 answers

Istnieje wiele źródeł niepewności pomiaru czasu. I wszystkie te źródła nie tylko wpływają na twoje pomiary, to samo środowisko uruchomieniowe jest niepewne. Wśród źródeł niepewności są:

  • Wykorzystanie pamięci podręcznej (jakie części pamięci są buforowane w procesorze). Twoje dane mogą zostać usunięte z pamięci podręcznej przez procesor wykonujący zadanie w tle.

  • Umiejscowienie pamięci (czy pamięć jest bezpośrednio podłączona do wykonującego rdzeń PROCESORA?). To może ulec zmianie w czasie, ponieważ proces może zostać przeniesiony do innego rdzenia w dowolnym momencie.

  • Oprogramowanie przerywa (Twój system operacyjny uprzedza proces, aby uruchomić inny). Można go nieco złagodzić, uruchamiając na cichej maszynie, ale nie ma gwarancji, że nie zostanie przerwany.

  • Termiczne Dławienie (procesor decyduje, że jest zbyt gorący i ścisza jego prędkość zegara). Naprawdę niewiele możesz z tym zrobić, chyba że jesteś przygotowany do pracy na jakimś wbudowanym procesor o stałej prędkości zegara.

  • Przerwania sprzętowe(złącze sieciowe odebrało niektóre dane z innego komputera w Internecie). Nie masz wpływu na to, kiedy to uderzy.

  • Nieprzewidywalne opóźnienia (odczytywasz dane z dysku, ale najpierw dysk musi poczekać, aż dane dotrą poniżej głowicy odczytu). Może to następować po wzorcach, gdy powtarzasz dokładnie te same działania w kółko, ale po uzyskaniu niepowiązanego przerwanie sprzętowe, może to spowodować nieoczekiwane opóźnienie 1/7200 rpm * 60 s/min = 8.3 ms.

  • Garbage collection(pytasz o Javę, więc masz GC uruchomiony w tle). Nawet najlepsi, większość współczesnych śmieciarzy nie może w pełni uniknąć zatrzymania świata od czasu do czasu. A nawet jeśli nie zatrzymują świata, nadal działają w tle, wprowadzając hałas podczas pracy poprzez pamięć podręczną, rozmieszczenie pamięci i przerwy w oprogramowaniu.

To chyba najważniejsze źródła i mogą być inne. Chodzi o to, że Twój Proces jest nigdy sam na maszynie. O ile nie uruchamiasz bez systemu operacyjnego i nie wyłączasz wszystkich przerw sprzętowych, musisz po prostu żyć z faktem, że Twoje czasy uruchamiania będą się różnić w zależności od wykonania i po prostu nie ma sposobu, aby to naprawić.

 40
Author: cmaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-03 12:52:09

To po prostu niemożliwe. Po pierwsze, pomiar czasu w nanosekundach nie jest dokładny. Mam wrażenie, że [1]} Ten post dobrze to wyjaśnia.

Po drugie nie masz kontroli nad tym, jak procesor planuje wykonanie. Mogą istnieć inne zadania ograniczające czas procesora, co opóźnia wykonanie programu.

 16
Author: Jerome Reinländer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 07:41:16

Dokładny czas wykonania dowolnego kodu nie jest deterministyczny, ponieważ zależy od innych rzeczy, które Maszyna fizyczna wykonuje jednocześnie.

Nawet jeśli planowałeś, aby czas wykonania był "stały", śledząc znacznik czasu uruchamiania i planowany znacznik czasu zakończenia i uśpiając główny wątek przez czas między zakończeniem programu, to nadal będzie się różnić, dość duża ilość.

Kiedy i jak długo wątki wykonują lub czekają jest poza Kontrola programisty.

 9
Author: Bohemian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 07:36:13

[TL; DR] to jest bardzo trudne/niemożliwe.

Dłuższa odpowiedź Zobacz Planarity Testing by Path Addition PhD thesis-Benchmarking Methodology Chapter dla niektórych zagadnień, w tym:

  1. inne aplikacje posiadające zasoby. Tzn. brak wystarczającej ilości pamięci i system operacyjny musi strona aplikacji; lub kod działa wolniej, jak inna aplikacja jest współdzielenie procesora.
  2. rozdzielczość zegara - Twój kod będzie działał tak szybko, jak Twój procesor jest w stanie. Przenieś go na inny komputer, a twoje benchmarki mogą dać szalenie różne wyniki, więc nie Optymalizuj go tylko dla swojego systemu.
  3. Class loading - gdy JVM po raz pierwszy uruchomi kod, musi załadować klasy do pamięci (zazwyczaj z dysku) i przetworzyć kod bajtowy, aby pierwsze uruchomienie było znacznie wolniejsze niż kolejne.
  4. Kompilacja Just-In-Time - gdy JVM po raz pierwszy wczytuje kod bajtowy, uruchomi go w trybie czysto interpretowanym. Po uruchomieniu bloku kod bajtowy (tj. jedna funkcja w kodzie) wiele razy (powiedzmy 10 000) może skompilować tę funkcję do kodu natywnego. Kompilacja spowolni to wykonanie, ale kolejne wywołania będą szybsze, ponieważ będzie uruchamiać natywny, a nie interpretowany kod. Jednak nie jest to kompilacja jednorazowa i jeśli JVM zauważy, że pewne ścieżki wykonania w bloku są preferowane, może przekompilować kod bajtowy, aby spróbować zoptymalizować te ścieżki i może to spowodować wiele natywnych wersji kodu bajtowego, dopóki JVM nie ustabilizuje kodu względem swoich statystyk.
  5. Garbage Collector-czasami Twój kod zostanie przerwany, gdy Java wywoła garbage collector.

Więc jeśli chcesz przetestować swoją aplikację, aby zobaczyć, jak będzie działać optymalnie, to:

  • Zatrzymaj tyle innych aplikacji, ile możesz;
  • Uruchom kod wiele dziesiątek tysięcy razy;
  • Ignoruj pierwsze 10 000 - 20 000 egzekucji (do minimalizuje Ładowanie klas i kompilację JIT); oraz
  • Zignoruj iteracje, gdy nastąpi usuwanie śmieci(jest to trudniejsze do określenia niż się wydaje).

Daje wyobrażenie o optymalnej wydajności, ale optymalna i realna to dwie bardzo różne rzeczy.

 6
Author: MT0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 09:29:46

Jedynym sposobem, aby się do tego zbliżyć, byłoby użycie Java czasu rzeczywistego na systemie operacyjnym zaprojektowanym specjalnie do obsługi wykonywania w czasie rzeczywistym.

 5
Author: Matt McHenry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 19:07:46

Jak powiedzieli inni, nie jest możliwe poznanie dokładnego czasu pozostałego z powodu innych czynników wpływających na szybkość programu. Można jednak umieścić kamienie milowe i odwoływać się do poprzednich przebiegów, aby uzyskać pół-dokładny czas obliczony na podstawie wariancji w czasie rzeczywistym do tej pory ten przebieg w porównaniu do poprzednich przebiegów, jak to ma miejsce podczas kopiowania dużych katalogów plików na przykład w systemie Windows lub podczas pobierania dużych plików w Chrome.

Więc nie podajesz dokładnego problemu, ale powiedzmy jest to coś w rodzaju przetwarzania 100 000 operacji, które wymagają skontaktowania się z systemem 3rd party w Internecie i zwykle trwa ~15 minut, aby zakończyć. Możesz śledzić 1) czas rozpoczęcia, 2) oczekiwany czas zakończenia i 3) Część zakończona. Więc powiedz, kiedy jesteś 1/2 gotowe, można wziąć upłynął czas i powiedzieć, że to, jak długo pozostaje. Zasadniczo uzyskaj szybkość operacji na sekundę i podziel pozostałe operacje przez to, aby uzyskać liczbę sekund / align = "left" /
double speed = completedOperations / elapsedSeconds;
double remainingSeconds = remainingOperations / speed;
To może się jednak zmienić. Powiedzmy, że rozpoczniesz proces, a po uzyskaniu 1/4 W ciągu 5 minut rozpocznie się Backup offsite, nie tylko uderzając w dyski komputera, ale i twoje połączenie internetowe. Teraz rzeczy są przetwarzane z 1/10 prędkością. Twój szacowany czas zakończenia rozpocznie się 20 minut, a następnie 5 minut w nim będzie 15 minut. Jednak spowalnia w tym momencie, więc jesteś tylko 1/2 zrobione po 30 minutach, a pozostały czas w tym momencie będzie za 30 minut. Teraz powiedz, że kopie zapasowe są kompletne, w rzeczywistości zrobisz to w ciągu 10 minut, ale mówi, że pozostało 30 minut. Nie ma możliwości obejścia takiego problemu, który jest poza Twoją kontrolą. Możesz zrobić kilka rzeczy, żeby to złagodzić. Możesz chcieć przyspieszyć tylko ostatnie 30 sekund przetwarzania. To będzie najdokładniejsze, jeśli wszystko będzie kontynuowane z aktualną prędkością. Można rejestrować średnią prędkość w porach dnia, jeśli jest to problem. Możesz średnią całkowitą prędkość biegu i prędkość ostatniej minuty, jeśli Prędkość się zmienia.

Kolejną rzeczą, która może to odrzucić, jest wariancja danych. Na przykład, jeśli patrzysz na klientów i przetwarzasz ich na podstawie daty, w której zostali klientami, Twoje pierwsze 10 000 operacji może dotyczyć lojalnych klientów, którzy są z Tobą od lat i mają mnóstwo danych do przetworzenia, podczas gdy ostatnie 10 000 może być nowymi klientami z niewielką ilością danych, które przetwarzają szybciej. Mógłbyś następnie użyj podstawowej ilości danych zamiast liczby klientów...


Jednakże, jeśli chcesz być dokładny z jakiegoś powodu (przez większość czasu), możesz udawać za cenę czasu. Weź największy normalny czas pracy i po prostu Użyj czasu zajętego od początku, aby zapewnić postęp i czas pozostały. Następnie, gdy cała rzeczywista praca zostanie wykonana, umieść sleep() polecenie, aby przeczekać pozostały czas. Zawsze będzie szansa, że obciążenie systemu lub coś sprawi, że zajmie wyjątkowo długi, ale można wtedy zmienić swój maksymalny czas na tę nową wartość.

Czasy Twoich biegów są prawdopodobnie na jakiejś krzywej, im dłuższy czas, tym bardziej prawdopodobne, że każdy pojedynczy bieg zakończy się w tym czasie, ale wtedy więcej biegów będzie czekać na nic:

         #            ^
         #            |
        ###           |
        ###           |
       #####          R
      #######         U
    ###########       N
###################   S

Time-------------->

Przyznaję, że wydaje się to głupie, ale Twoja aplikacja będzie działać z różnymi prędkościami ze względu na zmienne, nad którymi nie możesz kontrolować, a jeśli bliski stały czas uruchamiania jest dla ciebie ważny to jedyny sposób.

 3
Author: Jason Goemaat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-04 16:52:28

To nie zadziała po twojemu. Zależy to od stanu systemu, na przykład od tego, ile zasobów systemowych pracuje w twoim programie.

Jak widzę, chcesz wyświetlić czas pozostały do otwarcia aplikacji. W takim przypadku Załóżmy, że dwóch użytkowników uruchamia Twój program na różnych maszynach, które mają różną strukturę rdzenia i częstotliwość taktowania ...

Ale mogę dać sugestię, możesz po prostu odczytać dane swojego programu i dostosować czas na tej podstawie, jak inne aplikacja do, co pokazuje ..% załadowany lub taki sam jak funkcja menedżera pobierania, która pokazuje ..% pobrano.

 1
Author: rajiv baghel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 12:13:21