ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/XmlTools2/trunk/xmlcustomcode.cpp
(Generate patch)

Comparing XmlTools2/trunk/xmlcustomcode.cpp (file contents):
Revision 1055 by s10k, Thu Mar 6 16:40:35 2014 UTC vs.
Revision 1056 by s10k, Sat Oct 29 22:52:03 2016 UTC

# Line 9 | Line 9 | QScriptValue echo(QScriptContext *contex
9      return "";
10   }
11  
12 < XmlCustomCode::XmlCustomCode(): numThreads(omp_get_num_procs()*2)
12 > XmlCustomCode::XmlCustomCode(): numThreads(QThread::idealThreadCount())
13   {
14 +    myThreadPool.setMaxThreadCount(numThreads);
15 +    myThreadPool.setExpiryTimeout(-1); // don't let threads expire
16 +
17      // create individual thread script engines
18 <    this->scriptEngines.reserve(this->numThreads);
16 <    this->jsFunctions.reserve(this->numThreads);
17 <    this->getXmlDataFunctions.reserve(this->numThreads);
18 <    this->setXmlDataFunctions.reserve(this->numThreads);
18 >    this->jsScriptEngines.reserve(this->numThreads);
19  
20      QString jsxmlString;
21      QFile jsxmlfile(":/resources/libs/jsxml.js");
# Line 25 | Line 25 | XmlCustomCode::XmlCustomCode(): numThrea
25      jsxmlString=QTextStream(&jsxmlfile).readAll();
26  
27      for(int i=0; i<this->numThreads; i++){
28 <        this->scriptEngines.append(new QScriptEngine());
29 <        this->jsFunctions.append(new QScriptValue());
28 >
29 >        jsCustomCodeEngine e;
30 >
31 >        e.scriptEngine = new QScriptEngine();
32 >        e.jsFunction = new QScriptValue();
33  
34          // main needs to be called so the user code is evaluated
35          // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
36          // Note the () around the function
37 <        this->getXmlDataFunctions.append(new QScriptValue(this->scriptEngines.at(i)->evaluate("(function getXmlData() { return $xmlData; })")));
38 <        this->setXmlDataFunctions.append(new QScriptValue(this->scriptEngines.at(i)->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })")));
37 >        e.getXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function getXmlData() { return $xmlData; })"));
38 >        e.setXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })"));
39 >        e.isAvailable = true;
40  
41          // Add echo function so user can debug the code
42 <        QScriptValue echoFunction = this->scriptEngines.at(i)->newFunction(echo);
43 <        this->scriptEngines.at(i)->globalObject().setProperty("echo", echoFunction);
42 >        QScriptValue echoFunction = e.scriptEngine->newFunction(echo);
43 >        e.scriptEngine->globalObject().setProperty("echo", echoFunction);
44  
45          // Add the js library for XmlEditing
46 <        this->scriptEngines.at(i)->evaluate(jsxmlString);
46 >        e.scriptEngine->evaluate(jsxmlString);
47 >
48 >        this->jsScriptEngines.append(e);
49      }
50   }
51  
# Line 56 | Line 62 | void XmlCustomCode::executeCustomCode(co
62  
63      // Reconstruct script functions
64      for(int i=0; i<this->numThreads; i++){
65 <        *this->jsFunctions[i]=this->scriptEngines.at(i)->evaluate("(function main() {"+jsString+"})");
65 >        *(jsScriptEngines[i].jsFunction) = jsScriptEngines.at(i).scriptEngine->evaluate("(function main() {"+jsString+"})");
66      }
67  
68      QString currXmlFileString;
# Line 65 | Line 71 | void XmlCustomCode::executeCustomCode(co
71      double elapsed_secs=0; // elapsed seconds that a user script took
72      clock_t begin; // seconds that a script started
73  
74 <    // Single tread if small number of files
75 <    if(filesToProcess.size()<CUSTOM_FILES_PER_THREAD){
74 >    // Single tread if small number of files or number of threads = 1
75 >    if(filesToProcess.size()<=CUSTOM_FILES_PER_THREAD || numThreads == 1){
76 >
77 >        jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
78 >
79          // Process all XmlFiles
80          for(int i=0; i<filesToProcess.size(); i++){
81 <
82 <            customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines.at(0),begin,elapsed_secs,engineResult,
74 <                                *this->jsFunctions.at(0),*this->getXmlDataFunctions.at(0),*this->setXmlDataFunctions.at(0),backupsEnabled,verboseEnabled);
81 >            customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult,
82 >                                *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
83          }
84      }
85      else{ // Multithread if there are many files
86          // Process all XmlFiles
79 #pragma omp parallel for num_threads(this->numThreads) schedule(dynamic)
80        for(int i=0; i<filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD){
81
82            const int tid=omp_get_thread_num();
87  
88 <            QString currXmlFileStringThread;
88 >        QVector<QFuture<void>> executingThreads;
89  
90 <            QScriptValue engineResultThread; // variable to check for js_errors
87 <            double elapsedSecsThread=0; // elapsed seconds that a user script took
88 <            clock_t beginThread; // seconds that a script started
90 >        for(int i=0; i<filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD){
91  
92 <            customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*this->scriptEngines.at(tid),beginThread,elapsedSecsThread,engineResultThread,
93 <                                *this->jsFunctions.at(tid),*this->getXmlDataFunctions.at(tid),*this->setXmlDataFunctions.at(tid),backupsEnabled,verboseEnabled);
92 >            executingThreads <<
93 >            QtConcurrent::run(&this->myThreadPool, [=]()
94 >            {
95 >                mutexIsAvailable.lock();
96 >                jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
97 >                jsEngine.isAvailable = false;
98 >                mutexIsAvailable.unlock();
99 >
100 >                QString currXmlFileStringThread;
101 >
102 >                QScriptValue engineResultThread; // variable to check for js_errors
103 >                double elapsedSecsThread=0; // elapsed seconds that a user script took
104 >                clock_t beginThread; // seconds that a script started
105 >
106 >                customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
107 >                                    *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
108 >
109 >                customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
110 >                                    *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
111 >
112 >                customCodeUnwinding(filesToProcess.at(i+2),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
113 >                                    *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
114 >
115 >                customCodeUnwinding(filesToProcess.at(i+3),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
116 >                                    *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
117 >
118 >                mutexIsAvailable.lock();
119 >                jsEngine.isAvailable = true;
120 >                mutexIsAvailable.unlock();
121 >            });
122 >        }
123  
124 <            customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*this->scriptEngines.at(tid),beginThread,elapsedSecsThread,engineResultThread,
125 <                                *this->jsFunctions.at(tid),*this->getXmlDataFunctions.at(tid),*this->setXmlDataFunctions.at(tid),backupsEnabled,verboseEnabled);
124 >        // Wait for all threads to finish
125 >        for(QFuture<void> &f :executingThreads){
126 >            f.waitForFinished();
127          }
128  
129          if(filesToProcess.size()%CUSTOM_FILES_PER_THREAD!=0){
130  
131              int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD;
132  
133 +            jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
134 +
135              for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){
136  
137 <                customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines.at(0),begin,elapsed_secs,engineResult,
138 <                                    *this->jsFunctions.at(0),*this->getXmlDataFunctions.at(0),*this->setXmlDataFunctions.at(0),backupsEnabled,verboseEnabled);
137 >                customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult,
138 >                                    *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
139              }
140          }
141      }
# Line 112 | Line 146 | void XmlCustomCode::displayJsException(Q
146          UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
147      }
148   }
149 +
150 + XmlCustomCode::jsCustomCodeEngine& XmlCustomCode::getAvailableJsEngine(){
151 +    for(jsCustomCodeEngine &e : this->jsScriptEngines){
152 +        if(e.isAvailable){
153 +            return e;
154 +        }
155 +    }
156 +
157 +    throw std::runtime_error("Could't find an available js engine for custom command.");
158 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)