Как найти время выполнения Java-программы

Обновлено: 21.11.2024

Java, будучи платформо-независимым языком программирования, не поддерживает одношаговую компиляцию. Вместо этого он включает двухэтапное выполнение, сначала через независимый от ОС компилятор; и, во-вторых, на виртуальной машине (JVM), которая настраивается для каждой операционной системы.

Два основных этапа объясняются ниже:

Принцип 1. Компиляция

Сначала исходный файл .java проходит через компилятор, который затем кодирует исходный код в машинно-независимую кодировку, известную как байт-код. Содержимое каждого класса, содержащегося в исходном файле, хранится в отдельном файле «.class». При преобразовании исходного кода в байт-код компилятор выполняет следующие шаги:

Шаг 1. Анализ. Считывает набор исходных файлов *.java и сопоставляет полученную последовательность токенов с узлами AST (абстрактного синтаксического дерева).

Шаг 2. Ввод. Вводит символы для определений в таблицу символов.

Шаг 3. Обработка аннотаций: по запросу обрабатывает аннотации, найденные в указанных единицах компиляции.

Шаг 4. Атрибут. Атрибуты синтаксических деревьев. Этот шаг включает в себя разрешение имен, проверку типов и свертывание констант.

Шаг 5. Поток. Выполняет анализ потока данных для деревьев из предыдущего шага. Сюда входят проверки назначений и доступности.

Шаг 6. Удаление сахара. Переписывает AST и удаляет часть синтаксического сахара.

Шаг 7. Генерация. Создание файлов .Class.

Принцип 2. Выполнение

Давайте обсудим все 3 этапа.

Этап 1. Загрузчик классов

Основной класс загружается в память, минуя свой файл .class в JVM, путем вызова последней. Все остальные классы, на которые есть ссылки в программе, загружаются через загрузчик классов.
Загрузчик классов, сам являющийся объектом, создает плоское пространство имен тел классов, на которые ссылается строковое имя. Определение метода представлено ниже на иллюстрации следующим образом:

Иллюстрация:

Первоначальный загрузчик классов встроен во все JVM и является загрузчиком классов по умолчанию. Непервичный загрузчик классов — это определяемый пользователем загрузчик классов, который можно закодировать, чтобы настроить процесс загрузки классов. Непервичный загрузчик классов, если он определен, предпочтительнее, чем загрузчик по умолчанию, для загрузки классов.

  • Переменные инициализируются перед использованием.
  • Вызовы методов соответствуют типам ссылок на объекты.
  • Правила доступа к закрытым данным и методам не нарушаются.
  • Доступ к локальным переменным относится к стеку среды выполнения.
  • Стек времени выполнения не переполняется.
  • Если какая-либо из вышеперечисленных проверок не пройдена, верификатор не разрешает загрузку класса.

Это последний этап, с которым сталкивается программа Java, и ее задача заключается в преобразовании загруженного байт-кода в машинный код. При использовании компилятора JIT аппаратное обеспечение может выполнять собственный код, в отличие от того, чтобы JVM неоднократно интерпретировала одну и ту же последовательность байт-кода и подвергалась штрафу в виде относительно длительного процесса трансляции. Это может привести к увеличению скорости выполнения, если только методы не будут выполняться реже.

Процесс может быть хорошо проиллюстрирован следующей диаграммой, приведенной выше, из которой мы пришли к выводу.

Вывод. Из-за двухэтапного процесса выполнения, описанного выше, программа Java не зависит от целевой операционной системы. Однако из-за того же время выполнения намного больше, чем у аналогичной программы, написанной в скомпилированной платформенно-зависимой программе.

Реализация:

Представьте себе, что простая программа печати написана где-то в локальном каталоге на машине.

Есть два способа измерить прошедшее время выполнения в Java: либо с помощью System. currentTimeinMillis() или с помощью System. наноВремя(). Эти два метода можно использовать для измерения прошедшего времени или времени выполнения между двумя вызовами метода или событием в Java.

Также нужно знать, как вы рассчитываете время выполнения?

1) Создайте цикл вокруг того, что нужно измерить, который выполняется 10, 100 или 1000 раз или более. Измерьте время выполнения с точностью до 10 мс. Затем разделите это время на количество выполнений цикла. Если цикл выполняется 1000 раз с тактовой частотой 10 мс, вы получаете разрешение цикла 10 мкс.

