Changeset 1056


Ignore:
Timestamp:
Oct 30, 2016, 12:52:03 AM (8 years ago)
Author:
s10k
Message:

XmlTools 2.0c - small fixes and dropped openmp in favor of Qt threads

Location:
XmlTools2/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • XmlTools2/trunk/XmlTools.pro

    r1055 r1056  
    77#QT += qml #for use new google v8 qtscript engine
    88QT += script #for use old qtscript engine
    9 QMAKE_CXXFLAGS+= -fopenmp
    10 QMAKE_LFLAGS +=  -fopenmp #OpenMP (multithreading) support
    119
    1210# More optimization
    1311QMAKE_CFLAGS_RELEASE += -O3
    1412QMAKE_CXXFLAGS_RELEASE += -O3
    15 
    16 
    1713
    1814
  • XmlTools2/trunk/readme.txt

    r1055 r1056  
    6262Change Log:
    6363----------------------------------
    64 2.0c, 28-10-2016
     642.0c, 30-10-2016
    6565-Fixed bug in --update-elements operation
    6666-Added some exception handling
    6767-Started migrating some of the source code to C++14
    6868-Upgraded pugixml to latest 1.7 version
     69-Dropped openmp since apple clang doesn't support it, using Qt threads mechanisms now
    6970----------------------------------
    70712.0b, 13-06-2014
  • XmlTools2/trunk/xmlcustomcode.cpp

    r980 r1056  
    1010}
    1111
    12 XmlCustomCode::XmlCustomCode(): numThreads(omp_get_num_procs()*2)
     12XmlCustomCode::XmlCustomCode(): numThreads(QThread::idealThreadCount())
    1313{
     14    myThreadPool.setMaxThreadCount(numThreads);
     15    myThreadPool.setExpiryTimeout(-1); // don't let threads expire
     16
    1417    // create individual thread script engines
    15     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);
    1919
    2020    QString jsxmlString;
     
    2626
    2727    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();
    3033
    3134        // main needs to be called so the user code is evaluated
    3235        // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
    3336        // Note the () around the function
    34         this->getXmlDataFunctions.append(new QScriptValue(this->scriptEngines.at(i)->evaluate("(function getXmlData() { return $xmlData; })")));
    35         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;
    3640
    3741        // Add echo function so user can debug the code
    38         QScriptValue echoFunction = this->scriptEngines.at(i)->newFunction(echo);
    39         this->scriptEngines.at(i)->globalObject().setProperty("echo", echoFunction);
     42        QScriptValue echoFunction = e.scriptEngine->newFunction(echo);
     43        e.scriptEngine->globalObject().setProperty("echo", echoFunction);
    4044
    4145        // Add the js library for XmlEditing
    42         this->scriptEngines.at(i)->evaluate(jsxmlString);
     46        e.scriptEngine->evaluate(jsxmlString);
     47
     48        this->jsScriptEngines.append(e);
    4349    }
    4450}
     
    5763    // Reconstruct script functions
    5864    for(int i=0; i<this->numThreads; i++){
    59         *this->jsFunctions[i]=this->scriptEngines.at(i)->evaluate("(function main() {"+jsString+"})");
     65        *(jsScriptEngines[i].jsFunction) = jsScriptEngines.at(i).scriptEngine->evaluate("(function main() {"+jsString+"})");
    6066    }
    6167
     
    6672    clock_t begin; // seconds that a script started
    6773
    68     // Single tread if small number of files
    69     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
    7079        // Process all XmlFiles
    7180        for(int i=0; i<filesToProcess.size(); i++){
    72 
    73             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);
    7583        }
    7684    }
    7785    else{ // Multithread if there are many files
    7886        // Process all XmlFiles
    79 #pragma omp parallel for num_threads(this->numThreads) schedule(dynamic)
     87
     88        QVector<QFuture<void>> executingThreads;
     89
    8090        for(int i=0; i<filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD){
    8191
    82             const int tid=omp_get_thread_num();
     92            executingThreads <<
     93            QtConcurrent::run(&this->myThreadPool, [=]()
     94            {
     95                mutexIsAvailable.lock();
     96                jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
     97                jsEngine.isAvailable = false;
     98                mutexIsAvailable.unlock();
    8399
    84             QString currXmlFileStringThread;
     100                QString currXmlFileStringThread;
    85101
    86             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
     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
    89105
    90             customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*this->scriptEngines.at(tid),beginThread,elapsedSecsThread,engineResultThread,
    91                                 *this->jsFunctions.at(tid),*this->getXmlDataFunctions.at(tid),*this->setXmlDataFunctions.at(tid),backupsEnabled,verboseEnabled);
     106                customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
     107                                    *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
    92108
    93             customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*this->scriptEngines.at(tid),beginThread,elapsedSecsThread,engineResultThread,
    94                                 *this->jsFunctions.at(tid),*this->getXmlDataFunctions.at(tid),*this->setXmlDataFunctions.at(tid),backupsEnabled,verboseEnabled);
     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        // Wait for all threads to finish
     125        for(QFuture<void> &f :executingThreads){
     126            f.waitForFinished();
    95127        }
    96128
     
    99131            int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD;
    100132
     133            jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
     134
    101135            for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){
    102136
    103                 customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*this->scriptEngines.at(0),begin,elapsed_secs,engineResult,
    104                                     *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);
    105139            }
    106140        }
     
    113147    }
    114148}
     149
     150XmlCustomCode::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}
  • XmlTools2/trunk/xmlcustomcode.h

    r980 r1056  
    1010#include <QCoreApplication>
    1111
     12#include <QThreadPool>
     13#include <QtConcurrent/QtConcurrent>
     14
    1215#define SLOW_SCRIPT_TIME 0.1 // if a user script takes more than 0.1 seconds to execute give a warning.
    13 #define CUSTOM_FILES_PER_THREAD 2
     16#define CUSTOM_FILES_PER_THREAD 4
    1417
    1518// Uses a singleton implementation (based on here: http://www.yolinux.com/TUTORIALS/C++Singleton.html)
     
    2225private:
    2326    static XmlCustomCode* uniqueInstance;
     27
    2428    const int numThreads;
    25     QVector<QScriptEngine*> scriptEngines;
    26     QVector<QScriptValue*> jsFunctions;
    27     QVector<QScriptValue*> getXmlDataFunctions;
    28     QVector<QScriptValue*> setXmlDataFunctions;
     29    QThreadPool myThreadPool;
     30    QMutex mutexIsAvailable;
     31
     32    struct jsCustomCodeEngine{
     33        QScriptEngine* scriptEngine;
     34        QScriptValue* jsFunction;
     35        QScriptValue* getXmlDataFunction;
     36        QScriptValue* setXmlDataFunction;
     37        bool isAvailable;
     38    };
     39
     40    QVector<jsCustomCodeEngine> jsScriptEngines;
    2941
    3042    XmlCustomCode(); // constructor is private (use getInstance)
     
    3345
    3446    void displayJsException(QScriptEngine &engine, QScriptValue &engineResult);
     47    jsCustomCodeEngine& getAvailableJsEngine();
    3548
    3649    __attribute__((always_inline)) inline void customCodeUnwinding(const QString &fileName, QString &currXmlFileString,
Note: See TracChangeset for help on using the changeset viewer.