You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2019/06/04 19:33:53 UTC
[plc4x] 02/02: - Optimized the generated code to be way more
efficient while parsing
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/code-gen
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 87a9a46b0cd7b07f0cb56e83d96d1b06d9b5c34e
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Tue Jun 4 21:33:41 2019 +0200
- Optimized the generated code to be way more efficient while parsing
---
.../apache/plc4x/language/fields/ArrayField.java | 5 ---
.../apache/plc4x/language/fields/ContextField.java | 36 -----------------
.../plc4x/language/fields/OptionalField.java | 5 ---
.../plc4x/language/fields/PropertyField.java | 7 ++++
.../apache/plc4x/language/fields/SimpleField.java | 6 ---
.../code-generation/language-template-java/pom.xml | 5 +++
.../language/java/JavaLanguageTemplateHelper.java | 22 ++++++++++
.../main/resources/templates/java/io-template.ftlh | 47 +++++++++++++++-------
.../codegenerator/parser/imaginary/Imaginary.g4 | 34 ++++++++--------
.../parser/MessageFormatListener.java | 15 +++----
.../src/main/resources/protocols/s7/protocol.spec | 2 +-
.../apache/plc4x/java/utils/EvaluationHelper.java} | 40 +++++++++---------
.../java/{Test.java => BenchmarkGeneratedS7.java} | 13 ++++--
13 files changed, 122 insertions(+), 115 deletions(-)
diff --git a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ArrayField.java b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ArrayField.java
index e79cb9b..a0af838 100644
--- a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ArrayField.java
+++ b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ArrayField.java
@@ -19,7 +19,6 @@
package org.apache.plc4x.language.fields;
-import org.apache.plc4x.language.references.TypeReference;
public interface ArrayField extends PropertyField {
@@ -27,10 +26,6 @@ public interface ArrayField extends PropertyField {
return "array";
}
- TypeReference getType();
-
- String getName();
-
LengthType getLengthType();
String getLengthExpression();
diff --git a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ContextField.java b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ContextField.java
deleted file mode 100644
index 5cb451b..0000000
--- a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/ContextField.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-
-package org.apache.plc4x.language.fields;
-
-import org.apache.plc4x.language.references.TypeReference;
-
-public interface ContextField extends Field {
-
- default String getTypeName() {
- return "context";
- }
-
- TypeReference getType();
-
- String getName();
-
- String getValueExpression();
-
-}
diff --git a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/OptionalField.java b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/OptionalField.java
index fad6cfd..7d0c60c 100644
--- a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/OptionalField.java
+++ b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/OptionalField.java
@@ -19,7 +19,6 @@
package org.apache.plc4x.language.fields;
-import org.apache.plc4x.language.references.TypeReference;
public interface OptionalField extends PropertyField {
@@ -27,10 +26,6 @@ public interface OptionalField extends PropertyField {
return "optional";
}
- TypeReference getType();
-
- String getName();
-
String getConditionExpression();
}
diff --git a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/PropertyField.java b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/PropertyField.java
index b6b83de..167e43d 100644
--- a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/PropertyField.java
+++ b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/PropertyField.java
@@ -19,5 +19,12 @@
package org.apache.plc4x.language.fields;
+import org.apache.plc4x.language.references.TypeReference;
+
public interface PropertyField extends Field {
+
+ TypeReference getType();
+
+ String getName();
+
}
diff --git a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/SimpleField.java b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/SimpleField.java
index 2ff614d..73a34f0 100644
--- a/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/SimpleField.java
+++ b/sandbox/code-generation/language-base/src/main/java/org/apache/plc4x/language/fields/SimpleField.java
@@ -19,16 +19,10 @@
package org.apache.plc4x.language.fields;
-import org.apache.plc4x.language.references.TypeReference;
-
public interface SimpleField extends PropertyField {
default String getTypeName() {
return "simple";
}
- TypeReference getType();
-
- String getName();
-
}
diff --git a/sandbox/code-generation/language-template-java/pom.xml b/sandbox/code-generation/language-template-java/pom.xml
index 60b1ca0..fdc791e 100644
--- a/sandbox/code-generation/language-template-java/pom.xml
+++ b/sandbox/code-generation/language-template-java/pom.xml
@@ -44,6 +44,11 @@
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-text</artifactId>
+ <version>1.6</version>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
diff --git a/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index d1c0ed9..744bc4c 100644
--- a/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -19,6 +19,7 @@
package org.apache.plc4x.language.java;
+import org.apache.commons.text.WordUtils;
import org.apache.plc4x.language.definitions.DiscriminatedComplexTypeDefinition;
import org.apache.plc4x.language.definitions.TypeDefinition;
import org.apache.plc4x.language.fields.ArrayField;
@@ -26,6 +27,9 @@ import org.apache.plc4x.language.references.ComplexTypeReference;
import org.apache.plc4x.language.references.SimpleTypeReference;
import org.apache.plc4x.language.references.TypeReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
public class JavaLanguageTemplateHelper {
public String getLanguageTypeNameForSpecType(TypeReference typeReference) {
@@ -253,4 +257,22 @@ public class JavaLanguageTemplateHelper {
return arrayField.getLengthType() == ArrayField.LengthType.COUNT;
}
+ public String toReadExpression(String expression) {
+ StringBuilder sb = new StringBuilder();
+ Pattern pattern = Pattern.compile("([^\\.]*)\\.([a-zA-Z\\d]+)(.*)");
+ Matcher matcher;
+ while ((matcher = pattern.matcher(expression)).matches()) {
+ String prefix = matcher.group(1);
+ String middle = matcher.group(2);
+ sb.append(prefix).append(".get").append(WordUtils.capitalize(middle)).append("()");
+ expression = matcher.group(3);
+ }
+ sb.append(expression);
+ return sb.toString();
+ }
+
+ public String toWriteExpression(String expression) {
+ return null;
+ }
+
}
diff --git a/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh b/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh
index fb45225..f167a8a 100644
--- a/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh
+++ b/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh
@@ -40,6 +40,7 @@ package ${packageName}.io;
import ${packageName}.*;
import org.apache.commons.jexl3.*;
+import org.apache.plc4x.java.utils.EvaluationHelper;
import org.apache.plc4x.java.utils.ReadBuffer;
import org.apache.plc4x.java.utils.ParseException;
import org.apache.plc4x.java.utils.WriteBuffer;
@@ -54,9 +55,37 @@ public class ${typeName}IO {
private static final Logger LOGGER = LoggerFactory.getLogger(${typeName}IO.class);
+<#assign needJexl=false>
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "array">
+ private static JexlExpression ex${field.name?cap_first};
+ <#assign needJexl=true>
+ <#break>
+ <#case "optional">
+ private static JexlExpression ex${field.name?cap_first};
+ <#assign needJexl=true>
+ <#break>
+ </#switch>
+</#list>
+<#if needJexl>
+ static {
+ JexlEngine jexl = new JexlBuilder().create();
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "array">
+ ex${field.name?cap_first} = jexl.createExpression("${field.lengthExpression}");
+ <#break>
+ <#case "optional">
+ ex${field.name?cap_first} = jexl.createExpression("${field.conditionExpression}");
+ <#break>
+</#switch>
+</#list>
+ }
+</#if>
+
public static <#if helper.isDiscriminatedType(type)>${typeName}Builder<#else>${typeName}</#if> parse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForSpecType(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
int startPos = io.getPos();
- JexlEngine jexl = new JexlBuilder().create();
JexlContext jc = new MapContext();
<#if type.parserArguments?has_content>
<#list type.parserArguments as parserArgument>
@@ -67,11 +96,10 @@ public class ${typeName}IO {
<#case "array">
// Array field
- JexlExpression ex${field.name} = jexl.createExpression("${field.lengthExpression}");
<#if field.lengthExpression?contains("curPos")>
jc.set("curPos", io.getPos() - startPos);
</#if>
- int size = Integer.valueOf(ex${field.name}.evaluate(jc).toString());
+ int size = Integer.valueOf(ex${field.name?cap_first}.evaluate(jc).toString());
<#if helper.isCountArray(field)>
${helper.getLanguageTypeNameForSpecType(field.type)}[] ${field.name} = new ${helper.getLanguageTypeNameForSpecType(field.type)}[size];
for(int i = 0; i < size; i++) {
@@ -96,13 +124,6 @@ public class ${typeName}IO {
}
jc.set("${field.name}", ${field.name});
<#break>
- <#case "context">
-
- // Context Field (Artificial value not retrieved by the input, but the context)
- JexlExpression ex${field.name?cap_first} = jexl.createExpression("${(field.valueExpression?replace("\"", "\\\"")?no_esc)}");
- ${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = (${helper.getLanguageTypeNameForSpecType(field.type)}) ex${field.name?cap_first}.evaluate(jc);
- jc.set("${field.name}", ${field.name});
- <#break>
<#case "discriminator">
// Discriminator Field (Used as input to a switch field)
@@ -119,7 +140,6 @@ public class ${typeName}IO {
// Optional Field (Can be skipped, if a given expression evaluates to false)
${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = ${helper.getNullValueForType(field.type)};
- JexlExpression ex${field.name?cap_first} = jexl.createExpression("${field.conditionExpression}");
if(ex${field.name?cap_first}.evaluate(jc) == Boolean.TRUE) {
${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io);</#if>;
}
@@ -146,10 +166,9 @@ public class ${typeName}IO {
// Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
${typeName}Builder builder = null;
<#list field.cases as case>
- JexlExpression ex${case.name} = jexl.createExpression("<#list case.discriminatorValues as discriminatorValue>(${field.discriminatorNames[discriminatorValue?index]} == ${discriminatorValue})<#sep> && </#sep></#list>");
- if(ex${case.name}.evaluate(jc) == Boolean.TRUE) {
+ if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toReadExpression(field.discriminatorNames[discriminatorValue?index])}, ${discriminatorValue})<#sep> && </#sep></#list>) {
builder = ${case.name}IO.parse(io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
- }
+ }<#sep> else </#sep>
</#list>
if (builder == null) {
throw new ParseException("Unsupported case for discriminated type");
diff --git a/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4 b/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4
index 4671814..6a866a4 100644
--- a/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4
+++ b/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4
@@ -1,4 +1,22 @@
grammar Imaginary;
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
file
: complexTypeDefinition* EOF
@@ -22,7 +40,6 @@ fieldDefinition
field
: arrayField
| constField
- | contextField
| discriminatorField
| simpleField
| implicitField
@@ -39,10 +56,6 @@ constField
: K_CONST type=dataType name=idExpression expected=expression
;
-contextField
- : K_CONTEXT type=dataType name=idExpression valueExpression=expression
- ;
-
discriminatorField
: K_DISCRIMINATOR type=dataType name=idExpression
;
@@ -112,10 +125,6 @@ innerExpression
| '"' innerExpression '"'
;
-context
- : IDENTIFIER ':' expression (',' IDENTIFIER ':' expression)*
- ;
-
COMMENT
: K_COMMENT [a-zA-Z0-9,.'":()/ \t\r\n\u000C-]*
| '//' [a-zA-Z0-9,.'":()/ \t-]*
@@ -136,13 +145,6 @@ fragment HexDigit
: [0-9a-fA-F]
;
-modifier
- : K_CONST
- | K_RESERVED
- | K_IMPLICIT
- | K_EMBEDDED
- ;
-
arrayType
: K_COUNT
| K_LENGTH
diff --git a/sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java b/sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java
index be438b5..001888c 100644
--- a/sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java
+++ b/sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/parser/MessageFormatListener.java
@@ -111,15 +111,6 @@ public class MessageFormatListener extends ImaginaryBaseListener {
}
@Override
- public void enterContextField(ImaginaryParser.ContextFieldContext ctx) {
- SimpleTypeReference type = getSimpleTypeReference(ctx.type);
- String name = ctx.name.id.getText();
- String valueExpression = ctx.valueExpression.expr.getText();
- Field field = new DefaultContextField(type, name, valueExpression);
- parserContexts.peek().add(field);
- }
-
- @Override
public void enterDiscriminatorField(ImaginaryParser.DiscriminatorFieldContext ctx) {
SimpleTypeReference type = getSimpleTypeReference(ctx.type);
String name = ctx.name.id.getText();
@@ -209,6 +200,12 @@ public class MessageFormatListener extends ImaginaryBaseListener {
complexTypes.put(typeName, type);
}
+ /*@Override
+ public void exitExpression(ImaginaryParser.ExpressionContext ctx) {
+ ImaginaryParser.InnerExpressionContext expressionContext = ctx.innerExpression();
+ super.exitExpression(ctx);
+ }*/
+
private TypeReference getTypeReference(ImaginaryParser.TypeReferenceContext ctx) {
if(ctx.simpleTypeReference != null) {
SimpleTypeReference.SimpleBaseType simpleBaseType = SimpleTypeReference.SimpleBaseType.valueOf(
diff --git a/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec b/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec
index a84cdcb..66e9fe9 100644
--- a/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec
+++ b/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec
@@ -14,7 +14,7 @@
////////////////////////////////////////////////////////////////
[discriminatedType 'COTPPacket'
- [implicit uint 8 'headerLength' 'this.size - (payload.size + 1)']
+ [implicit uint 8 'headerLength' 'size - (payload.size + 1)']
[discriminator uint 8 'tpduCode']
[typeSwitch 'tpduCode'
['0xF0' COTPPacketData
diff --git a/sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/model/fields/DefaultContextField.java b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/EvaluationHelper.java
similarity index 50%
rename from sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/model/fields/DefaultContextField.java
rename to sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/EvaluationHelper.java
index f9ad5c8..8e62d79 100644
--- a/sandbox/code-generation/plc4x-maven-plugin/src/main/java/org/apache/plc4x/plugins/codegenerator/model/fields/DefaultContextField.java
+++ b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/EvaluationHelper.java
@@ -17,37 +17,37 @@
under the License.
*/
-package org.apache.plc4x.plugins.codegenerator.model.fields;
+package org.apache.plc4x.java.utils;
-import org.apache.plc4x.language.fields.ContextField;
-import org.apache.plc4x.language.references.TypeReference;
+public class EvaluationHelper {
-public class DefaultContextField implements ContextField {
-
- private final TypeReference type;
- private final String name;
- private final String valueExpression;
+ public static boolean equals(Object val1, Object val2) {
+ if(val1 instanceof Number && val2 instanceof Number) {
+ Number number1 = (Number) val1;
+ Number number2 = (Number) val2;
+ return number1.doubleValue() == number2.doubleValue();
+ }
+ return false;
+ }
- public DefaultContextField(TypeReference type, String name, String valueExpression) {
- this.type = type;
- this.name = name;
- this.valueExpression = valueExpression;
+ public static boolean notEquals(Object val1, Object val2) {
+ return true;
}
- public TypeReference getType() {
- return type;
+ public static boolean greater(Object val1, Object val2) {
+ return true;
}
- public String getName() {
- return name;
+ public static boolean greaterEquals(Object val1, Object val2) {
+ return true;
}
- public String getValueExpression() {
- return valueExpression;
+ public static boolean smaller(Object val1, Object val2) {
+ return true;
}
- public String[] getParams() {
- return new String[0];
+ public static boolean smallerEquals(Object val1, Object val2) {
+ return true;
}
}
diff --git a/sandbox/code-generation/test-java-s7-driver/src/test/java/Test.java b/sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
similarity index 71%
rename from sandbox/code-generation/test-java-s7-driver/src/test/java/Test.java
rename to sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
index 28598d5..9ba58b3 100644
--- a/sandbox/code-generation/test-java-s7-driver/src/test/java/Test.java
+++ b/sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
@@ -22,12 +22,19 @@ import org.apache.plc4x.java.s7.TPKTPacket;
import org.apache.plc4x.java.s7.io.TPKTPacketIO;
import org.apache.plc4x.java.utils.ReadBuffer;
-public class Test {
+public class BenchmarkGeneratedS7 {
public static void main(String[] args) throws Exception {
byte[] data = Hex.decodeHex("0300006702f080320100000001005600000407120a10060001032b84000160120a10020001032b840001a0120a10010001032b840001a9120a10050001032b84000150120a10020001032b84000198120a10040001032b84000140120a10020001032b84000190");
- ReadBuffer buf = new ReadBuffer(data);
- TPKTPacket packet = TPKTPacketIO.parse(buf);
+ long start = System.currentTimeMillis();
+ int numRuns = 20000;
+ for(int i = 0; i < numRuns; i++) {
+ ReadBuffer buf = new ReadBuffer(data);
+ TPKTPacket packet = TPKTPacketIO.parse(buf);
+ }
+ long end = System.currentTimeMillis();
+ System.out.println("Parsed " + numRuns + " packets in " + (end - start) + "ms");
+ System.out.println("That's " + ((float) (end - start) / numRuns) + "ms per packet");
}
}