Кроме того, как вы считаете время в Java?

  1. долгий запуск = System. текущийВремяМиллис(); // проходит некоторое время long end = System.
  2. долгий запуск = System. наноВремя(); // проходит некоторое время long end = System.
  3. Секундомер watch = new StopWatch(); смотреть.
  4. Мгновенный запуск = Мгновенный.

Что такое время выполнения в C?

Среда выполнения или среда выполнения — это часть языковой реализации, которая выполняет код и присутствует во время выполнения; часть реализации времени компиляции называется средой перевода в стандарте C. Примеры: среда выполнения Java состоит из виртуальной машины и стандартной библиотеки.

Что такое прошедшее время?

Прошедшее время — это просто количество времени, которое проходит от начала события до его окончания. На этом уроке вы научитесь вычислять прошедшее время и узнаете, как его можно использовать в повседневной жизни.

Что такое время выполнения ЦП?

Время выполнения или процессорное время данной задачи определяется как время, затрачиваемое системой на выполнение этой задачи, включая время, затраченное на выполнение среды выполнения или системных служб от ее имени. Механизм, используемый для измерения времени выполнения, определяется реализацией.

Как PHP вычисляет время выполнения?

Чтобы проверить время выполнения фрагмента кода, вам необходимо: Сохранить текущее время с помощью time() или microtime() перед кодом, который вы хотите профилировать. После кода снова вызовите time() или microtime() и рассчитайте разницу от ранее сохраненного значения. Это время выполнения в секундах??

Как узнать время выполнения программы на C?

Как сравнить две даты в Java?

В Java две даты можно сравнить с помощью метода compareTo() интерфейса Comparable. Этот метод возвращает «0», если обе даты равны, возвращает значение «больше 0», если дата1 предшествует дате2, и возвращает значение «меньше 0», если дата1 предшествует дате2.

Как добавить отметку времени в Java?

импортировать java. утилиз. Дата; импортировать java. sql. Отметка времени; public static void main( String[] args ) Date date= new Date(); долгое время = дата. получить время(); Система. вне. println("Время в миллисекундах: " + time); Временная метка ts = новая временная метка (время); Система. вне. println("Текущая метка времени: " + ts);

Что такое секундомер в Java?

Используйте класс секундомера Guava. Объект, измеряющий прошедшее время в наносекундах. Полезно измерять прошедшее время с помощью этого класса вместо прямых вызовов System. Секундомер — более эффективная абстракция, потому что он предоставляет только эти относительные значения, а не абсолютные.

Как конвертировать миллисекунды в секунды в Java?

Программа Java для преобразования миллисекунд в минуты и секунды import java. утилиз. одновременно. общедоступный класс Миллисекунды <длинные миллисекунды = 1000000; // длинные минуты = (миллисекунды/1000)/60; длинные минуты = TimeUnit. МИЛЛИСЕКУНДЫ. // длинные секунды = (миллисекунды / 1000); длинные секунды = TimeUnit. МИЛЛИСЕКУНДЫ. format("%d миллисекунд = %d минут ", миллисекунды, минуты );

Как преобразовать наносекунды в секунды в Java?

Ну, можно просто разделить на 1 000 000 000: long elapsedTime = end - start; двойные секунды = (двойное) прошедшее время / 1_000_000_000. 0; Если вы используете TimeUnit для преобразования, вы получите результат как long, поэтому вы потеряете десятичную точность, но сохраните точность целого числа.

Создание трассировки среды выполнения Java с помощью TPTP

Следующие примечания были собраны, чтобы помочь вам начать профилирование с помощью проекта Eclipse Test and Performance Tools Project (TPTP). Рекомендуем сначала просмотреть эту страницу, а затем просмотреть документацию по TPTP.

Eclipse TPTP предоставляет набор инструментов для тестирования и профилирования приложений Java. Трассировка выполняется с помощью контроллера агентов (AC): он действует как посредник между отслеживаемым Java-приложением и рабочей средой Eclipse. Приложение Java запускается с помощью агента JVMTI/JVMPI (с параметром -Xrun ), который кодирует примитивную информацию о трассировке, предоставленную JVM, и пересылает результаты в AC.

Существует две формы AC: удаленный AC, длительный процесс и интегрированный AC, который по мере необходимости создается рабочей средой. IAC проще в использовании. В этих инструкциях будет использоваться IAC.

