mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Optimize logging overhead and character animation threading
This commit is contained in:
parent
9d647e5622
commit
85c8b5d5f4
5 changed files with 73 additions and 14 deletions
|
|
@ -5,6 +5,7 @@
|
|||
#include <sstream>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
|
||||
namespace wowee {
|
||||
namespace core {
|
||||
|
|
@ -73,6 +74,8 @@ private:
|
|||
std::mutex mutex;
|
||||
std::ofstream fileStream;
|
||||
bool fileReady = false;
|
||||
std::chrono::steady_clock::time_point lastFlushTime_{};
|
||||
uint32_t flushIntervalMs_ = 250;
|
||||
void ensureFile();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <future>
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline { class AssetManager; }
|
||||
|
|
@ -269,6 +270,8 @@ private:
|
|||
|
||||
// Maximum bones supported
|
||||
static constexpr int MAX_BONES = 240;
|
||||
uint32_t numAnimThreads_ = 1;
|
||||
std::vector<std::future<void>> animFutures_;
|
||||
|
||||
// Shadow pipeline resources
|
||||
VkPipeline shadowPipeline_ = VK_NULL_HANDLE;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace wowee {
|
||||
namespace core {
|
||||
|
|
@ -15,9 +16,17 @@ Logger& Logger::getInstance() {
|
|||
void Logger::ensureFile() {
|
||||
if (fileReady) return;
|
||||
fileReady = true;
|
||||
if (const char* flushMs = std::getenv("WOWEE_LOG_FLUSH_MS")) {
|
||||
char* end = nullptr;
|
||||
unsigned long parsed = std::strtoul(flushMs, &end, 10);
|
||||
if (end != flushMs && parsed <= 10000ul) {
|
||||
flushIntervalMs_ = static_cast<uint32_t>(parsed);
|
||||
}
|
||||
}
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories("logs", ec);
|
||||
fileStream.open("logs/wowee.log", std::ios::out | std::ios::trunc);
|
||||
lastFlushTime_ = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void Logger::log(LogLevel level, const std::string& message) {
|
||||
|
|
@ -61,7 +70,18 @@ void Logger::log(LogLevel level, const std::string& message) {
|
|||
std::cout << line.str() << '\n';
|
||||
if (fileStream.is_open()) {
|
||||
fileStream << line.str() << '\n';
|
||||
fileStream.flush();
|
||||
bool shouldFlush = (level >= LogLevel::WARNING);
|
||||
if (!shouldFlush) {
|
||||
auto nowSteady = std::chrono::steady_clock::now();
|
||||
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(nowSteady - lastFlushTime_).count();
|
||||
shouldFlush = (elapsedMs >= static_cast<long long>(flushIntervalMs_));
|
||||
if (shouldFlush) {
|
||||
lastFlushTime_ = nowSteady;
|
||||
}
|
||||
}
|
||||
if (shouldFlush) {
|
||||
fileStream.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
18
src/main.cpp
18
src/main.cpp
|
|
@ -2,6 +2,9 @@
|
|||
#include "core/logger.hpp"
|
||||
#include <exception>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <SDL2/SDL.h>
|
||||
#ifdef __linux__
|
||||
#include <X11/Xlib.h>
|
||||
|
|
@ -27,6 +30,19 @@ static void crashHandler(int sig) {
|
|||
std::raise(sig);
|
||||
}
|
||||
|
||||
static wowee::core::LogLevel readLogLevelFromEnv() {
|
||||
const char* raw = std::getenv("WOWEE_LOG_LEVEL");
|
||||
if (!raw || !*raw) return wowee::core::LogLevel::WARNING;
|
||||
std::string level(raw);
|
||||
for (char& c : level) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
if (level == "debug") return wowee::core::LogLevel::DEBUG;
|
||||
if (level == "info") return wowee::core::LogLevel::INFO;
|
||||
if (level == "warn" || level == "warning") return wowee::core::LogLevel::WARNING;
|
||||
if (level == "error") return wowee::core::LogLevel::ERROR;
|
||||
if (level == "fatal") return wowee::core::LogLevel::FATAL;
|
||||
return wowee::core::LogLevel::WARNING;
|
||||
}
|
||||
|
||||
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
|
||||
#ifdef __linux__
|
||||
g_emergencyDisplay = XOpenDisplay(nullptr);
|
||||
|
|
@ -37,7 +53,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
|
|||
std::signal(SIGTERM, crashHandler);
|
||||
std::signal(SIGINT, crashHandler);
|
||||
try {
|
||||
wowee::core::Logger::getInstance().setLogLevel(wowee::core::LogLevel::INFO);
|
||||
wowee::core::Logger::getInstance().setLogLevel(readLogLevelFromEnv());
|
||||
LOG_INFO("=== Wowee Native Client ===");
|
||||
LOG_INFO("Starting application...");
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
|
@ -94,6 +95,7 @@ bool CharacterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFram
|
|||
assetManager = am;
|
||||
perFrameLayout_ = perFrameLayout;
|
||||
renderPassOverride_ = renderPassOverride;
|
||||
numAnimThreads_ = std::max(1u, std::min(8u, std::thread::hardware_concurrency()));
|
||||
|
||||
VkDevice device = vkCtx_->getDevice();
|
||||
|
||||
|
|
@ -1138,21 +1140,32 @@ void CharacterRenderer::update(float deltaTime, const glm::vec3& cameraPos) {
|
|||
}
|
||||
}
|
||||
|
||||
int updatedCount = toUpdate.size();
|
||||
const size_t updatedCount = toUpdate.size();
|
||||
|
||||
// Thread bone calculations if we have many characters (4+)
|
||||
if (updatedCount >= 4) {
|
||||
std::vector<std::future<void>> futures;
|
||||
futures.reserve(updatedCount);
|
||||
// Thread animation updates in chunks to avoid spawning one task per instance.
|
||||
if (updatedCount >= 8 && numAnimThreads_ > 1) {
|
||||
const size_t numThreads = std::min(static_cast<size_t>(numAnimThreads_), updatedCount);
|
||||
const size_t chunkSize = updatedCount / numThreads;
|
||||
const size_t remainder = updatedCount % numThreads;
|
||||
|
||||
for (auto& instRef : toUpdate) {
|
||||
futures.push_back(std::async(std::launch::async, [this, &instRef, deltaTime]() {
|
||||
updateAnimation(instRef.get(), deltaTime);
|
||||
}));
|
||||
animFutures_.clear();
|
||||
if (animFutures_.capacity() < numThreads) {
|
||||
animFutures_.reserve(numThreads);
|
||||
}
|
||||
|
||||
// Wait for all to complete
|
||||
for (auto& f : futures) {
|
||||
size_t start = 0;
|
||||
for (size_t t = 0; t < numThreads; t++) {
|
||||
size_t end = start + chunkSize + (t < remainder ? 1 : 0);
|
||||
animFutures_.push_back(std::async(std::launch::async,
|
||||
[this, &toUpdate, start, end, deltaTime]() {
|
||||
for (size_t i = start; i < end; i++) {
|
||||
updateAnimation(toUpdate[i].get(), deltaTime);
|
||||
}
|
||||
}));
|
||||
start = end;
|
||||
}
|
||||
|
||||
for (auto& f : animFutures_) {
|
||||
f.get();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1197,7 +1210,11 @@ void CharacterRenderer::update(float deltaTime, const glm::vec3& cameraPos) {
|
|||
}
|
||||
|
||||
void CharacterRenderer::updateAnimation(CharacterInstance& instance, float deltaTime) {
|
||||
auto& model = models[instance.modelId].data;
|
||||
auto modelIt = models.find(instance.modelId);
|
||||
if (modelIt == models.end()) {
|
||||
return;
|
||||
}
|
||||
const auto& model = modelIt->second.data;
|
||||
|
||||
if (model.sequences.empty()) {
|
||||
return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue