Skip to content

Cut a new project's first build download in half, and gate it - #6213

Merged
shai-almog merged 3 commits into
masterfrom
first-build-download-diet
Nov 12, 2026
Merged

shai-almog merged 3 commits into
masterfrom
first-build-download-diet

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

What a new developer saw

The first thing anyone does with Codename One is run a project from the initializr on a machine that has never built one. That build downloaded 346 MB before the simulator opened. Maven resolves a plugin's whole class path before its first goal, so every runtime dependency of the build tools was downloaded by a Hello World:

  • 55 MB of ports (iOS, Android, Mac, Windows, Linux, ParparVM) that no simulator run opens
  • 157 MB of ffmpeg natives for seven platforms, of which the machine can run one

It is 174 MB on a Mac now, and less on Linux and Windows, which take one ffmpeg architecture where a Mac takes two.

What changed

  • Ports are resolved when a target needs them. They are provided and optional in codenameone-maven-plugin and build-engine. AppBuilder.LocalBuild names the ports each local target reads, ProjectHost.getPortJar resolves one at the build tool's own version, and Executor.getResourceAsStream reads the class path first and those jars second. Maven and Gradle behave the same way.
  • ffmpeg is the host's alone. cn1-binaries-javase selects natives with OS-activated profiles; the Gradle plugin mirrors the table in PluginInfo.hostFfmpegPlatforms.
  • The desktop jar still plays media everywhere. javase-executable-jar resolves the other desktop platforms itself. A project with a javase module gets them through -Dcn1.ffmpeg.allPlatforms=true, which every generated launcher (scripts, Eclipse, IntelliJ, NetBeans, VS Code, the Initializr archives) and cn1:buildExecutableJar pass. An older project's launcher gets a build warning naming the property.

What stops it growing back

  • scripts/check-first-build-footprint.py (in archetype-smoke.yml) generates a project, builds what run.sh builds into an empty local repository, and fails on a port, on a native for another platform, on a host with no ffmpeg, or on the size budget. CI runs on Linux only, so it also holds every host's profile to a table.
  • scripts/sync-initializr-launchers.py (in starter-launchers.yml) fails on any launcher copy that builds the desktop jar without the property, command by command.
  • LocalBuildPortsTest, ExecutorPortJarTest, PortJarSelectionTest and DesktopNativesTest cover the target table, the resource lookup, the Gradle selection and the desktop natives.

Verified locally

  • Putting the iOS port back at runtime scope makes the footprint gate fail and name it.
  • ios-source, mac-source, local-javascript and android-source each resolve only their own ports from an empty repository, through Maven and through Gradle (gradle-maven-parity-test).
  • Hosted and javase-module desktop jars both carry the five desktop ffmpeg natives.
  • Tests and SpotBugs (zero findings) for build-engine, codenameone-maven-plugin and codenameone-gradle-plugin.

The Linux budget is derived from the Mac measurement; the first archetype-smoke run gives the real figure.

🤖 Generated with Claude Code

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 12 screenshots: 12 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 195 screenshots: 195 matched.