Если вы столкнетесь с трудностями, вам может помочь часть следующего. Самая последняя версия этих заметок доступна по адресу:

Примечание. Hyades — это кодовое название более ранних версий TPTP.

Как создать файл трассировки при запуске приложения:

Выберите «Выполнить» → «Профиль». . Это эквивалент профилирования диалоговым окнам «Выполнить» или «Отладка». Любые ранее определенные конфигурации запуска также должны отображаться здесь. Наиболее заметным отличием диалоговых окон «Выполнение» от «Отладка» является добавление вкладок «Монитор» и «Назначение».

Либо выберите существующую конфигурацию, либо создайте подходящую конфигурацию для своего приложения.

Выберите вкладку "Монитор". Разверните элемент "Профилирование Java" и включите "Анализ времени выполнения".

Выберите «Параметры редактирования», чтобы открыть мастер анализа времени выполнения. Выберите Показать графические сведения о потоке выполнения , а затем выберите Готово, чтобы закрыть мастер.

[Необязательно] TPTP устанавливает набор фильтров профилирования по умолчанию в зависимости от типа конфигурации. Это определяет набор классов и методов, которые необходимо удалить из трассировки, и может привести к значительному сокращению трассировки. Чтобы настроить фильтры, выберите «Профилирование Java» и нажмите кнопку «Изменить параметры». Дополнительную информацию см. в разделе «Указание критериев профилирования».

[Необязательно] По умолчанию профилирование начинается сразу после запуска приложения. Чтобы вместо этого включить ручное инициирование профилирования, выберите элемент « Профилирование Java » и нажмите кнопку «Изменить параметры», чтобы открыть мастер набора фильтров. Нажмите «Далее», чтобы открыть страницу «Ограничения». Отключите параметр Автоматически запускать мониторинг при запуске приложения. Мониторинг (профилирование) можно выборочно включить и приостановить с помощью контекстного меню монитора в представлении «Мониторы профилирования» в перспективе «Профилирование и ведение журнала». Нажмите Готово, чтобы вернуться к диалоговому окну профиля.

Выберите вкладку "Назначение". Выберите «Отправить данные профилирования в файл» и укажите файл. Обязательно указывайте полный путь, иначе не всегда понятно, куда будет записан файл.

Теперь вы сможете нажать кнопку "Профиль", чтобы начать профилирование.

Профилирование можно приостановить и возобновить с помощью представления «Мониторы профилирования».

При импорте набора данных профилирования для Ferret обязательно выберите Показать полные данные (графические сведения о потоке выполнения) в мастере импорта.

Дополнительные примечания по устранению неполадок:

Если вы столкнулись со сбоями JVM, попробуйте добавить -Xint к аргументам JVM. Это приводит к тому, что JVM отключает свой JIT-компилятор, но это приводит к значительному снижению производительности.

[Linux/Unix] Обратите внимание, что ошибка 150006 требует явной настройки DISPLAY в Unix на вкладке Environment.

Примечание. При использовании нестандартной перспективы вам может потребоваться явно добавить элементы меню профилирования: выполните «Окно» → «Настроить перспективу». , выберите Команды и отметьте набор команд профиля.

Как создать файл трассировки при запуске приложения:

Выберите «Выполнить» → «Профиль». . Это эквивалент профилирования диалоговым окнам «Выполнить» или «Отладка». Любые ранее определенные конфигурации запуска также должны отображаться здесь. Наиболее заметным отличием диалоговых окон «Выполнение» от «Отладка» является добавление вкладок «Монитор» и «Назначение».

Либо выберите существующую конфигурацию, либо создайте подходящую конфигурацию для своего приложения.

Выберите вкладку "Монитор". Разверните элемент «Профилирование Java — JRE 1.5 или новее» и выберите «Анализ времени выполнения».

Нажмите кнопку "Изменить параметры" и убедитесь, что выбран параметр "Показать графические сведения о потоке выполнения".

[Необязательно] TPTP устанавливает набор фильтров профилирования по умолчанию в зависимости от типа конфигурации. Это определяет набор классов и методов, которые необходимо удалить из трассировки, и может привести к значительному сокращению трассировки. Чтобы настроить фильтры, выберите «Профилирование Java» и нажмите кнопку «Изменить параметры». Дополнительную информацию см. в разделе «Указание критериев профилирования».

Выберите вкладку "Назначение". Выберите «Отправить данные профилирования в файл» и укажите файл. Обязательно указывайте полный путь, иначе не всегда понятно, куда будет записан файл.

Теперь вы сможете нажать кнопку "Профиль", чтобы начать профилирование.

Профилирование можно приостановить и возобновить с помощью представления «Мониторы профилирования».

При импорте набора данных профилирования для Ferret обязательно выберите Показать полные данные (графические сведения о потоке выполнения) в мастере импорта.

Дополнительные примечания по устранению неполадок:

Если вы столкнулись со сбоями JVM, попробуйте добавить -Xint к аргументам JVM. Это приводит к тому, что JVM отключает свой JIT-компилятор, но это приводит к значительному снижению производительности.

[Linux/Unix] Обратите внимание, что ошибка 150006 требует явной настройки DISPLAY в Unix на вкладке Environment. Предполагается, что это было исправлено в TPTP 4.4 (Европа).

Профилировщик Java до версии 1.5 поддерживает запуск профилирования вручную вместо автоматического запуска при запуске.

На вкладке «Монитор» выберите элемент «Профилирование Java — до JRE 1.5» и выберите «Параметры редактирования», чтобы открыть мастер «Изменить параметры профилирования».

Нажмите «Далее», чтобы открыть страницу «Ограничения», и снимите флажок «Автоматически запускать мониторинг при запуске приложения». Мониторинг (профилирование) можно выборочно включить и приостановить с помощью контекстного меню монитора в представлении «Мониторы профилирования» в перспективе «Профилирование и ведение журнала».

Нажмите «Готово», чтобы вернуться к диалоговому окну профиля. Выберите пункт «Анализ времени выполнения» и нажмите «Изменить параметры». Крайне важно включить параметр Показать графические сведения о потоке выполнения .

При использовании нестандартной перспективы вам может потребоваться явно добавить элементы меню профилирования: do Окно → Настроить перспективу. , выберите Команды и отметьте набор команд профиля.

Мы все хотели знать, как быстро работает фрагмент кода или алгоритм. Мы хотим рассчитать время работы кода либо для того, чтобы узнать его эффективность, либо для сравнения двух или более алгоритмов, чтобы выбрать лучший из них. Этот пост является частью серии постов, в которых объясняются подводные камни обычных способов измерения времени выполнения фрагмента кода на Java, почему это неправильный способ измерения времени выполнения/выполнения и правильный способ измерения времени выполнения. кода на Java.

Измерение времени выполнения

Вы написали код, который что-то делает, и хотите измерить время выполнения этого кода, чтобы определить его эффективность. У вас может быть два или более разных кода, выполняющих одну и ту же работу. Итак, вы измеряете время работы каждого кода, чтобы решить, какой из них лучше. Этот процесс определения времени выполнения называется сравнительным анализом.
У нас есть код для сортировки вставками, и мы хотели бы измерить время его выполнения. Сортировка вставками — это один из алгоритмов сортировки со средним и худшим временем выполнения O(n^2). В лучшем случае это O(n), и это происходит, когда ввод уже отсортирован. В худшем случае O(n^2) входные данные сортируются в обратном порядке.
У нас также есть код для быстрой сортировки. Его время работы составляет O(n log n) (лучшее, худшее и среднее).

Для остальной части обсуждения мы будем сортировать массив в порядке возрастания, а обратный порядок означает порядок убывания.

Алгоритмы сортировки

Код для вставки и быстрой сортировки размещается в классе как статические методы.

Очень наивный способ тестирования кода

Обычный способ, который я называю очень наивным, заключается в измерении времени работы с использованием подхода, основанного на часах. Мы бы измерили время (часы) в начале и время, когда выполнение метода/кода завершилось, и вычли бы время окончания из начала. Обычно для этого мы используем System.currentTimeMillis. Но использование System.nanoTime более точно, чем currentTimeMillis.

Типичный код теста выглядит так

Это дает время в наносекундах. Чтобы получить время в миллисекундах, мы должны разделить результат разницы на 100_000 (10 6 ).

В остальной части поста рассказывается о проблемах подхода и о том, почему этого нельзя делать для получения точных результатов.

