Compile Reports & Optimization
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against GWT 2.13.1 (2026-06-19), gwt-maven-plugin 1.3.0, JDK 21 with -sourceLevel 17 and the Jakarta
Servlet 6 stack of the modular-webapp archetype, checked on 2026-10-09. It is build and tooling knowledge with one
client part: the compile report and the JFR events are produced by the compiler on the developer or CI machine, while
the lightweight metrics are JavaScript events emitted by the compiled client code in the visitor’s browser. Every
number and output block below was produced on the Bookshelf scenario of this section (three locales, two user agents,
one DataGrid and one GWT.runAsync split point) with a private copy of the scratch application. The application grew
a little during the section, so the absolute sizes differ from those on the compiler page; compare figures only inside one table.
Measure first
Optimising without numbers usually shrinks the wrong thing. GWT gives three different instruments, and each answers a different question:
| Instrument | Question it answers | Where it runs | Cost |
|---|---|---|---|
Compile report ( |
Which packages, classes and fragments make my JavaScript big, and why is this class in the initial download? |
Compile time, written to the |
About 2 to 3 seconds more and several MB of files per permutation |
JFR events (2.13) |
Where does the compiler spend its time, how many permutations, fragments and AST nodes, how many bytes? |
Compile time, in the compiler JVM |
Only while a JDK Flight Recorder recording is active |
Lightweight metrics ( |
How long do bootstrap, module start, RPC calls and fragment downloads take for a real visitor? |
Browser |
Negligible; nothing happens if the host page defines no collector |
compile report, JFR,
lightweight metrics"] --> find["Find the cause
package breakdown,
dependency chain"] find --> change["Change one thing
flag, property,
code or split point"] change --> verify["Compile again
and compare bytes"] verify --> measure
Source: GWT — Optimizing
The flags themselves are described in Compiler & Compilation; this page is about using them with evidence. Splitting code into fragments is covered by Code Splitting, and the bootstrap sequence whose events are measured below by Linkers & Bootstrap.
The compile report
Producing it
-compileReport ("Compile a report that tells the Story of Your Compile", default off) collects, for every permutation,
the size contributed by each package and class and how the code is distributed over fragments, and writes a set of static
HTML pages. The gwt-maven-plugin compile goal has no compileReport parameter, so pass the flag through compilerArgs.
With the plugin the extras directory is target/extras, and the report ends up in
target/extras/<module>/soycReport/compile-report/.
<plugin>
<groupId>net.ltgt.gwt.maven</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<configuration>
<moduleName>com.example.bookshelf.App</moduleName>
<moduleShortName>bookshelf</moduleShortName>
<compilerArgs>
<arg>-generateJsInteropExports</arg>
<arg>-compileReport</arg>
</compilerArgs>
</configuration>
</plugin>
The run printed the location of the extras, and the report is not part of the war:
[INFO] Compilation succeeded -- 12,164s
[INFO] Linking into .../bookshelf-client/target/bookshelf-client-1.0-SNAPSHOT/bookshelf; Writing extras to .../bookshelf-client/target/extras/bookshelf
With the command-line compiler the same flag works with -extra dir. The flags related to the report are:
| Flag | Effect | Status |
|---|---|---|
|
Standard report. |
Documented; |
|
Adds |
Experimental, not listed by the |
|
Adds |
Experimental, not listed by the |
The -XsoycDetailed flag is a size-for-time trade: the documentation says it is "at the expense of compile time". In this
application the difference was within the noise of the machine. Two more switches (-XenableJsonSoyc and -XdisableSoycHtml)
exist in the 2.13.1 source as undocumented experimental flags and were not run here.
What a report contains
For one permutation (locale=en, user.agent=safari) the report directory held 102 files and 6.2 MB, and
the extras directory 8.4 MB. A six-permutation compile with -XsoycDetailed wrote about 40 MB of extras.
soycReport/
compile-report/
index.html overview of all permutations
SoycDashboard-0-index.html sizes of permutation 0 and its split points
CompilerMetrics-0-index.html only with -XcompilerMetrics
total-0-packageBreakdown.html package breakdown of the whole program
initial-0-packageBreakdown.html ... of the initial download
leftovers-0-codeTypeBreakdown.html
fragment1-0-overallBreakdown.html
splitStatus-0.html, leftoverStatus-0.html
methodDependencies-initial-0.html (+ .js), methodDependencies-total-0.html, methodDependencies-sp1-0.html
stories0.xml.gz dependencies0.xml.gz splitPoints0.xml.gz (detailedStories0.xml.gz with -XsoycDetailed)
Source: GWT — Compile Report: Features
Open compile-report/index.html directly from disk. It lists the permutations with their property values
('locale' : 'en' , 'user.agent' : 'safari' and so on). Without -XcompilerMetrics the "Compiler Metrics" link under each
permutation points to a page that was not written.
Overall sizes and split points
The permutation dashboard shows three numbers and the split points. For the Bookshelf permutation:
| Item | Bytes | Meaning |
|---|---|---|
Full code size |
262,930 |
The whole compiled program |
Initial download size |
262,286 |
What is downloaded before the application starts |
Left over code |
11 |
Code that no split point owns exclusively |
Split point 1, |
633 |
Fragment 1, the |
The Developer Guide explains the relation: without code splitting the initial download equals the full code size. Here
the admin area is a trivial panel, so the split point moves only 633 bytes (0.2 %) out of the initial download. The same
633 bytes can be seen in a JFR event further down. The numbers are formatted with the default locale of the JVM that ran
the compiler: on the machine used here they read 262.930 for 262,930 and 66,2 % for 66.2 %. A report generated on
a build server with another locale looks different.
The sizes are the compiled program; the permutation file <hash>.cache.js was 265,852 bytes because the linker adds its
wrapper, and about 89,500 bytes after gzip -9. Serve the .cache.js files compressed: it matters more than
most flags below.
Package and code type breakdown
The initial download of that permutation, by code type:
| Code type | Bytes | Share |
|---|---|---|
|
156,997 |
66.2 % |
|
42,556 |
18.0 % |
|
34,592 |
14.6 % |
|
2,704 |
1.1 % |
|
194 |
0.1 % |
The report also states that 4,202 bytes are strings and that 21,041 bytes cannot be attributed to a package or code type. The largest packages of the initial download were:
| Package | Bytes | Share |
|---|---|---|
|
37,066 |
15.6 % |
|
34,190 |
14.4 % |
|
27,757 |
11.7 % |
|
24,289 |
10.2 % |
|
11,248 |
4.7 % |
|
11,068 |
4.7 % |
|
4,682 |
2.0 % |
|
1,972 |
0.8 % |
Drilling into a package lists classes: the largest allOther classes were com.google.gwt.i18n.client.NumberFormat
(6,510 bytes), AbstractCellTable (5,916) and HasDataPresenter (5,547), and in the jre group java.util.ArrayList
(1,922), java.util.AbstractMap (1,838) and java.lang.Throwable (1,672). The reading is immediate: the Bookshelf’s
own code is 2 % of the program and the DataGrid is 15 %. Cutting application code would be pointless; the levers are
the widget choice, the locale machinery and the runtime flags of the next section.
Why is this class in the initial download?
The dependency pages answer "I expected this to be left out". The Developer Guide describes the procedure: from the
overview open the permutation, follow the "Report" link under "Initial download size", open the package and then the class;
the page shows a chain of calls back to the entry point. The same information is in dependencies<n>.xml.gz, where
every method lists its called by entries. Following the first caller at every step for the sort-icon initializer of the grid gave:
DataGrid_Resources_en_InlineClientBundleGenerator$dataGridSortAscendingInitializer::$clinit
<- AbstractHeaderOrFooterBuilder::AbstractHeaderOrFooterBuilder
<- DefaultHeaderOrFooterBuilder::DefaultHeaderOrFooterBuilder
<- AbstractCellTable::$init
<- AbstractCellTable::AbstractCellTable
<- DataGrid::DataGrid
The DataGrid constructor is the link to break: create the grid inside a split point and the whole chain, including the
generated client bundle, leaves the initial download. The "Split point status" and "Leftover status" pages explain the
opposite case, an item that is only in the leftover fragment because two split points need it (each page offers a
"See why it’s not exclusive to s.p. #n" link). The mechanics of exclusive and leftover fragments belong to Code Splitting.
Comparing permutations and keeping the report private
The overview lists every permutation, so differences between user agents or locales can be compared one by one. The four use cases named by the Developer Guide are reducing the whole download, the initial fragment, specific fragments and comparing permutations.
The report contains class names, method names and, with -XsoycDetailed, JavaScript snippets mapped to Java. Keep it out of the public site. With the Maven plugin the
extras folder is outside the war (a search of the war found no soyc or symbol-map file), and the same holds for
-extra of the command-line compiler as long as that directory is not inside -war. Never point -extra at the web root.
Reducing code size
All figures below are the total bytes of the six .cache.js files (three locales times two user agents), compiled with JDK 21.
| Change | Total bytes | Versus default | Remarks |
|---|---|---|---|
Default ( |
1,591,788 |
about 265 KB per permutation |
|
|
1,472,418 |
-7.5 % |
|
|
1,571,739 |
-1.3 % |
removes bounds, API and numeric checks |
|
1,554,579 |
-2.3 % |
removes the type checks too |
|
1,436,127 |
-9.8 % |
|
|
1,595,478 |
+0.2 % |
no gain below 9 here |
|
3,558,305 |
+123.5 % |
never ship |
|
3,558,321 |
+123.5 % |
never ship |
|
4,380,419 |
+175.2 % |
readable, for debugging only |
Class metadata: -XnoclassMetadata
By default GWT keeps metadata so that Class.getName() and getSimpleName() work (-X[no]classMetadata, default on). Turning it off saved
119,370 bytes over the six files. The price is visible at run time. A line that logs
App.class.getName() + " / " + App.class.getSimpleName() printed, in a headless Chrome:
com.example.bookshelf.client.App / App (default)
Class$17 / Class$17 (with -XnoclassMetadata)
So do not use the flag in an application that logs, serializes or switches on class names. In the source the disabled mode names a
class "Class$" plus an id.
Runtime checks: jre.checks.*
The JRE emulation contains checks that Java programs get from the JVM. They are controlled by properties defined in
Preconditions.gwt.xml: jre.checks.checkLevel (NORMAL, the default, OPTIMIZED or MINIMAL) and the four
finer switches jre.checks.bounds, jre.checks.api, jre.checks.numeric and jre.checks.type, each AUTO (follow the
level), ENABLED or DISABLED. In InternalPreconditions the bounds, API and numeric checks are on only at NORMAL,
and the type check at OPTIMIZED or higher. Set the level in the module or on the command line:
<!-- bookshelf-client/src/main/module.gwt.xml, release build only -->
<set-property name="jre.checks.checkLevel" value="MINIMAL" />
# same effect from the compiler arguments of a profile
-setProperty jre.checks.checkLevel=MINIMAL
The property is a deferred-binding property, so it does not add permutations when it has one value. The trade-off is
correctness: with the checks gone an out-of-range list.get(10) or a failed cast is no longer reported the way Java reports it. Measure
the gain first (2.3 % here) and try OPTIMIZED before MINIMAL. The old -XcheckCasts flag is deprecated in favour of
jre.checks.checkLevel, as the -help text says.
Avoiding heavy JRE classes
The report’s jre group is the cost of Java library classes that you pull in. A single call chain using BigDecimal
to compute a late fee, new BigDecimal("0.25").multiply(BigDecimal.valueOf(days)).setScale(2, RoundingMode.HALF_UP), made one permutation grow
from 265,852 to 290,470 bytes (+24,618, +9.3 %); the report named java.math as 21,220 bytes (8.1 %). Computing the fee
in whole cents with int removes all of it:
// shared: Bookshelf late fee in cents, no java.math needed
public static int lateFeeCents(int daysLate) {
return 25 * Math.max(0, daysLate);
}
Other classes with the same effect are listed on the JRE emulation page; see
JRE Emulation & Shared Code. Prefer plain int, double and String in shared code, and check
the report’s jre list after adding a library.
Other levers
-
Optimisation level. Keep the default
-optimize 9. Level 5 was already as large as 9 here (+0.2 %) and level 0 more than doubled the output. -
Widgets.
com.google.gwt.user.cellview.clientwas 15.6 % of the Bookshelf. A plain table in the first screen and theDataGridin a lazily loaded area is a real saving. -
Locales. Every locale adds a permutation (more build output, not more bytes per visitor); see Internationalization.
-
Split points. Code that the first screen does not need belongs behind
GWT.runAsync; the compile report is the tool that proves it left the initial fragment. -
Compression. The
.cache.jsof 265,852 bytes compressed to about 89,500 bytes withgzip -9, a 66 % reduction without touching code. See Server Integration & Deployment. -
Output style.
OBFUSCATEDis the default;PRETTYwas 2.75 times larger.
Reducing compile time
| Technique | Measured here | Notes |
|---|---|---|
Default six-permutation compile |
11 to 17 seconds |
the compiler page measured 12 seconds |
|
7 to 9.5 seconds |
optimisation level 0 plus no clustering, no literal inlining and the |
One permutation ( |
5.1 to 7.7 seconds |
produced 1 of 6 files |
|
+2 to 3 seconds |
the output files are identical to the default |
|
inconclusive |
see below |
The timings were taken on a machine shared with other builds (load average 8 to 12), so use them only for order of magnitude; the byte counts are exact and repeatable.
Fewer permutations
The cheapest saving is to compile fewer permutations while developing. Fixing the properties reduced six permutations to one:
mvn -B package -pl bookshelf-client -am -DskipTests -Dgwt.draftCompile=true
# or, with compilerArgs in a dev profile:
# -setProperty locale=en -setProperty user.agent=safari
The Maven user properties gwt.draftCompile, gwt.optimize and gwt.localWorkers exist on the compile goal.
-localWorkers is not just threads
-localWorkers count is the number of workers that compile permutations. The 2.13.1 source shows what a worker is:
ThreadedPermutationWorkerFactory creates in-process threads, but caps them at the system property gwt.jjs.maxThreads,
whose default is 1. Every further worker is launched by ExternalPermutationWorkerFactory as a separate JVM that inherits
the JVM arguments of the compiler (-Xmx and -D options) unless gwt.jjs.javaArgs overrides them. Consequences:
-
with no
-localWorkersthe six permutations were compiled one after the other by "In-process PermutationWorker 0", as the JFR events show; -
-localWorkers Nneeds memory for N compiler JVMs, not for one; -
timing gains depend on the free cores, and on the loaded machine used here the runs with 1, 3 and 6 workers (9.8 to 13.5 seconds) were not distinguishable from the default.
-incremental and -validateOnly
-incremental compiles faster by reusing data from the previous compile, but it works on one permutation only:
[ERROR] Current binding properties are expanding to more than one permutation but per-file compilation requires that each compile operate on only one permutation.
Combine it with -setProperty values that fix every property, as the code server does. The flag is meant for development; the
compiler page lists its other restrictions. -validateOnly -failOnError checks the sources without producing output and is the
cheapest first step of a pull-request build.
Runtime performance: lightweight metrics
The collector and its events
The lightweight metrics system is a global JavaScript function, __gwtStatsEvent, that the compiled code and the bootstrap call with an event
object. If the host page does not define it, nothing is reported (the compiled code checks for it before building an event).
The event is a plain object with these fields:
| Field | Meaning |
|---|---|
|
The GWT module that emitted the event, so several modules on one page can be told apart |
|
The component: |
|
A group of related events that follow a serial order; for RPC it is the request number |
|
Timestamp in milliseconds |
|
The step, for example |
Some events carry more: sessionId, method (the RPC proxy and method), fragment and size (fragment downloads) and bytes (RPC payloads).
The collector must return true or false to say whether it recorded the event, and it has to be defined before the
bootstrap script runs.
A collector for the Bookshelf host page
The Developer Guide’s example writes each event into the page with innerHTML. A collector should never render event
fields as HTML (custom events can carry any string), so this one stores text only and prints it with textContent:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Bookshelf (metrics)</title>
<meta name="gwt:property" content="locale=en">
<script>
// Must run before bookshelf.nocache.js
window.__gwtStatsEvent = function (e) {
window.__t0 = window.__t0 || e.millis;
var line = (e.millis - window.__t0) + ' ms | ' + e.moduleName + ' | ' + e.subSystem
+ ' | ' + e.evtGroup + ' | ' + e.type
+ (e.method ? ' | ' + e.method : '')
+ (e.fragment !== undefined ? ' | fragment=' + e.fragment : '');
(window.__lines = window.__lines || []).push(line);
return true;
};
window.addEventListener('load', function () {
setTimeout(function () {
var pre = document.createElement('pre');
pre.textContent = window.__lines.join('\n');
document.body.appendChild(pre);
}, 3000);
});
</script>
<script src="bookshelf/bookshelf.nocache.js"></script>
</head>
<body></body>
</html>
Served by a static server and loaded in headless Chrome, the page printed (RPC lines are from the XSRF token request, which got a 404 because no servlet container ran; the events appear all the same):
0 ms | bookshelf | startup | bootstrap | begin
0 ms | bookshelf | startup | bootstrap | selectingPermutation
4 ms | bookshelf | startup | loadExternalRefs | begin
4 ms | bookshelf | startup | loadExternalRefs | end
4 ms | bookshelf | startup | bootstrap | end
4 ms | bookshelf | startup | moduleStartup | moduleRequested
23 ms | bookshelf | startup | moduleStartup | moduleEvalStart
24 ms | bookshelf | startup | moduleStartup | moduleEvalEnd
25 ms | bookshelf | bookshelf | shell | begin
27 ms | bookshelf | bookshelf | shell | end
27 ms | bookshelf | rpc | 0 | begin | XsrfTokenService_Proxy.getNewXsrfToken
28 ms | bookshelf | rpc | 0 | requestSerialized | XsrfTokenService_Proxy.getNewXsrfToken
28 ms | bookshelf | rpc | 0 | requestSent | XsrfTokenService_Proxy.getNewXsrfToken
28 ms | bookshelf | startup | moduleStartup | end
35 ms | bookshelf | rpc | 0 | responseReceived | XsrfTokenService_Proxy.getNewXsrfToken
36 ms | bookshelf | rpc | 0 | responseDeserialized | XsrfTokenService_Proxy.getNewXsrfToken
36 ms | bookshelf | rpc | 0 | end | XsrfTokenService_Proxy.getNewXsrfToken
The startup events come from the bootstrap script, moduleStartup from the module loading (see Linkers & Bootstrap), rpc from the
RPC proxies and runAsync from the fragment loader. Opening the admin place added the split point downloads, with the leftover fragment first:
25 ms | bookshelf | runAsync | leftoversDownload | begin | fragment=2
35 ms | bookshelf | runAsync | leftoversDownload | end | fragment=2
35 ms | bookshelf | runAsync | download1 | begin | fragment=1
45 ms | bookshelf | runAsync | download1 | end | fragment=1
45 ms | bookshelf | runAsync | runCallbacks1 | begin
45 ms | bookshelf | runAsync | runCallbacks1 | end
Your own events with JsInterop
The Developer Guide extends the system with a JSNI method. In 2.13 a native JsInterop binding does the same without JSNI, and
JsPackage.GLOBAL reached the host page’s __gwtStatsEvent (the compiled code runs inside the xsiframe iframe, and the
call still arrived):
@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
public class StatsEvent {
public String moduleName;
public String subSystem;
public String evtGroup;
public double millis;
public String type;
}
public final class Stats {
private Stats() {
}
@JsProperty(namespace = JsPackage.GLOBAL, name = "__gwtStatsEvent")
private static native Object collector();
@JsMethod(namespace = JsPackage.GLOBAL, name = "__gwtStatsEvent")
private static native boolean send(StatsEvent event);
public static void log(String subSystem, String evtGroup, String type) {
if (collector() == null) {
return; // no collector on the host page: cost is one check
}
StatsEvent e = new StatsEvent();
e.moduleName = GWT.getModuleName();
e.subSystem = subSystem;
e.evtGroup = evtGroup;
e.millis = Duration.currentTimeMillis();
e.type = type;
send(e);
}
}
// App.onModuleLoad
Stats.log("bookshelf", "shell", "begin");
ClientFactory factory = new ClientFactory();
// ... build the shell ...
Stats.log("bookshelf", "shell", "end");
The shell begin and shell end lines in the output above come from this code. Several modules on one page report to the
same collector with their own moduleName, which allows comparing them (the "multiple modules" section of the guide).
Using the data in production
-
Events contain module names, RPC method names, timings and fragment numbers, not RPC payloads. Do not add user data to custom events.
-
The collector is an inline
<script>; with a strict Content-Security-Policy put it in a file or give it a nonce. -
To send field data to a server, batch the lines and use
navigator.sendBeaconfrom the collector; do not issue a request per event. -
The Developer Guide mentions a Debug Panel for GWT built on this system; it was not tried here.
JFR events of the compiler (2.13)
The 2.13.0 release notes say: "JFR events added to replace SpeedTracer, support observability into compiler steps, permutation and fragment counts, and output size". The Optimizing page of the Developer Guide still recommends Speed Tracer, which is outdated. These are Java Flight Recorder events in the compiler JVM, not browser data; use the browser’s own developer tools for run-time profiling, with source maps from Super Dev Mode & Debugging. The 2.13.1 release added the GWT version and commit to the output, so recordings can be compared across releases.
Recording
The events are ordinary jdk.jfr.Event subclasses in the GWT category with @StackTrace(false). They are written when a recording is
running in the compiler JVM. With Maven the compiler is a forked JVM, so pass the option in jvmArgs:
<configuration>
<jvmArgs>
<arg>-XX:StartFlightRecording:filename=${project.build.directory}/gwt-compile.jfr,settings=default</arg>
</jvmArgs>
</configuration>
mvn -B package -pl bookshelf-client -am -DskipTests
$JAVA_HOME/bin/jfr summary bookshelf-client/target/gwt-compile.jfr
$JAVA_HOME/bin/jfr print --events gwt.compiler.js.Fragment bookshelf-client/target/gwt-compile.jfr
The summary of the six-permutation compile listed these GWT events (count of events in the recording):
| Event | Count | What it records |
|---|---|---|
|
1 |
GWT version ( |
|
3,798 |
A named task and its duration, for example |
|
739 |
One optimisation or normalisation pass |
|
72 |
An iteration of the Java or JavaScript optimisation loop, with |
|
6 |
Duration and property values of each permutation |
|
18 |
Permutation id, fragment index and |
|
60 and 24 |
AST node count |
|
438 and 95 |
Deferred-binding resolutions (see Deferred Binding & Generators) |
|
192 |
Time per generator class |
|
155, 30 and 4 |
Module loading and type oracle phases |
The fragment events tie the two tools together. For permutation 0 the recording has fragment 0 with jsBytes = 259606
and fragment 1 with jsBytes = 658; the compile report of the same permutation reported an initial download of 259,606 bytes
and a split point of 658.
Reading a recording
Printing as JSON and aggregating gave this picture for the Bookshelf compile:
| Task or pass | Time |
|---|---|
|
8.1 s |
|
7.2 s |
|
6.1 s |
|
5.6 s |
|
1.5 s |
|
1.2 s |
|
0.9 s |
|
0.8 s |
generator |
0.36 s |
generator |
0.08 s |
Nested tasks overlap, so the figures do not add up. Two conclusions followed: the time before the permutations
(parsing and type resolution) is as large as the optimisation, and generators are almost free here, so
trimming UiBinder templates would not shorten this build while fewer permutations would.
The gwt.jjs.dumpAst system property, which the release notes say was tweaked in 2.13.0, dumps the Java and JavaScript AST between
passes to a file; gwt.jjs.dumpAst.filter restricts the output to source files and line ranges. It is a compiler-developer tool and is only mentioned for completeness.
Worked example: a Bookshelf size and time budget
| Step | Action | Result |
|---|---|---|
1 |
Compile with |
Initial download 262,286 bytes; |
2 |
Open the dependency chain of the grid |
|
3 |
Replace the |
-24,618 bytes (-9.3 %) in the experiment |
4 |
Release profile: |
-7.5 % and -1.3 % of the total bytes |
5 |
Pull-request profile: one permutation, |
about 5 to 8 seconds instead of 11 to 17 |
6 |
Serve |
265,852 to about 89,500 bytes on the wire |
7 |
Add the metrics collector to a staging host page |
startup and RPC timings per visitor, no code change in the application |
Pitfalls
| Symptom or message | Cause | Fix |
|---|---|---|
|
|
Fix every property with |
No |
Not a |
Use |
"Compiler Metrics" link in the report opens nothing |
|
Add |
Class names such as |
|
Do not rely on |
No |
|
Define it before the bootstrap script |
JFR file lacks most permutations |
With |
Profile with the default single worker |
Report numbers look like |
Number format of the compiler JVM’s default locale |
Read it as 262,930, or set a locale for the compile |
Compile times vary by 50 % between runs |
Other processes on the machine |
Compare bytes, or repeat and take the minimum |
A draft compile is 600 KB per permutation |
|
Never deploy them |
Report published with the site |
|
Keep |
Recent changes and outdated material
-
2.13.0. JFR events replace Speed Tracer for compiler observability; 2.13.1 adds the GWT version and commit to them.
-
Optimizing page. The Developer Guide page still points to Speed Tracer and uses
innerHTMLin its metrics sample; both are outdated. -
JSNI. The extension example of the lightweight metrics page uses JSNI; JsInterop does it without JSNI.
-
The book. The first edition of GWT in Action predates GWT 2 and does not cover compile reports, lightweight metrics or JFR.