Дипломный проект в рамках магистерской диссертации по направлению DevTools (2025) Тема: "Сравнительное тестирование производительности реализаций JVM с помощью методов мутационного фаззинга"
JVM Performance Fuzzer - инструмент для автоматизированного поиска различий в производительности между разными реализациями Java Virtual Machine (OpenJDK, Oracle JVM, GraalVM и др.) с помощью методов мутационного фаззинга байткода.
Инструмент генерирует функционально эквивалентные варианты программ на Java, которые теоретически должны иметь одинаковую производительность на всех JVM, но на практике могут выявлять существенные различия из-за особенностей реализации, JIT-оптимизаций и других факторов.
- Автоматизированное выявление аномалий производительности между различными JVM
- Обнаружение потенциальных багов производительности в конкретных реализациях JVM
- Создание тестовых сценариев, демонстрирующих различия в производительности
- Предоставление данных для последующего анализа причин расхождений
Проект использует модификацию Java-программ на уровне байткода с сохранением функциональной эквивалентности:
- Функциональная стабильность: мутации сохраняют валидность байткода и возможность его выполнения на разных JVM
- Байткод-ориентированные мутации: изменения программы направлены на исследование различий в обработке байткода между JVM, а не на сохранение семантики
- Разнообразие мутаций: 10+ стратегий мутаций для тестирования различных аспектов JVM
- Адаптивность: фаззер адаптивно выбирает наиболее эффективные стратегии мутаций
Подробнее об архитектуре фаззера
В проекте описана оригинальная модель отбора сидов для мутации, сочетающая два параметра:
- Энергия - динамический ресурс сида, расходуемый при каждом использовании
- Ценность - статическая метрика ценности сида, вычисляемая на основе аномалий
Данная модель обеспечивает эффективный баланс между исследованием нового пространства мутаций и углублением в перспективные направления.
Подробнее о модели отбора сидов
Фаззер реализует двухуровневую систему для измерения и верификации аномалий:
- Двухуровневые измерения - быстрые для эволюции сидов и подробные для верификации аномалий
- Двухэтапная верификация - с разными порогами значимости на разных этапах
- Периодическая верификация - проверка наиболее перспективных сидов для исключения ложных срабатываний
Подробнее о системе измерения и верификации
- Оборачивание блоков кода в циклы
- Инвертирование условий ветвлений
- Добавление "мертвого кода"
- Операции упаковки/распаковки примитивов
- Оборачивание операторов в условные конструкции
- Добавление обработки исключений
- Вставка switch-конструкций
- Перемешивание порядка независимых операторов
- Добавление избыточных вычислений
- Блокировка свертки констант
- Вставка избыточных проверок на null
- Инвертирование направления циклов
- Использование JMH (Java Microbenchmark Harness) для точных измерений
- Отслеживание времени выполнения и потребления памяти
- Обнаружение четырех типов аномалий: время, память, таймауты, ошибки
- Двухэтапная верификация аномалий для исключения ложных срабатываний
- Анализ JIT-компиляции для выявления причин различий в производительности
- Генерация подробных отчетов с информацией о JIT-оптимизациях
- Сохранение оригинальных JMH-отчетов для каждой JVM для последующего глубокого анализа
- Модульная структура, позволяющая легко расширять функциональность
- Мощная система формирования и фильтрации мутаций
- Детальное отслеживание истории мутаций для анализа эффективных цепочек
- Автоматическое сохранение подтвержденных аномалий для дальнейшего исследования
- Java 11+ (рекомендуется Java 17)
- Gradle 7.0+
- Достаточно оперативной памяти (рекомендуется от 4GB)
- Тестируемые JVM (OpenJDK, Oracle JVM, GraalVM и т.д.)
git clone https://github.com/donebd/jvm-performance-fuzzer.git
cd jvm-performance-fuzzer
./gradlew build./gradlew run --args="--help"Фаззер поддерживает гибкий запуск с CLI-параметрами.
Все параметры можно посмотреть через --help.
| Аргумент | Описание | Пример значения | Значение по умолчанию |
|---|---|---|---|
-j, --jvms |
Список тестируемых JVM через запятую (hotspot, graalvm, openj9, axiom) |
hotspot,graalvm,openj9 |
Все поддерживаемые JVM |
-s, --seedsDir |
Путь к директории с начальными сидами (Java-файлы) | src/test/resources/InitialSeedExamples |
src/test/resources/InitialSeedExamples |
-n, --iterations |
Максимальное число итераций фаззинга | 50000 |
1000 |
-m, --mutation-strategies |
Стратегии мутаций через запятую (список поддерживается через --help) |
LOOP,BRANCH,BOXING |
Все стратегии |
--enable-jit-analysis |
Включить анализ JIT-логов | (флаг, true/false) | false |
-a, --anomaliesDir |
Папка для сохранения обнаруженных аномалий | report |
anomalies |
Параметр --seeds (или коротко -s) указывает путь к директории с исходными сидами для фаззинга.
Важно: Фаззер автоматически будет искать в этой директории все файлы с расширением .java. Для каждого такого файла будет сгенерирован отдельный стартовый сид (по имени файла без расширения).
- Если параметр не указан, используется дефолтная папка с заранее подобранными бенчмарками.
- Если указана другая директория — фаззер построит пул сидов по всем
.java-файлам внутри неё.
Требования к структуре сидов
Файлы сидов должны быть валидными Java-классами (или тестами), подходящими для загрузки в JVM.
Ожидается, что:
- Каждый файл содержит ровно один
public-класс с именем, совпадающим с именем файла. - Класс реализует простой и компактный бенчмарк, аналогичный примерам из директории
src/test/resources/InitialSeedExamples. - Рекомендуется: за основу брать структуру из существующих примеров сидов — там минимально необходимый шаблон класса для корректной работы фаззера.
Пример структуры сида:
package benchmark;
public class MyBenchClass {
public void run() {
// Код бенчмарка
}
}См. больше примеров в папке
src/test/resources/InitialSeedExamplesв проекте.
./gradlew run --args="-j hotspot,graalvm -n 5000 -m LOOP,BOXING -s src/test/resources/InitialSeedExamples -a ./report"- Запуск на HotSpot и GraalVM
- 5000 итераций
- Мутации только циклов и boxing/unboxing
- Сиды из папки
InitialSeedExamples - Аномалии сохраняются в папку
./report
Фаззер поддерживает не только запуск с помощью аргументов командной строки, но и полную ручную настройку из кода. Вы можете напрямую редактировать параметры запуска, список используемых JVM, стратегии мутаций, директории сидов и любые другие настройки внутри функции main или соответствующих компонентов.
Для полной изоляции окружения и запуска фаззера "в один клик" рекомендуется использовать Docker.
В проекте уже есть готовый Dockerfile, который:
- Поддерживает HotSpot, GraalVM и OpenJ9 внутри одного контейнера (см. пути в
jvm_config.json) - Позволяет собирать и запускать фаззер без предварительной установки JVM/Gradle/Kotlin на вашей машине
docker build -t jvm-fuzzer .(для передачи сидов, получения аномалий и т.д.)
docker run --rm -v "$PWD":/app jvm-fuzzer \
-j hotspot,graalvm,openj9 \
-n 2000 \
-s /app/src/test/resources/InitialSeedExamples \
-a /app/anomalies-v "$PWD":/app— пробрасывает весь проект внутрь контейнера (можно указывать другую директорию с сидами и папку для аномалий)- Все параметры CLI работают точно так же, как при запуске локально
docker run --rm -v "$PWD":/app jvm-fuzzer \
./gradlew run --args="ваши параметры"- Это позволяет запускать любые ваши gradle-таски (например,
build,testи т.п.) прямо в Docker
./gradlew buildDockerImage
./gradlew runDockerContainer
./gradlew stopDockerContainer- Можно управлять сборкой образа и запуском контейнера с помощью gradle-команд
- После запуска, аномалии и отчёты будут лежать в
anomalies/(или папке, указанной через-a) - Для корректной работы с кастомными сидами — просто пробрасывайте нужные директории через
-vи указывайте путь через-s
После выполнения фаззинга результаты сохраняются в структурированном виде:
report/
├── seed_anomaly_TIME_dev85pct_iter_123_8a7b2c3d/
│ ├── seed_info.json # Общая информация о сиде
│ ├── bytecode/ # Мутированный байткод
│ ├── jmh_reports/ # Исходные JMH-отчеты для каждой JVM
│ │ ├── jmh_time_GraalVM.json
│ │ └── jmh_time_HotSpotJvm.json
│ ├── anomalies/ # Данные об аномалиях
│ │ ├── anomaly_0_time_dev85pct.json
│ │ └── jit_analysis/ # Анализ JIT-компиляции
│ │ ├── jit_report_0.md # Человекочитаемый отчет
│ │ └── jit_details_0.json # Детальные данные
└── seed_anomaly_MEMORY_dev42pct_iter_456_9e8f7d6c/
...
Пример обнаруженной аномалии времени выполнения между OpenJDK и GraalVM:
{
"anomalyType": "TIME",
"fasterJvms": [{"jvmName": "GraalVM", "metrics": {...}}],
"slowerJvms": [{"jvmName": "HotSpotJvm", "metrics": {...}}],
"averageDeviation": 85.7,
"maxDeviation": 92.3,
"minDeviation": 79.2,
"pairwiseDeviations": {
"HotSpotJvmExecutor": {
"GraalVmExecutor": 85.7
}
},
"description": "Группа JVM (HotSpotJvmExecutor) медленнее по показателю времени выполнения на 85.7% по сравнению с группой (GraalVmExecutor)",
"interestingnessScore": 8.5773279339335733,
"exitCodes": {},
"errorDetails": {},
"jitRelatedProbability": 0.73
}Описание известных, а также уникальных проблем производительности, выявленных фаззером, можно найти здесь:
Документация по найденным аномалиям
Ниже представлена структура проекта, которая помогает понять организацию исходного кода и расположение ключевых компонентов системы:
src/
├── main/
│ ├── kotlin/
│ │ ├── core/ # Ядро фаззера
│ │ │ ├── mutation/ # Система мутаций
│ │ │ └── seed/ # Управление сидами
│ │ └── infrastructure/ # Инфраструктурные компоненты
│ │ ├── jvm/ # Запуск и управление JVM
│ │ ├── jit/ # Анализ JIT-компиляции
│ │ ├── performance/ # Измерение и анализ производительности
│ │ └── translator/ # Работа с байткодом и Jimple
│ └── resources/
│ └── initial-seeds/ # Начальные сиды для фаззинга
├── test/ # Тесты
└── documentation/ # Подробная документация
├── EnergyInterestingnessModel.md # Модель отбора сидов
├── FuzzerArchitecture.md # Архитектура фаззера
├── JitAnalyze.md # Система анализа JIT-компиляции
└── MeasurementAndVerificationSystem.md # Система измерения и верификации
- Разработана оригинальная энергетическо-ценностная модель эволюции сидов
- Предложены новые методы мутационного фаззинга, специализированные для сравнения JVM
- Реализован автоматизированный подход к выявлению багов производительности в JVM
- Разработана система анализа и сопоставления JIT-компиляции между различными JVM
- Выявление проблем производительности в популярных реализациях JVM
- Создание тестовых сценариев для валидации оптимизаций
- Помощь разработчикам высоконагруженных Java-приложений в выборе оптимальной JVM
- Детальный анализ различий в JIT-компиляции для понимания причин расхождений в производительности
Проект распространяется под лицензией MIT. Подробности в файле LICENSE.