svg_loader: applied asynchronous threads tasks for optimal performance. 39/242039/6
authorHermet Park <chuneon.park@samsung.com>
Fri, 21 Aug 2020 12:13:39 +0000 (21:13 +0900)
committerHermet Park <chuneon.park@samsung.com>
Tue, 25 Aug 2020 05:11:34 +0000 (14:11 +0900)
Change-Id: I6575a6a6302c0ae52d1256a5f79f4c080002a4aa

src/lib/tvgTaskScheduler.cpp
src/lib/tvgTaskScheduler.h
src/loaders/svg/tvgSvgLoader.cpp
src/loaders/svg/tvgSvgLoader.h
test/testSvg.cpp

index e7df53a9e8fb4a95f17806178670794ebfcecc3a..bdf6edc7d4294b6ef2384239d1ac6b3fa063bc93 100644 (file)
 namespace tvg {
 
 struct TaskQueue {
-    deque<shared_ptr<Task>>  taskDeque;
+    deque<Task*>             taskDeque;
     mutex                    mtx;
     condition_variable       ready;
     bool                     done = false;
 
-    bool tryPop(shared_ptr<Task> &task)
+    bool tryPop(Task** task)
     {
         unique_lock<mutex> lock{mtx, try_to_lock};
         if (!lock || taskDeque.empty()) return false;
-        task = move(taskDeque.front());
+        *task = taskDeque.front();
         taskDeque.pop_front();
 
         return true;
     }
 
-    bool tryPush(shared_ptr<Task> &&task)
+    bool tryPush(Task* task)
     {
         {
             unique_lock<mutex> lock{mtx, try_to_lock};
             if (!lock) return false;
-            taskDeque.push_back(move(task));
+            taskDeque.push_back(task);
         }
 
         ready.notify_one();
@@ -67,7 +67,7 @@ struct TaskQueue {
         ready.notify_all();
     }
 
-    bool pop(shared_ptr<Task> &task)
+    bool pop(Task** task)
     {
         unique_lock<mutex> lock{mtx};
 
@@ -77,17 +77,17 @@ struct TaskQueue {
 
         if (taskDeque.empty()) return false;
 
-        task = move(taskDeque.front());
+        *task = taskDeque.front();
         taskDeque.pop_front();
 
         return true;
     }
 
-    void push(shared_ptr<Task> &&task)
+    void push(Task* task)
     {
         {
             unique_lock<mutex> lock{mtx};
-            taskDeque.push_back(move(task));
+            taskDeque.push_back(task);
         }
 
         ready.notify_one();
@@ -104,9 +104,8 @@ public:
     vector<TaskQueue>              taskQueues;
     atomic<unsigned>               idx{0};
 
-    TaskSchedulerImpl(unsigned count) : taskQueues(count)
+    TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt)
     {
-        threadCnt = count;
         for (unsigned i = 0; i < threadCnt; ++i) {
             threads.emplace_back([&, i] { run(i); });
         }
@@ -120,37 +119,33 @@ public:
 
     void run(unsigned i)
     {
-        shared_ptr<Task> task;
+        Task* task;
 
         //Thread Loop
         while (true) {
             auto success = false;
-
             for (unsigned i = 0; i < threadCnt * 2; ++i) {
-                if (taskQueues[(i + i) % threadCnt].tryPop(task)) {
+                if (taskQueues[(i + i) % threadCnt].tryPop(&task)) {
                     success = true;
                     break;
                 }
             }
 
-            if (!success && !taskQueues[i].pop(task)) break;
-
+            if (!success && !taskQueues[i].pop(&task)) break;
             (*task)();
         }
     }
 
-    void request(shared_ptr<Task> task)
+    void request(Task* task)
     {
         //Async
         if (threadCnt > 0) {
             task->prepare();
             auto i = idx++;
             for (unsigned n = 0; n < threadCnt; ++n) {
-                if (taskQueues[(i + n) % threadCnt].tryPush(move(task))) return;
+                if (taskQueues[(i + n) % threadCnt].tryPush(task)) return;
             }
-
-            taskQueues[i % threadCnt].push(move(task));
-
+            taskQueues[i % threadCnt].push(task);
         //Sync
         } else {
             task->run();
@@ -181,9 +176,9 @@ void TaskScheduler::term()
 }
 
 
-void TaskScheduler::request(shared_ptr<Task> task)
+void TaskScheduler::request(Task* task)
 {
     if (inst) {
-        inst->request(move(task));
+        inst->request(task);
     }
-}
\ No newline at end of file
+}
index 4380a9cabf15014b22d440bf01a63c13914f100e..1b1cc1280444adae303c92473145b28f6c6598a6 100644 (file)
@@ -30,15 +30,17 @@ namespace tvg
 struct Task
 {
 private:
-    std::promise<void> sender;
-    std::future<void>  receiver;
+    promise<void> sender;
+    future<void>  receiver;
 
 public:
     virtual ~Task() = default;
 
     void get()
     {
-        if (receiver.valid()) receiver.get();
+        if (receiver.valid()) {
+            receiver.get();
+        }
     }
 
 protected:
@@ -53,7 +55,7 @@ private:
 
     void prepare()
     {
-        sender = std::promise<void>();
+        sender = promise<void>();
         receiver = sender.get_future();
     }
 
@@ -64,7 +66,7 @@ struct TaskScheduler
 {
     static void init(unsigned threads);
     static void term();
-    static void request(shared_ptr<Task> task);
+    static void request(Task* task);
 };
 
 }
index b174300e6d12a893c7056a59677f4359d337524e..341dc5537e84cd0424191feeaaef04694143afef 100644 (file)
@@ -2263,12 +2263,36 @@ static bool _svgLoaderParserForValidCheck(void* data, SimpleXMLType type, const
     return res;
 }
 
+
+void SvgTask::run()
+{
+    if (!simpleXmlParse(loader->content, loader->size, true, _svgLoaderParser, &(loader->loaderData))) return;
+
+    if (loader->loaderData.doc) {
+        _updateStyle(loader->loaderData.doc, nullptr);
+        auto defs = loader->loaderData.doc->node.doc.defs;
+        if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients);
+        else {
+            if (!loader->loaderData.gradients.empty()) {
+                vector<SvgStyleGradient*> gradientList;
+                for (auto gradient : loader->loaderData.gradients) {
+                    gradientList.push_back(gradient);
+                }
+                _updateGradient(loader->loaderData.doc, gradientList);
+                gradientList.clear();
+            }
+        }
+    }
+    loader->root = loader->builder.build(loader->loaderData.doc);
+};
+
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
 
-SvgLoader::SvgLoader()
+SvgLoader::SvgLoader() : task(new SvgTask)
 {
+    task->loader = this;
 }
 
 
@@ -2339,34 +2363,7 @@ bool SvgLoader::read()
 {
     if (!content || size == 0) return false;
 
-    loaderData = {vector<SvgNode*>(),
-        nullptr,
-        nullptr,
-        vector<SvgStyleGradient*>(),
-        nullptr,
-        nullptr,
-        0,
-        false};
-
-    loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser));
-
-    if (!simpleXmlParse(content, size, true, _svgLoaderParser, &loaderData)) return false;
-
-    if (loaderData.doc) {
-        _updateStyle(loaderData.doc, nullptr);
-        auto defs = loaderData.doc->node.doc.defs;
-        if (defs) _updateGradient(loaderData.doc, defs->node.defs.gradients);
-        else {
-            if (!loaderData.gradients.empty()) {
-                vector<SvgStyleGradient*> gradientList;
-                std::copy(loaderData.gradients.begin(), loaderData.gradients.end(), gradientList.begin());
-                _updateGradient(loaderData.doc, gradientList);
-                gradientList.clear();
-            }
-        }
-    }
-
-    root = builder.build(loaderData.doc);
+    TaskScheduler::request(task);
 
     return true;
 }
@@ -2374,6 +2371,12 @@ bool SvgLoader::read()
 
 bool SvgLoader::close()
 {
+    if (task) {
+        task->get();
+        delete(task);
+        task = nullptr;
+    }
+
     if (loaderData.svgParse) {
         free(loaderData.svgParse);
         loaderData.svgParse = nullptr;
@@ -2387,5 +2390,7 @@ bool SvgLoader::close()
 
 unique_ptr<Scene> SvgLoader::data()
 {
-    return move(root);
+    if (task) task->get();
+    if (root) return move(root);
+    else return nullptr;
 }
\ No newline at end of file
index e85582bf7f37fdbf26dffa03df2c746ca1e5ff5b..451583f1bc824435835a74b61c6051c27ef91b7e 100644 (file)
 #include "tvgSvgLoaderCommon.h"
 #include "tvgSvgSceneBuilder.h"
 
+class SvgLoader;
+
+struct SvgTask : Task
+{
+    SvgLoader* loader = nullptr;
+    void run() override;
+};
+
 
 class SvgLoader : public Loader
 {
-private:
+public:
     string filePath;
     const char* content = nullptr;
     uint32_t size = 0;
@@ -36,8 +44,8 @@ private:
     SvgLoaderData loaderData;
     SvgSceneBuilder builder;
     unique_ptr<Scene> root;
+    SvgTask* task = nullptr;
 
-public:
     SvgLoader();
     ~SvgLoader();
 
index ad720271bad2e4c8bcabd7d49c7cae838696643e..7e3d7753b503b04c733f4a10755373fe8c7c712f 100644 (file)
@@ -1,3 +1,4 @@
+#include <vector>
 #include "testCommon.h"
 
 /************************************************************************/
@@ -9,6 +10,8 @@
 
 static int count = 0;
 
+static std::vector<unique_ptr<tvg::Picture>> pictures;
+
 void svgDirCallback(const char* name, const char* path, void* data)
 {
     tvg::Canvas* canvas = static_cast<tvg::Canvas*>(data);
@@ -40,7 +43,7 @@ void svgDirCallback(const char* name, const char* path, void* data)
 
     picture->translate((count % NUM_PER_LINE) * SIZE - x, SIZE * (count / NUM_PER_LINE) - y);
 
-    canvas->push(move(picture));
+    pictures.push_back(move(picture));
 
     cout << "SVG: " << buf << endl;
 
@@ -59,6 +62,16 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     if (canvas->push(move(shape)) != tvg::Result::Success) return;
 
     eina_file_dir_list("./svgs", EINA_TRUE, svgDirCallback, canvas);
+
+    /* This showcase shows you asynchrounous loading of svg.
+       For this, pushing pictures at a certian sync time.
+       This means it earns the time to finish loading svg resources,
+       otherwise you can push pictures immediately. */
+    for (auto& paint : pictures) {
+        canvas->push(move(paint));
+    }
+
+    pictures.clear();
 }