Skip to content

Commit

Permalink
feat: add timing command
Browse files Browse the repository at this point in the history
  • Loading branch information
Dofes committed Feb 19, 2024
1 parent a9c5269 commit bfce24c
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/levioptimize/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace lo {

struct Config {

int version = 2;
int version = 3;

struct {
ll::reflection::Dispatcher<bool, moving_block_fix::MovingBlockFix> fixMovingBlock = true;
Expand All @@ -16,6 +16,9 @@ struct Config {
ll::reflection::Dispatcher<bool, push_entity_opt::PushEntityOpt> optPushEntity = true;
ll::reflection::Dispatcher<bool, block_lookup_opt::BlockLookupOpt> optBlockLookup = true;
} features{};
struct {
bool timingCommand = true;
} commands{};
};

} // namespace lo
1 change: 1 addition & 0 deletions src/levioptimize/LeviOptimize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ bool LeviOptimize::disable(ll::plugin::NativePlugin&) { // NOLINT
mConfig.features.fixHopperItem = false;
mConfig.features.optPushEntity = false;
mConfig.features.optBlockLookup = false;
mConfig.commands.timingCommand = false;
return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/levioptimize/features/BlockLookupOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ void BlockLookupOpt::call(bool enable) {
if (!impl) impl = std::make_unique<Impl>();
initHashMap();
} else {
impl.reset();
clearHashMap();
}
};
Expand Down
28 changes: 28 additions & 0 deletions src/levioptimize/features/command/Command.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "levioptimize/LeviOptimize.h"
#include "ll/api/memory/Hook.h"
#include "ll/api/service/Bedrock.h"
#include "mc/server/commands/ServerCommands.h"
#include <string>


namespace lo::command {
extern void registerTimingCommand();

LL_STATIC_HOOK(
RegisterCommandsHook,
ll::memory::HookPriority::Normal,
ServerCommands::setupStandardServer,
void,
Minecraft& server,
std::string const& networkCommands,
std::string const& networkTestCommands,
PermissionsFile* permissionsFile
) {
origin(server, networkCommands, networkTestCommands, permissionsFile);
if (LeviOptimize::getInstance().getConfig().commands.timingCommand) {
registerTimingCommand();
}
}

static ll::memory::HookRegistrar<RegisterCommandsHook> hooks{};
} // namespace lo::command
107 changes: 107 additions & 0 deletions src/levioptimize/features/command/TimingCommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>

#include "ll/api/Logger.h"
#include "ll/api/base/StdInt.h"
#include "ll/api/command/CommandHandle.h"
#include "ll/api/command/CommandRegistrar.h"
#include "ll/api/thread/TickSyncSleep.h"
#include "mc/entity/systems/DefaultEntitySystemsCollection.h"
#include "mc/server/commands/CommandFlag.h"
#include "mc/server/commands/CommandOrigin.h"
#include "mc/server/commands/CommandOutput.h"
#include "mc/server/commands/CommandPermissionLevel.h"

#include "ll/api/Logger.h"
#include "ll/api/service/Bedrock.h"
#include "mc/world/level/Level.h"

#include "ll/api/service/Bedrock.h"
#include "mc/entity/systems/EntitySystems.h"
#include "mc/world/level/Level.h"
#include <ranges>
#include <vector>

#include "ll/api/chrono/GameChrono.h"

namespace lo::command {

void registerTimingCommand() {
static ll::Logger logger{"Timing"};
constexpr static size_t counttick = 100;
auto& cmd = ll::command::CommandRegistrar::getInstance()
.getOrCreateCommand("timing", "timing", CommandPermissionLevel::Host, CommandFlagValue::None);
cmd.overload().execute<[](CommandOrigin const&, CommandOutput&) {
auto thread = std::thread([] {
auto& system = ll::service::getLevel()->getEntitySystems();

auto& collection = system.getDefaultCollection();
{
std::lock_guard lock(collection.mTimingMutex);
system.mEnableTimingCapture = true;
logger.warn("EnableTimingCapture");
}

std::unordered_map<uint, DefaultEntitySystemsCollection::ECSTiming> timings{};
using namespace ll::chrono;
using namespace ll::chrono_literals;
ll::thread::TickSyncSleep<GameTickClock> sleeper;
auto begin = std::chrono::steady_clock::now();
for (size_t i = 0; i < counttick; i++) {
sleeper.sleepFor(1_tick);
{
std::lock_guard lock(collection.mTimingMutex);
for (auto& collectCategory : collection.mTickingSystemCategories) {
auto& tickTimings = collectCategory.mTimings;
for (size_t j = 0; j < tickTimings.size(); j++) {
auto& timing = timings[collectCategory.mSystems.at(j)];
timing.mCount += tickTimings.at(j).mCount;
timing.mMsTime += tickTimings.at(j).mMsTime;
}
}
}
}
auto end = std::chrono::steady_clock::now();
{
std::lock_guard lock(collection.mTimingMutex);
system.mEnableTimingCapture = false;
}
struct TimingData {
uint id;
double avg;
uint count;
};

std::vector<TimingData> orderdTiming;
orderdTiming.reserve(timings.size());
double allTime = 0.0;
for (auto& [systemId, timing] : timings) {
orderdTiming.emplace_back(systemId, double(timing.mMsTime) / counttick, timing.mCount);
allTime += double(timing.mMsTime) / counttick;
}

std::ranges::sort(orderdTiming, [](TimingData const& a, TimingData const& b) { return a.avg > b.avg; });

logger.warn("TPS: {:.5f}", double(counttick) / std::chrono::duration<double>(end - begin).count());
logger.warn("ECS cost {:.5f}ms per tick", allTime);

for (size_t i = 0; i < orderdTiming.size() && i < 20; i++) {
auto& data = orderdTiming[i];
logger.warn(
" | {:.5f}ms {} for {:0>3} {}",
data.avg,
double(data.count) / counttick,
data.id,
collection.mAllSystemsInfo[data.id].mName
);
}
});
thread.detach();
}>();
}
} // namespace lo::command

0 comments on commit bfce24c

Please sign in to comment.