View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.internal.xml;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.TimeUnit;
25  
26  import org.apache.maven.api.xml.XmlNode;
27  import org.codehaus.plexus.configuration.PlexusConfiguration;
28  import org.openjdk.jmh.annotations.Benchmark;
29  import org.openjdk.jmh.annotations.BenchmarkMode;
30  import org.openjdk.jmh.annotations.Fork;
31  import org.openjdk.jmh.annotations.Measurement;
32  import org.openjdk.jmh.annotations.Mode;
33  import org.openjdk.jmh.annotations.OutputTimeUnit;
34  import org.openjdk.jmh.annotations.Scope;
35  import org.openjdk.jmh.annotations.Setup;
36  import org.openjdk.jmh.annotations.State;
37  import org.openjdk.jmh.annotations.Warmup;
38  import org.openjdk.jmh.infra.Blackhole;
39  
40  /**
41   * JMH benchmarks comparing the performance of the old vs new XmlPlexusConfiguration implementations.
42   *
43   * To run these benchmarks:
44   * mvn test-compile exec:java -Dexec.mainClass="org.openjdk.jmh.Main"
45   *     -Dexec.classpathScope=test
46   *     -Dexec.args="org.apache.maven.internal.xml.XmlPlexusConfigurationBenchmark"
47   */
48  @BenchmarkMode(Mode.AverageTime)
49  @OutputTimeUnit(TimeUnit.NANOSECONDS)
50  @State(Scope.Benchmark)
51  @Fork(1)
52  @Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
53  @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
54  public class XmlPlexusConfigurationBenchmark {
55  
56      private XmlNode simpleNode;
57      private XmlNode complexNode;
58      private XmlNode deepNode;
59  
60      @Setup
61      public void setup() {
62          // Create test XML nodes of varying complexity
63          simpleNode = createSimpleNode();
64          complexNode = createComplexNode();
65          deepNode = createDeepNode();
66      }
67  
68      /**
69       * Benchmark constructor performance - Simple XML
70       */
71      @Benchmark
72      public PlexusConfiguration constructorOldSimple() {
73          return new XmlPlexusConfigurationOld(simpleNode);
74      }
75  
76      @Benchmark
77      public PlexusConfiguration constructorNewSimple() {
78          return new XmlPlexusConfiguration(simpleNode);
79      }
80  
81      /**
82       * Benchmark constructor performance - Complex XML
83       */
84      @Benchmark
85      public PlexusConfiguration constructorOldComplex() {
86          return new XmlPlexusConfigurationOld(complexNode);
87      }
88  
89      @Benchmark
90      public PlexusConfiguration constructorNewComplex() {
91          return new XmlPlexusConfiguration(complexNode);
92      }
93  
94      /**
95       * Benchmark constructor performance - Deep XML
96       */
97      @Benchmark
98      public PlexusConfiguration constructorOldDeep() {
99          return new XmlPlexusConfigurationOld(deepNode);
100     }
101 
102     @Benchmark
103     public PlexusConfiguration constructorNewDeep() {
104         return new XmlPlexusConfiguration(deepNode);
105     }
106 
107     /**
108      * Benchmark child access performance - Lazy vs Eager
109      */
110     @Benchmark
111     public void childAccessOldComplex(Blackhole bh) {
112         PlexusConfiguration config = new XmlPlexusConfigurationOld(complexNode);
113         // Access all children to measure eager loading performance
114         for (int i = 0; i < config.getChildCount(); i++) {
115             bh.consume(config.getChild(i));
116         }
117     }
118 
119     @Benchmark
120     public void childAccessNewComplex(Blackhole bh) {
121         PlexusConfiguration config = new XmlPlexusConfiguration(complexNode);
122         // Access all children to measure lazy loading performance
123         for (int i = 0; i < config.getChildCount(); i++) {
124             bh.consume(config.getChild(i));
125         }
126     }
127 
128     /**
129      * Benchmark memory allocation patterns
130      */
131     @Benchmark
132     public PlexusConfiguration memoryAllocationOld() {
133         // This will trigger deep copying and high memory allocation
134         return new XmlPlexusConfigurationOld(deepNode);
135     }
136 
137     @Benchmark
138     public PlexusConfiguration memoryAllocationNew() {
139         // This should have much lower memory allocation due to sharing
140         return new XmlPlexusConfiguration(deepNode);
141     }
142 
143     // Helper methods to create test XML nodes
144     private XmlNode createSimpleNode() {
145         Map<String, String> attrs = Map.of("attr1", "value1");
146         return XmlNode.newBuilder()
147                 .name("simple")
148                 .value("test-value")
149                 .attributes(attrs)
150                 .build();
151     }
152 
153     private XmlNode createComplexNode() {
154         Map<String, String> attrs = Map.of("id", "test", "version", "1.0");
155         List<XmlNode> children = List.of(
156                 XmlNode.newInstance("child1", "value1"),
157                 XmlNode.newInstance("child2", "value2"),
158                 XmlNode.newBuilder()
159                         .name("child3")
160                         .children(List.of(
161                                 XmlNode.newInstance("nested1", "nested-value1"),
162                                 XmlNode.newInstance("nested2", "nested-value2")))
163                         .build(),
164                 XmlNode.newInstance("child4", "value4"),
165                 XmlNode.newInstance("child5", "value5"));
166 
167         return XmlNode.newBuilder()
168                 .name("complex")
169                 .attributes(attrs)
170                 .children(children)
171                 .build();
172     }
173 
174     private XmlNode createDeepNode() {
175         List<XmlNode> levels = new ArrayList<>();
176 
177         // Create a deep hierarchy to stress test performance
178         for (int i = 0; i < 10; i++) {
179             List<XmlNode> items = new ArrayList<>();
180             for (int j = 0; j < 5; j++) {
181                 Map<String, String> itemAttrs = Map.of("index", String.valueOf(j));
182                 items.add(XmlNode.newBuilder()
183                         .name("item" + j)
184                         .value("value-" + i + "-" + j)
185                         .attributes(itemAttrs)
186                         .build());
187             }
188             levels.add(XmlNode.newBuilder().name("level" + i).children(items).build());
189         }
190 
191         return XmlNode.newBuilder().name("root").children(levels).build();
192     }
193 }