Skip to content

Commit

Permalink
god
Browse files Browse the repository at this point in the history
  • Loading branch information
CCIGAMES committed Mar 2, 2024
1 parent 79afddc commit 9a98bfe
Show file tree
Hide file tree
Showing 3 changed files with 298 additions and 0 deletions.
107 changes: 107 additions & 0 deletions sonic3air-main/Oxygen/oxygenengine/source/oxygen/helper/Logging.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution.
* Copyright (C) 2017-2024 by Eukaryot
*
* Published under the GNU GPLv3 open source software license, see license.txt
* or https://www.gnu.org/licenses/gpl-3.0.en.html
*/

#include "oxygen/pch.h"
#include "oxygen/helper/Logging.h"
#include "oxygen/platform/PlatformFunctions.h"
#include "oxygen/simulation/LemonScriptRuntime.h"


namespace
{

class ErrorLogger : public rmx::ErrorHandling::LoggerInterface, public rmx::ErrorHandling::MessageBoxInterface
{
public:
std::string mCaption;

protected:
void logMessage(rmx::ErrorSeverity errorSeverity, const std::string& message) override
{
switch (errorSeverity)
{
default:
case rmx::ErrorSeverity::INFO: rmx::Logging::log(rmx::LogLevel::INFO, message); break;
case rmx::ErrorSeverity::WARNING: rmx::Logging::log(rmx::LogLevel::WARNING, message); break;
case rmx::ErrorSeverity::ERROR: rmx::Logging::log(rmx::LogLevel::ERROR, message); break;
}
}

Result showMessageBox(rmx::ErrorHandling::MessageBoxInterface::DialogType dialogType, rmx::ErrorSeverity errorSeverity, const std::string& message, const char* filename, int line) override
{
#if defined(DEBUG)
std::string name;
std::string ext;
rmx::FileIO::splitPath(filename, nullptr, &name, &ext);
std::string text = message + "\n[" + name + "." + ext + ", line " + std::to_string(line) + "]";
#else
std::string text = message;
#endif

// Check if it was caused inside a script function
{
std::string_view functionName;
std::wstring fileName;
uint32 lineNumber = 0;
std::string moduleName;
if (LemonScriptRuntime::getCurrentScriptFunction(&functionName, &fileName, &lineNumber, &moduleName))
{
text += "\n\nCaused during script execution in function '" + std::string(functionName) + "' at line " + std::to_string(lineNumber) + " of file '" + WString(fileName).toStdString() + "' in module '" + moduleName + "'.";
}
}

std::string caption = (errorSeverity == rmx::ErrorSeverity::ERROR) ? "Error" : "Warning";
if (!mCaption.empty())
{
caption = mCaption + " - " + caption;
}

if (rmx::ErrorHandling::isDebuggerAttached())
{
text += "\n\nBreak here?";
}

PlatformFunctions::DialogButtons dialogButtons = PlatformFunctions::DialogButtons::OK_CANCEL;
switch (dialogType)
{
case rmx::ErrorHandling::MessageBoxInterface::DialogType::ACCEPT_ONLY: dialogButtons = PlatformFunctions::DialogButtons::OK; break;
case rmx::ErrorHandling::MessageBoxInterface::DialogType::ACCEPT_OR_CANCEL: dialogButtons = PlatformFunctions::DialogButtons::OK_CANCEL; break;
case rmx::ErrorHandling::MessageBoxInterface::DialogType::ALL_OPTIONS: dialogButtons = PlatformFunctions::DialogButtons::YES_NO_CANCEL; break;
}
const PlatformFunctions::DialogResult result = PlatformFunctions::showDialogBox(errorSeverity, dialogButtons, caption, text);
return (result == PlatformFunctions::DialogResult::CANCEL) ? Result::IGNORE : (result == PlatformFunctions::DialogResult::OK) ? Result::ACCEPT : Result::ABORT;
}
};

static ErrorLogger mErrorLogger;
}



namespace oxygen
{
void Logging::startup(const std::wstring& filename)
{
rmx::Logging::addLogger(*new rmx::StdCoutLogger());
rmx::Logging::addLogger(*new rmx::FileLogger(filename, true));

// Register as logger and message box callback for rmx error handling
rmx::ErrorHandling::mLogger = &mErrorLogger;
rmx::ErrorHandling::mMessageBoxImplementation = &mErrorLogger;
}

void Logging::shutdown()
{
rmx::Logging::clear();
}

void Logging::setAssertBreakCaption(const std::string& caption)
{
::mErrorLogger.mCaption = caption;
}
}
23 changes: 23 additions & 0 deletions sonic3air-main/Oxygen/oxygenengine/source/oxygen/helper/Logging.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution.
* Copyright (C) 2017-2024 by Eukaryot
*
* Published under the GNU GPLv3 open source software license, see license.txt
* or https://www.gnu.org/licenses/gpl-3.0.en.html
*/

#pragma once

#include <rmxbase.h>


namespace oxygen
{
class Logging
{
public:
static void startup(const std::wstring& filename);
static void shutdown();
static void setAssertBreakCaption(const std::string& caption);
};
}
168 changes: 168 additions & 0 deletions sonic3air-main/Oxygen/oxygenengine/source/oxygen/helper/Profiling.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution.
* Copyright (C) 2017-2024 by Eukaryot
*
* Published under the GNU GPLv3 open source software license, see license.txt
* or https://www.gnu.org/licenses/gpl-3.0.en.html
*/

#include "oxygen/pch.h"
#include "oxygen/helper/Profiling.h"


namespace profiling
{
Profiling::Region mRootRegion;
std::map<uint16, Profiling::Region> mRegionsByID; // Does not contain root region
std::vector<Profiling::Region*> mAllRegions;
std::vector<Profiling::Region*> mRegionStack;
Profiling::AdditionalData mAdditionalData;
int mAccumulatedFrames = 0;

Profiling::Region* getRegionByID(uint16 id)
{
const auto it = mRegionsByID.find(id);
return (it == mRegionsByID.end()) ? nullptr : &it->second;
}
}

using namespace profiling;


void Profiling::startup()
{
// No need to do things twice
if (!mAllRegions.empty())
return;

mRootRegion.mName = "root";
mAllRegions.push_back(&mRootRegion);
mRegionStack.push_back(&mRootRegion);
}

void Profiling::registerRegion(uint16 id, const char* name, const Color& color)
{
RMX_ASSERT(mRegionsByID.count(id) == 0, "Profiling region with id " << id << " registered twice, second time with name '" << name << "'");

Profiling::Region& region = mRegionsByID[id];
region.mName = name;
region.mColor = color;
mAllRegions.push_back(&region);
}

void Profiling::pushRegion(uint16 id)
{
Region* region = getRegionByID(id);
RMX_ASSERT(nullptr != region, "Profiling region with id " << id << " not found");
RMX_ASSERT(!region->mOnStack, "Profiling region with name '" << region->mName << "' is already on the stack");
RMX_ASSERT(mRegionStack.size() >= 1, "Profiling region stack got emptied before");

mRegionStack.push_back(region);
region->mOnStack = true;
region->mTimer.resumeTiming();

if (nullptr == region->mParent)
{
region->mParent = mRegionStack[mRegionStack.size() - 2];
region->mParent->mChildren.push_back(region);
}
else
{
RMX_ASSERT(region->mParent == mRegionStack[mRegionStack.size() - 2], "Profiling region '" << region->mName << "' has different parents on the stack: '" << region->mParent->mName << "' and '" << mRegionStack[mRegionStack.size() - 2] << "'");
}
}

void Profiling::popRegion(uint16 id)
{
Region* region = getRegionByID(id);
RMX_ASSERT(nullptr != region, "Profiling region with id " << id << " not found");
RMX_ASSERT(mRegionStack.size() >= 2, "Can't pop another profiling region from stack, that would remove the root region");
RMX_ASSERT(mRegionStack.back() == region, "Profiling region to be popped must be top of stack");

mRegionStack.pop_back();
region->mOnStack = false;
region->mTimer.pauseTiming();
}

