diff --git a/.gitignore b/.gitignore index 71e5fda9..66f96a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,7 @@ cmake-build-* .vscode .vs /compile_commands.json -/.cache/clangd +.cache # js node_modules diff --git a/backend/Lua/LuaEngine.cc b/backend/Lua/LuaEngine.cc index 0354f50c..30a756d6 100644 --- a/backend/Lua/LuaEngine.cc +++ b/backend/Lua/LuaEngine.cc @@ -206,19 +206,19 @@ size_t LuaEngine::globalIdCounter() { } Local LuaEngine::get(const Local& key) { - auto lua = lua_backend::currentLua(); + auto lua = lua_; auto keyString = lua_tostring(lua, key.val_); return get(keyString); } void LuaEngine::set(const Local& key, const Local& value) { - auto lua = lua_backend::currentLua(); + auto lua = lua_; auto keyString = lua_tostring(lua, key.val_); set(keyString, value); } Local LuaEngine::get(const char* key) { - auto lua = lua_backend::currentLua(); + auto lua = lua_; lua_backend::luaEnsureStack(lua, 1); lua_getglobal(lua, key); @@ -227,7 +227,7 @@ Local LuaEngine::get(const char* key) { } void LuaEngine::set(const char* key, const Local& value) { - auto lua = lua_backend::currentLua(); + auto lua = lua_; lua_backend::luaStackScope(lua, [lua, key, &value]() { lua_backend::luaEnsureStack(lua, 2); diff --git a/backend/Lua/LuaScope.cc b/backend/Lua/LuaScope.cc index df2d5e6b..4633c525 100644 --- a/backend/Lua/LuaScope.cc +++ b/backend/Lua/LuaScope.cc @@ -16,6 +16,7 @@ */ #include "LuaScope.hpp" +#include "LuaReference.hpp" #include "trait/TraitScope.h" namespace script::lua_backend { diff --git a/src/utils/MessageQueue.cc b/src/utils/MessageQueue.cc index af7c6012..6e809380 100644 --- a/src/utils/MessageQueue.cc +++ b/src/utils/MessageQueue.cc @@ -234,7 +234,16 @@ int32_t MessageQueue::postMessage(Message* msg, int64_t delayNanos) { std::deque::const_iterator MessageQueue::findInsertPositionLocked( std::chrono::nanoseconds dueTime, int32_t priority) const { - auto it = queue_.begin(); + if (queue_.empty()) { + return queue_.end(); + } + + // search backwords, since add to queue-end is the most common case + auto it = queue_.end() - 1; + while (it != queue_.begin() && (*it)->dueTime >= dueTime) { + --it; + } + // search by due-time while (it != queue_.end() && (*it)->dueTime < dueTime) { ++it; diff --git a/src/utils/MessageQueue.h b/src/utils/MessageQueue.h index 73e823f9..15c97b69 100644 --- a/src/utils/MessageQueue.h +++ b/src/utils/MessageQueue.h @@ -350,7 +350,7 @@ class MessageQueue { * \endcode * */ - template + template int32_t postMessage(const Message& message, std::chrono::duration delay = std::chrono::milliseconds(0)) { using std::chrono::duration_cast; diff --git a/test/src/ThreadPoolTest.cc b/test/src/ThreadPoolTest.cc index e804c36c..1fb8b40f 100644 --- a/test/src/ThreadPoolTest.cc +++ b/test/src/ThreadPoolTest.cc @@ -17,10 +17,10 @@ #include #include +#include #include "test.h" namespace script::utils::test { - static void handleMessage(Message& msg) { auto* i = static_cast(msg.ptr0); (*i)++; @@ -74,19 +74,21 @@ TEST(ThreadPool, MultiThreadRun) { EXPECT_EQ(max * kProducerCount, i->load()); } -TEST(ThreadPool, Benchmark) { +static constexpr auto kEnableMultiThreadTest = true; + +template +void runThreadpoolBenchmark() { + using std::chrono::duration; using std::chrono::duration_cast; using std::chrono::milliseconds; + using std::chrono::nanoseconds; using std::chrono::steady_clock; using std::chrono_literals::operator""ms; - constexpr auto kEnable = false; - constexpr auto kRunTime = 5000ms; - constexpr auto kWorkerThreads = 4; - constexpr auto kProducerThreads = 4; + constexpr auto kRunTimeMs = 1000ms; // simple benchmark - if (!kEnable) return; + if (!kEnableMultiThreadTest) return; auto start = steady_clock::now(); @@ -97,30 +99,50 @@ TEST(ThreadPool, Benchmark) { nullptr); stopMsg.ptr0 = &tp; - tp.postMessage(stopMsg, kRunTime); + tp.postMessage(stopMsg, kRunTimeMs); - for (int j = 0; j < kProducerThreads; ++j) { - std::thread([&]() { + std::array, kProducerThreads> p; + for (auto& t : p) { + t = std::make_unique([&]() { while (true) { Message msg(handleMessage, nullptr); msg.ptr0 = i.get(); - try { - tp.postMessage(msg); - } catch (std::runtime_error&) { + if (tp.postMessage(msg) == 0) { break; } } - }).detach(); + }); } tp.awaitTermination(); + for (auto& t : p) { + t->join(); + } // run time should be close to kRunTime - auto runTimeMillis = duration_cast((steady_clock::now() - start)).count(); + const auto runTimeMillis = duration_cast((steady_clock::now() - start)).count(); - std::cout << "run time:" << runTimeMillis << "ms, " << i->load() << "ops" - << " [" << i->load() * 1000 / static_cast(runTimeMillis) << " ops/S]" - << std::endl; + const auto opsPerSecond = i->load() * 1000 / runTimeMillis; + const auto nanosencodsPerOp = duration_cast>( + duration(static_cast(runTimeMillis) / i->load())); + + std::cout << kProducerThreads << "-producers " << kWorkerThreads << "-workers " + << "time:" << runTimeMillis << "ms, " << std::setw(9) << i->load() << " ops" + << " [" << std::setw(9) << opsPerSecond << " ops/s]" + << " [" << std::setw(9) << nanosencodsPerOp.count() << " ns/op]" << std::endl; } -} // namespace script::utils::test \ No newline at end of file +TEST(ThreadPool, Benchmark_1p_1w) { runThreadpoolBenchmark<1, 1>(); } + +TEST(ThreadPool, Benchmark_1p_2w) { runThreadpoolBenchmark<1, 2>(); } + +TEST(ThreadPool, Benchmark_1p_4w) { runThreadpoolBenchmark<1, 4>(); } + +TEST(ThreadPool, Benchmark_2p_1w) { runThreadpoolBenchmark<2, 1>(); } + +TEST(ThreadPool, Benchmark_4p_1w) { runThreadpoolBenchmark<4, 1>(); } + +TEST(ThreadPool, Benchmark_2p_2w) { runThreadpoolBenchmark<2, 2>(); } + +TEST(ThreadPool, Benchmark_4p_4w) { runThreadpoolBenchmark<4, 4>(); } +} // namespace script::utils::test