I'm trying to optimize QScriptEngine operations in one of my functions.
The function is named executeCustomJSOperation
and it executes the same JS code in multiple files. However each file needs to change a global variable named $xmlData
. The function basicaly loads a XML file to memory using the $xmlData
variable and then always apply the same javascript code (jsString
) to edit this XML file using javascript. In the end the $xmlData
variable is updated with the edited XML again.
I've got a 2.5 speedup using only an OpenMP parallel for
over the for loop that processes each XML file. But now I don't know how to proceed to improve this function speed further.
The code is the following:
// allows user to echo js variables to check them in terminal using cout
QScriptValue echo(QScriptContext *context, QScriptEngine *engine)
{
std::cout << context->argument(0).toString().toUtf8().constData() << std::endl;
return "";
}
void executeCustomJSOperation(const QString &jsString, const QStringList &filesToProcess){
QString rexmlString, jsxmlString;
QFile rexmlfile(":/resources/libs/rexml.js"); // load javascript libraries as strings to memory
QFile jsxmlfile(":/resources/libs/jsxml.js");
rexmlfile.open(QFile::ReadOnly | QFile::Text);
jsxmlfile.open(QFile::ReadOnly | QFile::Text);
rexmlString=QTextStream(&rexmlfile).readAll();
jsxmlString=QTextStream(&jsxmlfile).readAll();
// Process all XmlFiles
#pragma omp parallel for // 2.5 speedup in my pc
for(int i=0; i<filesToProcess.size(); i++){
QString currXmlFileString;
QScriptEngine engine;
QScriptValue engineResult;
// Add echo function so user can debug the code
QScriptValue echoFunction = engine.newFunction(echo);
engine.globalObject().setProperty("echo", echoFunction);
engine.evaluate(rexmlString); // load js libraries in js engine
engine.evaluate(jsxmlString);
QFile currXmlFile(filesToProcess[i]);
currXmlFileString=QTextStream(&currXmlFile).readAll();
currXmlFile.close(); // close reading
engine.globalObject().setProperty("$xmlData",currXmlFileString);
engine.evaluate("main(); function main() {"+jsString+"}"); // main function allows to use return to exit prematurely from user code
engineResult=engine.globalObject().property("$xmlData");
QTextStream(&currXmlFile) << engineResult.toString(); // retreive the modified xml by javascript and save it to the file
}
}
Do you think it is possible to optimize further this code? If you have any doubt please ask.
Why are you creating / initializing a separate QScriptEngine for each iteration? I'd suggest moving everything up to your line
engine.evaluate(jsxmlString);
to outside the for()-loop
.
True, this will make things more difficult WRT threading. Essentially you'd have to set up n worker threads, and create one script engine per thread (not per file). For starters a simple single threaded version should give you a first idea of what speedup to expect, and if that is worth the trouble.
Of course, if your JS code really is single use, only, QScriptProgram
is your only hope of optimization. Again, you'd set up a limited number of worker threads, each with its own QScriptProgram
(and one QScriptEngine
per iteration, as in your current code).