void Profiling::nextFrame(int simulationFrameNumber)
{
RMX_ASSERT(mRegionStack.size() == 1, "Profiling region stack must only contain the root on frame end");

for (Region* region : mAllRegions)
{
const double lastTime = region->mTimer.getAccumulatedSecondsAndRestart(); // For root timer (which is usually still running), this will perform a stop and immediate restart
while (region->mFrameTimes.size() >= MAX_FRAMES)
region->mFrameTimes.pop_front();
region->mFrameTimes.emplace_back();
Region::Frame& frame = region->mFrameTimes.back();
frame.mInclusiveTime = lastTime;
frame.mExclusiveTime = lastTime;
region->mAccumulatedTime += lastTime;
region->mTimer.resetTiming();
}
for (Region* region : mAllRegions)
{
if (nullptr != region->mParent)
{
region->mParent->mFrameTimes.back().mExclusiveTime -= region->mFrameTimes.back().mExclusiveTime;
}
}
mRootRegion.mTimer.resumeTiming(); // Needed for first frame to start timing

static const PerFrameData dummy;
const PerFrameData& oldData = mAdditionalData.mFrames.empty() ? dummy : mAdditionalData.mFrames.back();
while (mAdditionalData.mFrames.size() >= MAX_FRAMES)
mAdditionalData.mFrames.pop_front();
mAdditionalData.mFrames.emplace_back();
PerFrameData& data = mAdditionalData.mFrames.back();
data.mSimulationFrameNumber = simulationFrameNumber;
data.mNumSimulationFrames = simulationFrameNumber - oldData.mSimulationFrameNumber;
mAdditionalData.mAccumulatedSimulationFrames += data.mNumSimulationFrames;

++mAccumulatedFrames;
if (mAccumulatedFrames >= 30 || mRootRegion.mAccumulatedTime >= 1.0)
{
mAdditionalData.mAverageSimulationsPerSecond = (float)mAdditionalData.mAccumulatedSimulationFrames / (float)mRootRegion.mAccumulatedTime;
mAdditionalData.mAccumulatedSimulationFrames = 0;

while (mAdditionalData.mSimulationsPerSecondDeque.size() >= 10)
mAdditionalData.mSimulationsPerSecondDeque.pop_front();
mAdditionalData.mSimulationsPerSecondDeque.push_back(mAdditionalData.mAverageSimulationsPerSecond);
mAdditionalData.mSmoothedSimulationsPerSecond = 0.0f;
for (float value : mAdditionalData.mSimulationsPerSecondDeque)
mAdditionalData.mSmoothedSimulationsPerSecond += value;
mAdditionalData.mSmoothedSimulationsPerSecond /= (float)std::max<size_t>(1, mAdditionalData.mSimulationsPerSecondDeque.size());

for (Region* region : mAllRegions)
{
region->mAverageTime = region->mAccumulatedTime / (float)mAccumulatedFrames;
region->mAccumulatedTime = 0.0;
}
mAccumulatedFrames = 0;
}
}

Profiling::Region& Profiling::getRootRegion()
{
return mRootRegion;
}

void Profiling::listRegionsRecursive(std::vector<std::pair<Region*, int>>& outRegions)
{
outRegions.clear();
listRegionsRecursiveInternal(outRegions, mRootRegion, 1);
}

Profiling::AdditionalData& Profiling::getAdditionalData()
{
return mAdditionalData;
}

void Profiling::listRegionsRecursiveInternal(std::vector<std::pair<Region*, int>>& outRegions, Region& parent, int level)
{
for (Region* child : parent.mChildren)
{
outRegions.emplace_back(child, level);
listRegionsRecursiveInternal(outRegions, *child, level + 1);
}
}

0 comments on commit 9a98bfe

Please sign in to comment.