New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NodesetCompiler use Byte array instead of string #1621
NodesetCompiler use Byte array instead of string #1621
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! As discussed in person earlier, here some comments:
-
Now that we do not have the problem of too long strings, you can completely remove the
max_string_length
parameter -
There is still some memory problem. See here:
https://travis-ci.org/open62541/open62541/jobs/347280202#L6644
In general I think it would be better to try to avoid the additional malloc call since the data is already on the stack we can just pass it as a reference
@@ -40,7 +46,15 @@ def generateXmlElementCode(value, alloc=False, max_string_length=0): | |||
return "UA_XMLELEMENT{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length)) | |||
|
|||
def generateByteStringCode(value, alloc=False, max_string_length=0): | |||
return "UA_BYTESTRING{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length)) | |||
return "char stringArr?{}! = {};\n\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you use this cryptic ?
and !
notation and replace it later? Can't you directly use []
? Adding the byte array then has to use the correct brackets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use 4 spaces indentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alloc parameter is not used anymore, remove it from the parameters
variable.data = (UA_Byte *)UA_malloc(variable.length);\n\ | ||
memcpy(&stringArr, &variable.data, variable.length)".format(len(stringtoByteArray(value, max_string_length=max_string_length)) \ | ||
,stringtoByteArray(value, max_string_length=max_string_length),\ | ||
len(stringtoByteArray(value, max_string_length=max_string_length)) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to avoid calling stringtoByteArray three times. Just store the result before and then use the resulting value here.
return "UA_BYTESTRING_NULL" if not node.value else generateByteStringCode(re.sub(r">\s*<", "><", re.sub(r"[\r\n]+", "", node.value)), alloc=asIndirect, max_string_length=max_string_length) | ||
return prepend + "UA_BYTESTRING_NULL" if not node.value else generateByteStringCode(re.sub(r">\s*<", "><", re.sub(r"[\r\n]+", "", node.value)), | ||
alloc=asIndirect, max_string_length=max_string_length).replace("[","{").replace("]","}")\ | ||
.replace("?","[").replace("!","]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous comment, then remove the last two replace operations.
@@ -521,7 +521,7 @@ def generateNodeCode_begin(node, nodeset, max_string_length, generate_ns0, paren | |||
code.append("UA_NODEID_NULL,") | |||
code.append("(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_{}ATTRIBUTES],NULL, NULL);".format(node.__class__.__name__.upper().replace("NODE" ,""))) | |||
code.extend(codeCleanup) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to avoid changes like this
return "char stringArr?{}! = {};\n\ | ||
UA_ByteString variable;\n\ | ||
variable.length = {};\n\ | ||
variable.data = (UA_Byte *)UA_malloc(variable.length);\n\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a check if variable.data
is NULL and return UA_STATUSCODE_BADOUTOFMEMORY
.
d2d20fd
to
81d76ca
Compare
81d76ca
to
eb48fdc
Compare
@jpfr the Opc.Ua node is a huge bytestring. With this PR we improve the handling of huge bytestrings, but currently there is the following issue: The generated code looks like this: /* Opc.Ua - ns=0;i=7617 */
static UA_StatusCode function_ua_namespace0_146_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = -1;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15);
UA_ByteString *variablenode_ns_0_i_7617_variant_DataContents = UA_ByteString_new();
UA_Byte stringArr[12777] = {60, 111, 112, 99, /* ... */ , 114, 121, 62};
variablenode_ns_0_i_7617_variant_DataContents->length = 12777;
variablenode_ns_0_i_7617_variant_DataContents->data = stringArr;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7617_variant_DataContents, &UA_TYPES[UA_TYPES_BYTESTRING]);
attr.displayName = UA_LOCALIZEDTEXT("", "Opc.Ua");
attr.description = UA_LOCALIZEDTEXT("", "");
attr.writeMask = 0;
attr.userWriteMask = 0;
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,
UA_NODEID_NUMERIC(ns[0], 7617),
UA_NODEID_NUMERIC(ns[0], 93),
UA_NODEID_NUMERIC(ns[0], 47),
UA_QUALIFIEDNAME(ns[0], "Opc.Ua"),
UA_NODEID_NUMERIC(ns[0], 72),
(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_ByteString_delete(variablenode_ns_0_i_7617_variant_DataContents);
return retVal;
} As you can see Do you have a good idea, how we can avoid the allocation and just take a reference to the data which is already there maybe in a global variable? |
Is the additional complexity worth it? If we need absolute minimum resource consumption, we could implement the binary nodeset file format. We could have a special nodestore that uses zero initialization and generates node only when they are used. http://documentation.unified-automation.com/uasdkhp/1.1.1/html/md_opcua_binary_fileformat.html Rumor has the binary nodeset format will play an important role in the standard. |
Ok, then I will try to get CI green again with the current status, and skip the issue of double memory usage for the (huge) nodes. |
fixes open62541#1254 The huge strings are changed as arrays of ASCII values of each element inside for ByteArrays. And also some implementations are done due to task.
16d8225
to
5f3b475
Compare
ab9e06e
to
30c2c5b
Compare
d9e4c13
to
6bd48c8
Compare
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Due to issue #1254 : The huge strings are changed as arrays of ASCII values of each element inside for ByteArrays. And also some implementations are done due to task.
Fixes #1254