Native Android coverage

  • 📊 Line coverage: 19.17% (56159/292885 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 18.13% (270547/1492353), branch 12.38% (19675/158943), complexity 10.36% (15847/153017), method 15.74% (11411/72518), class 27.94% (2248/8045)
    • Lowest covered classes
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2396 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • androidx.compose.runtime.androidx.compose.runtime.LinkComposer – 0.00% (0/1430 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlinx.coroutines.channels.kotlinx.coroutines.channels.BufferedChannel – 0.00% (0/863 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/744 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/630 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 19.17% (56159/292885 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 18.13% (270547/1492353), branch 12.38% (19675/158943), complexity 10.36% (15847/153017), method 15.74% (11411/72518), class 27.94% (2248/8045)
    • Lowest covered classes
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2396 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • androidx.compose.runtime.androidx.compose.runtime.LinkComposer – 0.00% (0/1430 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlinx.coroutines.channels.kotlinx.coroutines.channels.BufferedChannel – 0.00% (0/863 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/744 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/630 lines covered)
      • com.codename1.androidcompat.rt.com.codename1.androidcompat.rt.TextXmlPullParser – 0.00% (0/623 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 181ms / native 152ms = 1.1x speedup
SIMD float-mul (64K x300) java 124ms / native 129ms = 0.9x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 68.000 ms
Base64 CN1 decode 67.000 ms
Base64 native encode 370.000 ms
Base64 encode ratio (CN1/native) 0.184x (81.6% faster)
Base64 native decode 236.000 ms
Base64 decode ratio (CN1/native) 0.284x (71.6% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ✅ ByteCodeTranslator: 0 findings (no issues)
    • ✅ android: 0 findings (no issues)
    • ✅ android-compat: 0 findings (no issues)
    • ✅ android-res-compiler: 0 findings (no issues)
    • ✅ backend: 0 findings (no issues)
    • ✅ backend-test: 0 findings (no issues)
    • ✅ build-engine: 0 findings (no issues)
    • ✅ build-hint-catalog: 0 findings (no issues)
    • ✅ build-hint-tools: 0 findings (no issues)
    • ✅ codenameone-gradle-plugin: 0 findings (no issues)
    • ✅ codenameone-maven-plugin: 0 findings (no issues)
    • ✅ compose-compat: 0 findings (no issues)
    • ✅ core-unittests: 0 findings (no issues)
    • ✅ desktop-compat-runtime: 0 findings (no issues)
    • ✅ fxml-compiler: 0 findings (no issues)
    • ✅ ios: 0 findings (no issues)
    • ✅ javac: 0 findings (no issues)
    • ✅ javafx-compat: 0 findings (no issues)
    • ✅ project-model: 0 findings (no issues)
    • ✅ python-runtime: 0 findings (no issues)
    • ✅ python-transpiler: 0 findings (no issues)
    • ✅ swing-compat: 0 findings (no issues)
  • ✅ PMD: 0 findings (no issues) [Report archive]
  • ✅ Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 193 screenshots: 193 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 3619 seconds

Build and Run Timing

Metric Duration
Simulator Boot 61000 ms
Simulator Boot (Run) 1000 ms
App Install 23000 ms
App Launch 8000 ms
Test Execution 480000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 124ms / native 4ms = 31.0x speedup
SIMD float-mul (64K x300) java 86ms / native 4ms = 21.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 51.000 ms
Base64 CN1 decode 88.000 ms
Base64 native encode 1136.000 ms
Base64 encode ratio (CN1/native) 0.045x (95.5% faster)
Base64 native decode 1117.000 ms
Base64 decode ratio (CN1/native) 0.079x (92.1% faster)
Base64 SIMD encode 90.000 ms
Base64 encode ratio (SIMD/CN1) 1.765x (76.5% slower)
Base64 SIMD decode 49.000 ms
Base64 decode ratio (SIMD/CN1) 0.557x (44.3% faster)
Base64 encode ratio (SIMD/native) 0.079x (92.1% faster)
Base64 decode ratio (SIMD/native) 0.044x (95.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 5.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.400x (60.0% faster)
Image applyMask (SIMD off) 37.000 ms
Image applyMask (SIMD on) 31.000 ms
Image applyMask ratio (SIMD on/off) 0.838x (16.2% faster)
Image modifyAlpha (SIMD off) 38.000 ms
Image modifyAlpha (SIMD on) 35.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.921x (7.9% faster)
Image modifyAlpha removeColor (SIMD off) 44.000 ms
Image modifyAlpha removeColor (SIMD on) 35.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.795x (20.5% faster)

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 231 screenshots: 231 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 188 screenshots: 188 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 192 screenshots: 192 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 917 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 81ms / native 3ms = 27.0x speedup
SIMD float-mul (64K x300) java 66ms / native 7ms = 9.4x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 52.000 ms
Base64 CN1 decode 68.000 ms
Base64 native encode 959.000 ms
Base64 encode ratio (CN1/native) 0.054x (94.6% faster)
Base64 native decode 345.000 ms
Base64 decode ratio (CN1/native) 0.197x (80.3% faster)
Base64 SIMD encode 79.000 ms
Base64 encode ratio (SIMD/CN1) 1.519x (51.9% slower)
Base64 SIMD decode 50.000 ms
Base64 decode ratio (SIMD/CN1) 0.735x (26.5% faster)
Base64 encode ratio (SIMD/native) 0.082x (91.8% faster)
Base64 decode ratio (SIMD/native) 0.145x (85.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 8.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.250x (75.0% faster)
Image applyMask (SIMD off) 89.000 ms
Image applyMask (SIMD on) 76.000 ms
Image applyMask ratio (SIMD on/off) 0.854x (14.6% faster)
Image modifyAlpha (SIMD off) 99.000 ms
Image modifyAlpha (SIMD on) 121.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.222x (22.2% slower)
Image modifyAlpha removeColor (SIMD off) 163.000 ms
Image modifyAlpha removeColor (SIMD on) 82.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.503x (49.7% faster)

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 196 screenshots: 196 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 525 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 55ms / native 3ms = 18.3x speedup
SIMD float-mul (64K x300) java 57ms / native 4ms = 14.2x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 43.000 ms
Base64 CN1 decode 50.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.429x (57.1% faster)
Image applyMask (SIMD off) 50.000 ms
Image applyMask (SIMD on) 49.000 ms
Image applyMask ratio (SIMD on/off) 0.980x (2.0% faster)
Image modifyAlpha (SIMD off) 48.000 ms
Image modifyAlpha (SIMD on) 41.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.854x (14.6% faster)
Image modifyAlpha removeColor (SIMD off) 44.000 ms
Image modifyAlpha removeColor (SIMD on) 51.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.159x (15.9% slower)

ParparVM vs HotSpot (JDK 25): macOS arm64

Runner CPU: Apple M1 (Virtual) (baseline macos-arm64)

Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in vm/selfhost/perf-baseline/ is a regression and fails; one that far below is an improvement, reported but not failed (a row whose calibration runs were noisier carries a wider tolerance), and for RAM the change must also exceed 0.05x in absolute terms. Both run unpinned on all of the runner's CPUs, with their own default thread counts.

Benchmark Cores Time RAM Status
hello (HelloCodenameOne) 3 1.12x (base 0.96x, +17.2%) 0.90x (base 0.93x, -3.0%) ok
translator (self) 3 0.66x (base 0.62x, +5.7%) 0.87x (base 0.78x, +10.7%) ok
intArithmetic 3 1.05x (base 1.03x, +1.4%) 0.12x (base 0.12x, +1.8%) ok
longArithmetic 3 1.02x (base 1.03x, -0.4%) 0.11x (base 0.07x, +63.6%) ok
mathTranscendental 3 0.98x (base 1.01x, -2.3%) 0.12x (base 0.12x, -0.1%) ok
arraySequential 3 0.45x (base 0.42x, +8.2%) 0.53x (base 0.53x, +0.3%) ok
arrayRandom 3 0.98x (base 0.99x, -0.6%) 0.33x (base 0.32x, +0.3%) ok
objectAllocation 3 1.00x (base 1.11x, -9.8%) 0.90x (base 0.72x, +25.0%) ok
valueEscape 3 0.51x (base 0.51x, +1.2%) 0.09x (base 0.09x, +0.9%) ok
hashMapChurn 3 1.09x (base 1.18x, -6.9%) 0.08x (base 0.07x, +12.3%) ok
stringBuilding 3 0.99x (base 0.84x, +17.7%) 0.46x (base 0.46x, -1.2%) ok
recursion 3 1.22x (base 1.24x, -0.9%) 0.12x (base 0.12x, +1.0%) ok
quicksort 3 0.99x (base 1.01x, -1.8%) 0.11x (base 0.11x, +1.0%) ok

Result: no regression

@shai-almog

shai-almog commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator Author

Compared 253 screenshots: 253 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

shai-almog and others added 3 commits November 12, 2026 00:32
A project from the initializr downloaded 346 MB before its first simulator
run. Maven resolves a plugin's whole class path before the first goal, so the
build tools' runtime dependencies were every Hello World's: 55 MB of ports no
simulator run opens and 157 MB of ffmpeg for seven platforms. It is 174 MB on
a Mac now.

- The ports are provided and optional in codenameone-maven-plugin and
  build-engine. AppBuilder.LocalBuild names the ports each local target
  reads, ProjectHost.getPortJar resolves one at the build tool's own version
  when that target is built, and Executor.getResourceAsStream reads the class
  path first and those jars second. Maven and Gradle both do this.
- ffmpeg is the host's alone: cn1-binaries-javase selects the natives with
  OS-activated profiles, and the Gradle plugin mirrors the table.
- The desktop jar runs on other machines, so it still carries every desktop
  platform's natives. javase-executable-jar resolves them itself; a project
  with a javase module gets them from -Dcn1.ffmpeg.allPlatforms=true, which
  every generated launcher and cn1:buildExecutableJar pass, and
  generate-desktop-app-wrapper warns when a launcher does not.

scripts/check-first-build-footprint.py (archetype-smoke.yml) generates a
project, builds it into an empty local repository and fails on a port, on a
native for another platform, on a host with no ffmpeg, or on the budget. It
also holds every host's profile to a table, since CI resolves on Linux only.
scripts/sync-initializr-launchers.py now fails on any launcher copy that
builds the desktop jar without the property.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The step inherited the JDK 8 the framework builds with, and the plugin
refuses a simulator build on anything older than 11.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Passing runs take 35 to 39 minutes there, and the 40 minute limit cancelled
the nightly and pull request runs alike.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@shai-almog
shai-almog force-pushed the first-build-download-diet branch from 0e9a74e to 80f5d98 Compare November 11, 2026 22:32
@github-actions

Copy link
Copy Markdown
Contributor

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • ✅ Tests: 934 total, 0 failed, 55 skipped

Benchmark Results

  • Execution Time: 6124 ms

  • Hotspots (Top 20 sampled methods):

    • 10.95% java.lang.System.identityHashCode (97 samples)
    • 6.77% com.codename1.tools.translator.BytecodeMethod.equals (60 samples)
    • 6.09% java.lang.Object.hashCode (54 samples)
    • 3.39% java.lang.StringBuilder.append (30 samples)
    • 3.27% java.util.ArrayList.indexOf (29 samples)
    • 3.05% com.codename1.tools.translator.NativeSymbolIndex.extend (27 samples)
    • 2.03% com.codename1.tools.translator.classfile.analysis.Frame.execute (18 samples)
    • 2.03% com.codename1.tools.translator.BytecodeMethod.updateInlinableFieldDependencies (18 samples)
    • 1.92% com.codename1.tools.translator.Parser.cullMethods (17 samples)
    • 1.92% java.lang.String.equals (17 samples)
    • 1.58% com.codename1.tools.translator.ByteCodeClass.fillVirtualMethodTable (14 samples)
    • 1.58% com.codename1.tools.translator.classfile.analysis.Frame.merge (14 samples)
    • 1.58% java.util.HashMap.hash (14 samples)
    • 1.24% com.codename1.tools.translator.bytecodes.Invoke.resolveDirectTarget (11 samples)
    • 1.24% com.codename1.tools.translator.DeadFieldElimination.run (11 samples)
    • 1.24% com.codename1.tools.translator.ByteCodeClass.hasDeclaredMethod (11 samples)
    • 1.13% com.codename1.tools.translator.JavascriptReachability.enqueueResolved (10 samples)
    • 1.13% java.io.FileInputStream.open0 (10 samples)
    • 1.13% java.io.FileOutputStream.writeBytes (10 samples)
    • 1.13% com.codename1.tools.translator.Parser.collectTypeTests (10 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@shai-almog
shai-almog merged commit d069e65 into master Nov 12, 2026
78 of 80 checks passed
@shai-almog
shai-almog deleted the first-build-download-diet branch November 12, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant