17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 01:02:26 +01:00

perf(physics): road vehicles farther than 1 km from the camera go by one step of the physics in a frame (physics.roadlod); count what resets the switching time of the vehicles (compressor, mains, diesel, physics woken) in the debug panel

This commit is contained in:
2026-10-23 18:47:01 +02:00
parent a04efbf968
commit f17462b186
9 changed files with 117 additions and 6 deletions

View File

@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "Oerlikon_ESt.h"
#include "utilities/Globals.h"
#include "utilities/Logs.h"
#include "utilities/Timer.h"
#include "utilities/parser.h"
#include "simulation/simulation.h"
//---------------------------------------------------------------------------
@@ -3608,6 +3609,7 @@ void TMoverParameters::MainSwitch_(bool const State)
if (Mains != initialstate)
{
LastSwitchingTime = 0;
Timer::subsystem.switching.note(Timer::switching_counter::mains, this, &TypeName, &Name);
}
}
}
@@ -4363,6 +4365,10 @@ void TMoverParameters::CompressorCheck(double dt)
// jeśli została załączona to trzeba ograniczyć ponowne włączenie
LastSwitchingTime = 0;
}
if (CompressorFlag != compressorflag)
{
Timer::subsystem.switching.note(CompressorFlag ? Timer::switching_counter::compressor_on : Timer::switching_counter::compressor_off, this, &TypeName, &Name);
}
if (false == CompressorFlag)
{
@@ -7804,6 +7810,7 @@ bool TMoverParameters::dizel_Update(double dt)
dizel_ignition = false;
// TODO: split engine and main circuit state indicator in two separate flags
LastSwitchingTime = 0;
Timer::subsystem.switching.note(Timer::switching_counter::diesel, this, &TypeName, &Name);
Mains = true;
dizel_spinup = true;
enrot = std::max(enrot,
@@ -8945,6 +8952,7 @@ bool TMoverParameters::switch_physics(bool const State) // DO PRZETLUMACZENIA NA
if (true == State)
{
LastSwitchingTime = 0;
Timer::subsystem.switching.note(Timer::switching_counter::wake, this, &TypeName, &Name);
}
return true;

View File

@@ -436,6 +436,7 @@ bool driver_mode::update()
Timer::subsystem.sim_total.stop();
// the parts of the vehicle update made in the frame, none when paused
Timer::subsystem.commit_frame();
Timer::subsystem.switching.update();
Timer::subsystem.loop_audio.start();
simulation::Region->update_sounds();

View File

@@ -1515,6 +1515,7 @@ debug_panel::render_section_renderer() {
ImGui::PopStyleColor();
// the physics of the vehicles, timed in the section of the main loop
ImGui::Checkbox( "let vehicles standing still and held by their brakes sleep (physics.sleepheld)", &Global.physics_sleepheld );
ImGui::Checkbox( "one step of the physics in a frame for road vehicles farther than 1 km (physics.roadlod)", &Global.physics_roadlod );
return true;
}

View File

@@ -876,6 +876,18 @@ void opengl46_renderer::SwapBuffers()
+ ", acceleration " + std::to_string( awake.acceleration ) + ", switching " + std::to_string( awake.switching ) + ", ezt/dmu "
+ std::to_string( awake.multipleunit ) + ", neighbour " + std::to_string( awake.neighbour ),
"" );
// what resets the switching time of the vehicles, in the last second
auto const &switching { timers.switching.last() };
using source = Timer::switching_counter::source;
text += timeline(
3,
"switching per second: compressor on " + std::to_string( switching.events[ source::compressor_on ] ) + ", off "
+ std::to_string( switching.events[ source::compressor_off ] ) + ", mains " + std::to_string( switching.events[ source::mains ] ) + ", diesel "
+ std::to_string( switching.events[ source::diesel ] ) + ", physics woken " + std::to_string( switching.events[ source::wake ] ),
"" );
if( switching.busiestevents > 0 ) {
text += timeline( 3, "most often: " + switching.busiest + " (" + std::to_string( switching.busiestevents ) + ")", "" );
}
}
text += timeline( 2, "secondary steps", ms( timers.sim_secondary.average() ) );
text += timeline( 2, "trains (cabs)", ms( timers.sim_trains.average() ) );

View File

@@ -6,6 +6,7 @@
#include "stdafx.h"
#include "utilities/Globals.h"
#include "utilities/Logs.h"
#include "utilities/Timer.h"
#include "scene/scenenodegroups.h"
#include "scene/scenelayers.h"
@@ -20,6 +21,12 @@ global_settings &GetGlobalSettings() {
return settings;
}
// timers of the debug panel, which the physics counts its switching in ---------------------------------
namespace Timer {
subsystem_stopwatches subsystem; // NOSONAR the engine's extern global, utilities/Timer.h
}
// logs: quiet, unless EU07_UNIT_TESTS_LOG is set --------------------------------------------------
namespace {

View File

@@ -485,6 +485,12 @@ bool global_settings::ConfigParseSimulation(cParser& Parser, const std::string&
return true;
}
if (token == "physics.roadlod")
{
ParseOne(Parser, physics_roadlod);
return true;
}
if (token == "enabletraction")
{
ParseOne(Parser, bEnableTraction);
@@ -1894,6 +1900,7 @@ global_settings::export_as_text( std::ostream &Output ) const {
export_as_text( Output, "physicslog", WriteLogFlag );
export_as_text( Output, "fullphysics", FullPhysics );
export_as_text( Output, "physics.sleepheld", physics_sleepheld );
export_as_text( Output, "physics.roadlod", physics_roadlod );
export_as_text( Output, "debuglog", iWriteLogEnabled );
export_as_text( Output, "multiplelogs", MultipleLogs );
export_as_text( Output, "showsystemconsole", ShowSystemConsole );

View File

@@ -115,6 +115,7 @@ struct global_settings {
std::string Period{}; // time of the day, based on sun position
bool FullPhysics{ true }; // full calculations performed for each simulation step
bool physics_sleepheld{ true }; // vehicles standing still and held by their brakes let their physics sleep, see TMoverParameters::accelerating()
bool physics_roadlod{ true }; // road vehicles far from the camera go by one step of the physics in a frame, see vehicle_table::update()
bool bnewAirCouplers{ true };
float fMoveLight{ 0.f }; // numer dnia w roku albo -1
bool FakeLight{ false }; // toggle between fixed and dynamic daylight

View File

@@ -9,6 +9,11 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include <array>
#include <chrono>
#include <string>
#include <unordered_map>
namespace Timer {
double GetTime();
@@ -79,6 +84,63 @@ private:
float m_accumulator { 0.f };
};
// what resets TMoverParameters::LastSwitchingTime, which keeps the physics of a vehicle on for 5 s: counted over a second,
// with the vehicle which did it most often, for the debug panel
class switching_counter {
public:
enum source : std::size_t {
compressor_on = 0,
compressor_off,
mains,
diesel,
wake, // switch_physics( true ) of a vehicle whose physics was off
count
};
struct result {
std::array<unsigned int, source::count> events {};
std::string busiest; // type and name of the vehicle with the most events
unsigned int busiestevents { 0 };
};
// Owner: the vehicle, Label: its type and name, read only when the second ends
void
note( source const Source, void const *Owner, std::string const *Type, std::string const *Name ) {
++m_events[ Source ];
auto &owner { m_owners[ Owner ] };
++owner.events;
owner.type = Type;
owner.name = Name; }
// ends the second when it's over. to be called once a frame, while the vehicles noted in it still exist
void
update() {
auto const now { std::chrono::steady_clock::now() };
if( now - m_start < std::chrono::seconds( 1 ) ) { return; }
m_last = {};
m_last.events = m_events;
for( auto const &owner : m_owners ) {
if( owner.second.events > m_last.busiestevents ) {
m_last.busiestevents = owner.second.events;
m_last.busiest = ( owner.second.type ? *owner.second.type : std::string{} ) + " " + ( owner.second.name ? *owner.second.name : std::string{} ); } }
m_events = {};
m_owners.clear();
m_start = now; }
// of the last whole second
result const &
last() const {
return m_last; }
private:
struct owner_data {
unsigned int events { 0 };
std::string const *type { nullptr };
std::string const *name { nullptr };
};
std::chrono::time_point<std::chrono::steady_clock> m_start { std::chrono::steady_clock::now() };
std::array<unsigned int, source::count> m_events {};
std::unordered_map<void const *, owner_data> m_owners;
result m_last;
};
struct subsystem_stopwatches {
stopwatch gfx_total;
stopwatch gfx_color;
@@ -139,6 +201,7 @@ struct subsystem_stopwatches {
} awake;
};
vehicle_counts vehicles; // of the frame under way
switching_counter switching;
vehicle_counts vehicleslast; // of the last frame
// ends the frame of the frame_stopwatches and of the counts
void

View File

@@ -8620,12 +8620,17 @@ vehicle_table::update( double Deltatime, int Iterationcount ) {
// kind, measured from the end of the one before it
static std::vector<std::uint8_t> kinds;
kinds.resize( m_items.size() );
// road vehicles far from the camera with nobody inside go by one step of the physics in the frame, as long as all the steps
// together (Global.physics_roadlod): their movement goes on, in coarser steps nobody is close enough to tell
static std::vector<std::uint8_t> coarse;
coarse.assign( m_items.size(), 0 );
auto const camera { Global.pCamera.Pos };
for( std::size_t index = 0; index < m_items.size(); ++index ) {
auto const *vehicle { m_items[ index ] };
auto const road { ( vehicle->MoverParameters->CategoryFlag & 2 ) != 0 };
auto const distant { glm::length2( vehicle->GetPosition() - camera ) > Timer::subsystem.VEHICLE_NEAR * Timer::subsystem.VEHICLE_NEAR };
kinds[ index ] = static_cast<std::uint8_t>( ( road ? 2 : 0 ) + ( distant ? 1 : 0 ) );
coarse[ index ] = static_cast<std::uint8_t>( Global.physics_roadlod && road && distant && ( false == vehicle->MechInside ) && ( Iterationcount > 1 ) );
if( false == vehicle->bEnabled ) { continue; }
++counts.kind[ kinds[ index ] ];
auto const *mover { vehicle->MoverParameters };
@@ -8680,34 +8685,40 @@ vehicle_table::update( double Deltatime, int Iterationcount ) {
for( int iteration = 0; iteration < Iterationcount - 1; ++iteration ) {
std::size_t index { 0 };
for( auto *vehicle : m_items ) {
vehicle->UpdateForce( Deltatime );
if( ( index >= coarse.size() ) || ( coarse[ index ] == 0 ) ) {
vehicle->UpdateForce( Deltatime );
}
lap( index++, Timer::subsystem.vehicles_forces_kind, mark );
}
index = 0;
for( auto *vehicle : m_items ) {
vehicle->FastUpdate( Deltatime );
if( ( index >= coarse.size() ) || ( coarse[ index ] == 0 ) ) {
vehicle->FastUpdate( Deltatime );
}
lap( index++, Timer::subsystem.vehicles_forces_kind, mark );
}
}
}
auto const totaltime { Deltatime * Iterationcount }; // całkowity czas
{
std::size_t index { 0 };
for( auto *vehicle : m_items ) {
vehicle->UpdateForce( Deltatime );
// the vehicles going by one step take it with the time of all of them
auto const coarsestep { ( index < coarse.size() ) && ( coarse[ index ] != 0 ) };
vehicle->UpdateForce( coarsestep ? totaltime : Deltatime );
lap( index++, Timer::subsystem.vehicles_forces_kind, mark );
}
}
Timer::subsystem.vehicles_forces.stop();
auto const totaltime { Deltatime * Iterationcount }; // całkowity czas
Timer::subsystem.vehicles_update.start();
{
std::size_t index { 0 };
mark = std::chrono::steady_clock::now();
for( auto *vehicle : m_items ) {
auto const coarsestep { ( index < coarse.size() ) && ( coarse[ index ] != 0 ) };
// Ra 2015-01: tylko tu przelicza sieć trakcyjną
vehicle->Update( Deltatime, totaltime );
vehicle->Update( coarsestep ? totaltime : Deltatime, totaltime );
lap( index++, Timer::subsystem.vehicles_update_kind, mark );
}
}