This repository was archived by the owner on Jan 26, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Full Comprehensive Comparison Tests #9
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
5cb33c9
Update .gitignore
expanded-for-real 63313e4
initial commit for imprint-java
dd4fdbc
initial commit for imprint-java
expanded-for-real bce1d13
Add GitHub Actions CI workflow for automated testing
f5d90b5
Merge remote-tracking branch 'origin/dev' into dev
72c468f
Update GitHub Actions workflow to use upload-artifact@v4
468d682
Add Gradle wrapper validation to CI workflow
cf05b13
Fix gitignore to include gradle-wrapper.jar for CI
d0d7983
Force add gradle-wrapper.jar to repository
f2cdd1b
Update wrapper validation action to v3
57c8249
Fix Javadoc syntax errors and disable strict Javadoc checking
edb3057
Add JMH benchmark .bat and .sh for full suite benchmarking and perfor…
2853e3f
fix map serialization error in benchmark test and streamline ci file …
3a5a113
Add execute permissions back for gradlew in CI
50a288b
Add some more string based performance benchmarks and try to make str…
ea1c4c4
Merge pull request #2 from imprint-serde/faster-strings
expanded-for-real 43cab28
second main commit to address initial commits
expanded-for-real fdb8a56
additional cleanup to address concerns in https://github.com/imprint-…
2e56688
minor style fixes
9353388
minor style fixes again
09d0377
minor style fixes on benchmark tests and supress unused
6209bb1
minor reordering
ace7c67
Merge branch 'main' into dev
12d2823
Merge Comparisons into dev branch (#8)
expanded-for-real 2834dbb
Merge remote-tracking branch 'origin/main' into dev
83ed961
minor cleanup
a605b65
minor cleanup
aacddeb
minor cleanup
3bf81ad
Actually fixes offsets and read Byte Values for Maps and Arrays even …
7eaa6e9
change CI file to use JMH plugin to respect iteration and warmup valu…
32640cd
ok plugin didn't work apparently so reverting that and just reducing …
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,30 +15,250 @@ jobs: | |
| java-version: [11, 17, 21] | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK ${{ matrix.java-version }} | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: ${{ matrix.java-version }} | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Gradle dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| ~/.gradle/caches | ||
| ~/.gradle/wrapper | ||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-gradle- | ||
|
|
||
| - name: Make gradlew executable | ||
| run: chmod +x ./gradlew | ||
|
|
||
| - name: Run tests | ||
| run: ./gradlew test | ||
|
|
||
| - name: Run build | ||
| run: ./gradlew build | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK ${{ matrix.java-version }} | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: ${{ matrix.java-version }} | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Gradle dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| ~/.gradle/caches | ||
| ~/.gradle/wrapper | ||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-gradle- | ||
|
|
||
| - name: Make gradlew executable | ||
| run: chmod +x ./gradlew | ||
|
|
||
| - name: Run tests | ||
| run: ./gradlew test | ||
|
|
||
| - name: Run build | ||
| run: ./gradlew build | ||
|
|
||
| benchmark: | ||
| runs-on: ubuntu-latest | ||
| needs: test | ||
| # Add explicit permissions for commenting on PRs | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| issues: write | ||
| # Only run benchmarks on main branch pushes and PRs to main to avoid excessive CI time | ||
| if: github.ref == 'refs/heads/main' || github.base_ref == 'main' | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK 11 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '11' | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Gradle dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| ~/.gradle/caches | ||
| ~/.gradle/wrapper | ||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-gradle- | ||
|
|
||
| - name: Make gradlew executable | ||
| run: chmod +x ./gradlew | ||
|
|
||
| - name: Create benchmark results directory | ||
| run: mkdir -p benchmark-results | ||
|
|
||
| - name: Run serialization benchmarks | ||
| run: | | ||
| ./gradlew jmhRunSerializationBenchmarks | ||
| continue-on-error: true | ||
|
|
||
| - name: Run deserialization benchmarks | ||
| run: | | ||
| ./gradlew jmhRunDeserializationBenchmarks | ||
| continue-on-error: true | ||
|
|
||
| - name: Run field access benchmarks | ||
| run: | | ||
| ./gradlew jmhRunFieldAccessBenchmarks | ||
| continue-on-error: true | ||
|
|
||
| - name: Run size comparison benchmarks | ||
| run: | | ||
| ./gradlew jmhRunSizeComparisonBenchmarks | ||
| continue-on-error: true | ||
|
|
||
| - name: Upload benchmark results | ||
| uses: actions/upload-artifact@v4 | ||
| if: always() | ||
| with: | ||
| name: benchmark-results-${{ github.sha }} | ||
| path: benchmark-results/ | ||
| retention-days: 30 | ||
|
|
||
| - name: Comment benchmark results on PR | ||
| if: github.event_name == 'pull_request' | ||
| uses: actions/github-script@v7 | ||
| continue-on-error: true | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| try { | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| // Find the latest benchmark results file | ||
| const resultsDir = 'benchmark-results'; | ||
| let latestFile = null; | ||
| let latestTime = 0; | ||
|
|
||
| if (fs.existsSync(resultsDir)) { | ||
| const files = fs.readdirSync(resultsDir); | ||
| for (const file of files) { | ||
| if (file.endsWith('.json')) { | ||
| const filePath = path.join(resultsDir, file); | ||
| const stats = fs.statSync(filePath); | ||
| if (stats.mtime.getTime() > latestTime) { | ||
| latestTime = stats.mtime.getTime(); | ||
| latestFile = filePath; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (latestFile) { | ||
| console.log(`📊 Found benchmark results: ${latestFile}`); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recommend having the minimal amount of scripting inside |
||
| const results = JSON.parse(fs.readFileSync(latestFile, 'utf8')); | ||
|
|
||
| // Group results by benchmark type | ||
| const serialization = results.filter(r => r.benchmark.includes('serialize')); | ||
| const deserialization = results.filter(r => r.benchmark.includes('deserialize')); | ||
| const fieldAccess = results.filter(r => r.benchmark.includes('singleFieldAccess')); | ||
| const sizes = results.filter(r => r.benchmark.includes('measure')); | ||
|
|
||
| // Format results into a table | ||
| const formatResults = (benchmarks, title) => { | ||
| if (benchmarks.length === 0) return ''; | ||
|
|
||
| let table = `\n### ${title}\n\n| Library | Score (ns/op) | Error | Unit |\n|---------|---------------|-------|------|\n`; | ||
|
|
||
| benchmarks | ||
| .sort((a, b) => a.primaryMetric.score - b.primaryMetric.score) | ||
| .forEach(benchmark => { | ||
| const name = benchmark.benchmark.split('.').pop().replace(/serialize|deserialize|singleFieldAccess|measure/, '').replace(/Imprint|JacksonJson|Kryo|MessagePack|Avro|Protobuf|FlatBuffers/, (match) => match); | ||
| const score = benchmark.primaryMetric.score.toFixed(2); | ||
| const error = benchmark.primaryMetric.scoreError.toFixed(2); | ||
| const unit = benchmark.primaryMetric.scoreUnit; | ||
| table += `| ${name} | ${score} | ±${error} | ${unit} |\n`; | ||
| }); | ||
|
|
||
| return table; | ||
| }; | ||
|
|
||
| const comment = `## 📊 Benchmark Results | ||
|
|
||
| Benchmark comparison between Imprint and other serialization libraries: | ||
| ${formatResults(serialization, 'Serialization Performance')} | ||
| ${formatResults(deserialization, 'Deserialization Performance')} | ||
| ${formatResults(fieldAccess, 'Single Field Access Performance')} | ||
| ${formatResults(sizes, 'Serialized Size Comparison')} | ||
|
|
||
| <details> | ||
| <summary>View detailed results</summary> | ||
|
|
||
| Results generated from commit: \`${context.sha.substring(0, 7)}\` | ||
|
|
||
| Lower scores are better for performance benchmarks. | ||
|
|
||
| </details>`; | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| issue_number: context.issue.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: comment | ||
| }); | ||
|
|
||
| console.log('✅ Successfully posted benchmark results to PR'); | ||
| } else { | ||
| console.log('⚠️ No benchmark results found'); | ||
| await github.rest.issues.createComment({ | ||
| issue_number: context.issue.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: '## 📊 Benchmark Results\n\nBenchmark execution completed but no results file was found. Check the [workflow logs](' + | ||
| `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + ') for details.' | ||
| }); | ||
| } | ||
| } catch (error) { | ||
| console.log('❌ Failed to post benchmark comment:', error.message); | ||
| console.log('📁 Benchmark results are still available in workflow artifacts'); | ||
|
|
||
| // Try to post a simple error message | ||
| try { | ||
| await github.rest.issues.createComment({ | ||
| issue_number: context.issue.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: `## 📊 Benchmark Results\n\n⚠️ Failed to process benchmark results automatically.\n\nResults are available in the [workflow artifacts](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}).` | ||
| }); | ||
| } catch (commentError) { | ||
| console.log('❌ Also failed to post error comment:', commentError.message); | ||
| } | ||
| } | ||
|
|
||
| # Optional: Run full benchmark suite on releases | ||
| benchmark-full: | ||
| runs-on: ubuntu-latest | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
| permissions: | ||
| contents: read | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK 11 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '11' | ||
| distribution: 'temurin' | ||
|
|
||
| - name: Cache Gradle dependencies | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| ~/.gradle/caches | ||
| ~/.gradle/wrapper | ||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-gradle- | ||
|
|
||
| - name: Make gradlew executable | ||
| run: chmod +x ./gradlew | ||
|
|
||
| - name: Create benchmark results directory | ||
| run: mkdir -p benchmark-results | ||
|
|
||
| - name: Run full benchmark suite | ||
| run: | | ||
| ./gradlew jmhRunAllBenchmarks | ||
|
|
||
| - name: Upload full benchmark results | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: full-benchmark-results-${{ github.ref_name }} | ||
| path: benchmark-results/ | ||
| retention-days: 90 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should run the comparison benchmarks on CI - they can be run on demand since we don't expect the performance of other systems to change when we commit to Imprint and the Imprint-specific benchmarks should catch regressions (which is the point of running things on each PR).
Not only does this slow down the PR builds, but I think there's some limit to the free GH plan on how many minutes you can run workflows for (though I need to double check that, it may only apply to private repos)
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes my life way easier lol. I can reduce it to just a gradle task for ease of use to run locally and remove all the complex custom tasking