This is an automated email from the ASF dual-hosted git repository.
papegaaij pushed a commit to branch wicket-6774
in repository https://gitbox.apache.org/repos/asf/wicket.git
The following commit(s) were added to refs/heads/wicket-6774 by this push:
new 338720c7fc WICKET-6774: benchmark a real ajax behavior, and hand out
behavior ids first
338720c7fc is described below
commit 338720c7fc3390a4746239ed1f31e65ca0f49e36
Author: Emond Papegaaij <[email protected]>
AuthorDate: Fri Sep 4 22:48:03 2026 +0200
WICKET-6774: benchmark a real ajax behavior, and hand out behavior ids first
Every behavior shape so far used AttributeModifier, which never needs a
stable
id, so none of them created the BehaviorIdList that stores those ids. That
is
the structure this issue claims its largest saving on, and it was the one
case
the benchmarks did not cover. AJAX_BEHAVIOR adds a real AjaxEventBehavior,
so
the numbers are comparable to the -36.2% serialized saving reported on the
issue in 2020; measured now it is -39.8% for the tree, -72 bytes of retained
heap and -32 bytes serialized per component.
Keeping STABLE_ID_BEHAVIOR alongside it is deliberate. The absolute saving
is
the same for both, because the same structure is removed either way, but the
bare behavior carries almost nothing of its own and so reports -86% per
component against the real behavior's -68%. Having both makes it obvious
that
the absolute figure is the one that carries over between cases and the
percentage is not.
readBehaviorById could not run at all before this. It looked up an id that
was
never handed out, which the array index of the reworked state resolves
happily
while master throws InvalidBehaviorIdException, since master only builds its
BehaviorIdList when getBehaviorId is called. The setup now assigns ids
first,
the way rendering does, so the benchmark measures the same work on both.
With that fixed, the ajax paths measure (2 forks, ns/op, master -> reworked
state):
readBehaviorById 2.82 -> 1.62 -43%
readBehaviors[AJAX_BEHAVIOR] 11.15 -> 1.97 -82%, 72 -> 24 B/op
readMetaData[AJAX_BEHAVIOR] 1.06 -> 0.81 -24%
buildAndDetach[AJAX_BEHAVIOR] 51.59 -> 29.36 -43%, 180 -> 96 B/op
Meta data reads get cheaper as a side effect: master keeps the id list in
the
component's own meta data, so any meta data read on a link or ajax component
pays to walk past it.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.../wicket/benchmarks/ComponentStateBenchmark.java | 49 +++++++++++++++++++---
1 file changed, 43 insertions(+), 6 deletions(-)
diff --git
a/wicket-benchmarks/src/main/java/org/apache/wicket/benchmarks/ComponentStateBenchmark.java
b/wicket-benchmarks/src/main/java/org/apache/wicket/benchmarks/ComponentStateBenchmark.java
index c43fd50976..b44b5a66af 100644
---
a/wicket-benchmarks/src/main/java/org/apache/wicket/benchmarks/ComponentStateBenchmark.java
+++
b/wicket-benchmarks/src/main/java/org/apache/wicket/benchmarks/ComponentStateBenchmark.java
@@ -21,6 +21,8 @@ import java.util.concurrent.TimeUnit;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.model.Model;
@@ -99,24 +101,37 @@ public class ComponentStateBenchmark
* biggest saving. None of the other shapes exercise it.
*/
STABLE_ID_BEHAVIOR(false, false, false, true),
- MODEL_STABLE_ID_BEHAVIOR(true, false, false, true);
+ MODEL_STABLE_ID_BEHAVIOR(true, false, false, true),
+ /**
+ * A real {@link AjaxEventBehavior}, so the figure is
comparable to the -36.2% serialized
+ * saving reported on WICKET-6774. {@link #STABLE_ID_BEHAVIOR}
isolates the id storage but
+ * carries almost nothing of its own, which flatters the
percentage.
+ */
+ AJAX_BEHAVIOR(false, false, false, true, true);
private final boolean model;
private final boolean behavior;
private final boolean metaData;
private final boolean stableId;
+ private final boolean ajax;
Shape(boolean model, boolean behavior, boolean metaData)
{
- this(model, behavior, metaData, false);
+ this(model, behavior, metaData, false, false);
}
Shape(boolean model, boolean behavior, boolean metaData,
boolean stableId)
+ {
+ this(model, behavior, metaData, stableId, false);
+ }
+
+ Shape(boolean model, boolean behavior, boolean metaData,
boolean stableId, boolean ajax)
{
this.model = model;
this.behavior = behavior;
this.metaData = metaData;
this.stableId = stableId;
+ this.ajax = ajax;
}
Component newComponent(String id)
@@ -142,7 +157,7 @@ public class ComponentStateBenchmark
}
if (stableId)
{
- Behavior stable = new StableIdBehavior();
+ Behavior stable = ajax ? new AjaxTestBehavior()
: new StableIdBehavior();
c.add(stable);
// rendering a callback url does this; it is
what materialises the id storage
c.getBehaviorId(stable);
@@ -150,6 +165,22 @@ public class ComponentStateBenchmark
}
}
+ /** A real ajax behavior, with the fields and callback machinery that
implies. */
+ private static class AjaxTestBehavior extends AjaxEventBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ AjaxTestBehavior()
+ {
+ super("change");
+ }
+
+ @Override
+ protected void onEvent(AjaxRequestTarget target)
+ {
+ }
+ }
+
/** Requires a stable behavior id, the way an ajax behavior or link
does. */
private static class StableIdBehavior extends Behavior
{
@@ -222,9 +253,15 @@ public class ComponentStateBenchmark
WicketContext.attach();
component = new WebMarkupContainer("c");
component.setDefaultModel(Model.of("m"));
- component.setMetaData(KEY, "v");
- component.add(AttributeModifier.replace("class", "a"),
- AttributeModifier.replace("style", "b"),
AttributeModifier.replace("title", "c"));
+ // ids have to be handed out before they can be looked
up: master only builds its
+ // BehaviorIdList when getBehaviorId is called, and
throws
+ // InvalidBehaviorIdException otherwise. Rendering a
callback url does this.
+ for (int i = 0; i < 3; i++)
+ {
+ Behavior stable = new StableIdBehavior();
+ component.add(stable);
+ component.getBehaviorId(stable);
+ }
}
@TearDown(Level.Trial)