Мы начинаем с создания списка случайных чисел. Затем мы запускаем нашу (очень) наивную логику бенчмарка в цикле. Затем мы расширим его, чтобы сравнить средний случай и наихудший случай сортировки вставками. Наконец, мы сравниваем сортировку вставками с сортировкой слиянием.

Построение нашего набора данных

Давайте создадим список из 10 000 чисел в качестве нашего набора данных. Я установил верхнюю границу (максимальное число) числа как 1 000 000 (1 миллион).

Измерение производительности в цикле

Давайте запустим тестовый код для измерения времени выполнения в цикле.

Причина, по которой мы копируем массив перед сортировкой, заключается в том, что наша сортировка вставками сортирует массив на месте, т. е. после того, как метод сортировки возвращает переданный массив, он будет располагаться в порядке возрастания (отсортирован). Это повлияет на измерение при последующих запусках. Следовательно, мы делаем копию входного массива перед каждым вызовом.

Это напечатает как (точный результат определенно будет варьироваться от прогона к прогону и от машины к машине)

Существует много расхождений в данных о времени. Время варьируется от 11 мс до максимум 41 мс. Кажется, он успокаивается ближе к концу, где время составляет около 11 мс.

Итак, что мы делаем, чтобы получить одно число в качестве времени выполнения или выполнения? Мы запускаем его в цикле, как указано выше (и, возможно, большее количество раз, скажем, 1000 или 10 000) и берем среднее значение. Это не дает нам правильного числа, так как мы также учитываем случайные зашумленные показания.

Давайте посмотрим на пару расширений, где шум очевиден.

Производительность сортировки вставками при обратной сортировке ввода

В этом случае мы вызываем сортировку выбором с перевернутым отсортированным массивом. Другими словами, мы моделируем наихудший вариант выполнения.

Это печатается как (все единицы измерения указаны в миллисекундах)

Мы печатаем среднее время выполнения дела, за которым следует время наихудшего случая. Как видно ранее, в цифрах есть некоторые расхождения и шум. Разница неравномерна (или близка к равномерности).

Кроме того, в некоторых случаях наихудший вариант меньше среднего (32, 23 и 47, 30). И это происходит для одного и того же набора данных (мы запускаем наше измерение в цикле для одного и того же массива). Но для большинства записей время в худшем случае > среднее время в случае. Это вторая форма шума в наших измерениях.

Сравнение сортировки вставками с быстрой сортировкой

Давайте сравним время выполнения сортировки вставками (среднее время выполнения n 2 ​​) с быстрой сортировкой (среднее время выполнения n log n).

Он печатает время выполнения сортировки вставками, за которой следует время выполнения быстрой сортировки (опять же, все единицы измерения указаны в миллисекундах).

Во-первых, мы видим отклонения или колебания во времени сортировки вставками.В большинстве случаев быстрая сортировка занимает ~0 мс. Но в некоторых случаях это занимает до 14 мс. Во-вторых, в некоторых случаях время быстрой сортировки превышает время сортировки вставками.

Проблемы с нашим очень наивным подходом

Выполнение эталонного теста с использованием часов или времени не дает правильных результатов. Я также имею в виду другие широко используемые подходы, такие как секундомер Google Guava и класс Instant в Java. Как было сказано ранее, мы обычно запускаем тесты в цикле и берем среднее значение. Шум вариаций наблюдаемых чисел связан со многими вещами, происходящими за кулисами JVM. Первый запуск кода занимает больше времени, чем следующий. JVM идентифицирует горячий метод и выполняет некоторые оптимизации. В этом также участвует сборка мусора (GC).

Кроме этого, некоторые вещи, которые мы делаем, такие как копирование входного массива и вывод результатов на экран, также могут сыграть свою роль.

Обзор

В этом посте мы рассмотрели наиболее распространенный ошибочный подход к измерению времени выполнения кода на Java. Мы начали с измерения/бенчмаркинга кода сортировки вставками. Мы последовали за ним, сравнив средний и худший случай. Наконец, мы сравнили сортировку вставками с быстрой сортировкой. Во всех случаях мы заметили отклонения в выводе и узнали, что такой метод измерения времени выполнения кода или бенчмаркинга неверен и на него нельзя полагаться.
В следующем посте мы улучшим этот весьма наивный подход. чтобы прийти к разумно звучащему методу сравнительного анализа. Оставайтесь с нами.

Читайте также: