diff options
| author | Li Jin <dragon-fly@qq.com> | 2026-07-24 17:12:21 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2026-07-24 17:12:21 +0800 |
| commit | 676da10a45af912d9226dce4cb447bf7bd923da0 (patch) | |
| tree | 1d973ebb1dd157c6db9f99c50259d5248a2d8240 /src/yue.cpp | |
| parent | c9f3a486cfdad6e134ec88b1e43717508e066796 (diff) | |
| download | yuescript-676da10a45af912d9226dce4cb447bf7bd923da0.tar.gz yuescript-676da10a45af912d9226dce4cb447bf7bd923da0.tar.bz2 yuescript-676da10a45af912d9226dce4cb447bf7bd923da0.zip | |
Optimize compiler parsing and module state
Diffstat (limited to 'src/yue.cpp')
| -rw-r--r-- | src/yue.cpp | 132 |
1 files changed, 105 insertions, 27 deletions
diff --git a/src/yue.cpp b/src/yue.cpp index 4bb4e70..8fe2aba 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
| @@ -9,18 +9,25 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| 9 | #include "yuescript/yue_compiler.h" | 9 | #include "yuescript/yue_compiler.h" |
| 10 | #include "yuescript/yue_parser.h" | 10 | #include "yuescript/yue_parser.h" |
| 11 | 11 | ||
| 12 | #include <algorithm> | ||
| 12 | #include <chrono> | 13 | #include <chrono> |
| 14 | #include <condition_variable> | ||
| 13 | #include <cstdlib> | 15 | #include <cstdlib> |
| 16 | #include <deque> | ||
| 14 | #include <fstream> | 17 | #include <fstream> |
| 18 | #include <functional> | ||
| 15 | #include <future> | 19 | #include <future> |
| 16 | #include <iomanip> | 20 | #include <iomanip> |
| 17 | #include <iostream> | 21 | #include <iostream> |
| 18 | #include <limits> | 22 | #include <limits> |
| 19 | #include <memory> | 23 | #include <memory> |
| 24 | #include <mutex> | ||
| 20 | #include <sstream> | 25 | #include <sstream> |
| 26 | #include <stdexcept> | ||
| 21 | #include <string_view> | 27 | #include <string_view> |
| 22 | #include <thread> | 28 | #include <thread> |
| 23 | #include <tuple> | 29 | #include <tuple> |
| 30 | #include <vector> | ||
| 24 | using namespace std::string_view_literals; | 31 | using namespace std::string_view_literals; |
| 25 | using namespace std::string_literals; | 32 | using namespace std::string_literals; |
| 26 | using namespace std::chrono_literals; | 33 | using namespace std::chrono_literals; |
| @@ -32,35 +39,102 @@ using namespace std::chrono_literals; | |||
| 32 | 39 | ||
| 33 | #if __has_include(<pthread.h>) | 40 | #if __has_include(<pthread.h>) |
| 34 | #include <pthread.h> | 41 | #include <pthread.h> |
| 35 | template<class R> | 42 | #endif |
| 36 | std::future<R> async(const std::function<R()>& f) { | ||
| 37 | using Fn = std::packaged_task<R()>; | ||
| 38 | auto task = new Fn(f); | ||
| 39 | std::future<R> fut = task->get_future(); | ||
| 40 | 43 | ||
| 41 | pthread_attr_t attr; | 44 | class AsyncPool { |
| 42 | pthread_attr_init(&attr); | 45 | public: |
| 43 | pthread_attr_setstacksize(&attr, 8 * 1024 * 1024); | 46 | explicit AsyncPool(size_t workerCount) { |
| 47 | workerCount = std::max<size_t>(workerCount, 1); | ||
| 48 | #if __has_include(<pthread.h>) | ||
| 49 | pthread_attr_t attr; | ||
| 50 | pthread_attr_init(&attr); | ||
| 51 | pthread_attr_setstacksize(&attr, 8 * 1024 * 1024); | ||
| 52 | _workers.reserve(workerCount); | ||
| 53 | for (size_t i = 0; i < workerCount; i++) { | ||
| 54 | pthread_t worker; | ||
| 55 | const int result = pthread_create(&worker, &attr, [](void* data) -> void* { | ||
| 56 | static_cast<AsyncPool*>(data)->run(); | ||
| 57 | return nullptr; | ||
| 58 | }, this); | ||
| 59 | if (result != 0) { | ||
| 60 | { | ||
| 61 | std::lock_guard<std::mutex> lock(_mutex); | ||
| 62 | _stopping = true; | ||
| 63 | } | ||
| 64 | _condition.notify_all(); | ||
| 65 | for (auto createdWorker : _workers) { | ||
| 66 | pthread_join(createdWorker, nullptr); | ||
| 67 | } | ||
| 68 | pthread_attr_destroy(&attr); | ||
| 69 | throw std::runtime_error("failed to create compiler worker thread"); | ||
| 70 | } | ||
| 71 | _workers.push_back(worker); | ||
| 72 | } | ||
| 73 | pthread_attr_destroy(&attr); | ||
| 74 | #else | ||
| 75 | _workers.reserve(workerCount); | ||
| 76 | for (size_t i = 0; i < workerCount; i++) { | ||
| 77 | _workers.emplace_back([this]() { run(); }); | ||
| 78 | } | ||
| 79 | #endif | ||
| 80 | } | ||
| 44 | 81 | ||
| 45 | pthread_t th; | 82 | ~AsyncPool() { |
| 46 | pthread_create(&th, &attr, | 83 | { |
| 47 | [](void* p)->void* { | 84 | std::lock_guard<std::mutex> lock(_mutex); |
| 48 | std::unique_ptr<Fn> fn(static_cast<Fn*>(p)); | 85 | _stopping = true; |
| 49 | (*fn)(); | 86 | } |
| 50 | return nullptr; | 87 | _condition.notify_all(); |
| 51 | }, | 88 | #if __has_include(<pthread.h>) |
| 52 | task); | 89 | for (auto worker : _workers) { |
| 53 | pthread_attr_destroy(&attr); | 90 | pthread_join(worker, nullptr); |
| 54 | pthread_detach(th); | 91 | } |
| 55 | return fut; | ||
| 56 | } | ||
| 57 | #else | 92 | #else |
| 58 | template<class R> | 93 | for (auto& worker : _workers) { |
| 59 | std::future<R> async(const std::function<R()>& f) { | 94 | worker.join(); |
| 60 | // fallback: ignore stack size | 95 | } |
| 61 | return std::async(std::launch::async, f); | ||
| 62 | } | ||
| 63 | #endif | 96 | #endif |
| 97 | } | ||
| 98 | |||
| 99 | template<class R> | ||
| 100 | std::future<R> async(const std::function<R()>& f) { | ||
| 101 | auto task = std::make_shared<std::packaged_task<R()>>(f); | ||
| 102 | auto result = task->get_future(); | ||
| 103 | { | ||
| 104 | std::lock_guard<std::mutex> lock(_mutex); | ||
| 105 | _tasks.emplace_back([task]() { (*task)(); }); | ||
| 106 | } | ||
| 107 | _condition.notify_one(); | ||
| 108 | return result; | ||
| 109 | } | ||
| 110 | |||
| 111 | private: | ||
| 112 | void run() { | ||
| 113 | while (true) { | ||
| 114 | std::function<void()> task; | ||
| 115 | { | ||
| 116 | std::unique_lock<std::mutex> lock(_mutex); | ||
| 117 | _condition.wait(lock, [this]() { | ||
| 118 | return _stopping || !_tasks.empty(); | ||
| 119 | }); | ||
| 120 | if (_stopping && _tasks.empty()) return; | ||
| 121 | task = std::move(_tasks.front()); | ||
| 122 | _tasks.pop_front(); | ||
| 123 | } | ||
| 124 | task(); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | std::mutex _mutex; | ||
| 129 | std::condition_variable _condition; | ||
| 130 | std::deque<std::function<void()>> _tasks; | ||
| 131 | bool _stopping = false; | ||
| 132 | #if __has_include(<pthread.h>) | ||
| 133 | std::vector<pthread_t> _workers; | ||
| 134 | #else | ||
| 135 | std::vector<std::thread> _workers; | ||
| 136 | #endif | ||
| 137 | }; | ||
| 64 | 138 | ||
| 65 | #if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) | 139 | #if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) |
| 66 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ | 140 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ |
| @@ -823,6 +897,10 @@ int main(int narg, const char** args) { | |||
| 823 | } | 897 | } |
| 824 | } | 898 | } |
| 825 | #endif // YUE_COMPILER_ONLY | 899 | #endif // YUE_COMPILER_ONLY |
| 900 | const size_t workerCount = std::min( | ||
| 901 | files.size(), | ||
| 902 | static_cast<size_t>(std::max(1u, std::thread::hardware_concurrency()))); | ||
| 903 | AsyncPool pool(workerCount); | ||
| 826 | #ifndef YUE_NO_WATCHER | 904 | #ifndef YUE_NO_WATCHER |
| 827 | if (watchFiles) { | 905 | if (watchFiles) { |
| 828 | auto fullWorkPath = fs::absolute(fs::path(workPath)).string(); | 906 | auto fullWorkPath = fs::absolute(fs::path(workPath)).string(); |
| @@ -832,7 +910,7 @@ int main(int narg, const char** args) { | |||
| 832 | } | 910 | } |
| 833 | std::list<std::future<std::string>> results; | 911 | std::list<std::future<std::string>> results; |
| 834 | for (const auto& file : files) { | 912 | for (const auto& file : files) { |
| 835 | auto task = async<std::string>([=]() { | 913 | auto task = pool.async<std::string>([=]() { |
| 836 | #ifndef YUE_COMPILER_ONLY | 914 | #ifndef YUE_COMPILER_ONLY |
| 837 | return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite); | 915 | return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite); |
| 838 | #else | 916 | #else |
| @@ -870,7 +948,7 @@ int main(int narg, const char** args) { | |||
| 870 | #endif // YUE_NO_WATCHER | 948 | #endif // YUE_NO_WATCHER |
| 871 | std::list<std::future<std::tuple<int, std::string, std::string>>> results; | 949 | std::list<std::future<std::tuple<int, std::string, std::string>>> results; |
| 872 | for (const auto& file : files) { | 950 | for (const auto& file : files) { |
| 873 | auto task = async<std::tuple<int, std::string, std::string>>([=]() { | 951 | auto task = pool.async<std::tuple<int, std::string, std::string>>([=]() { |
| 874 | std::ifstream input(file.first, std::ios::in); | 952 | std::ifstream input(file.first, std::ios::in); |
| 875 | if (input) { | 953 | if (input) { |
| 876 | std::string s( | 954 | std::string s( |
