Skip to content

Commit 2d8d5e3

Browse files
committed
add HydroSystem profiling and per-component timing
- Introduce HydroComponentType and Type() in hydro force components. - Add HydroSystemProfileStats and per-component timing in HydroSystem::Evaluate. - Expose profiling enable/disable and stats via ChronoHydroCoupler and TestHydro. - Default to profiling disabled; only enabled in profile runs.
1 parent e89cabb commit 2d8d5e3

11 files changed

Lines changed: 200 additions & 14 deletions

include/hydroc/hydro_forces.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,16 @@ class TestHydro {
359359
// Hydrodynamics profiling accessors
360360
HydroProfileStats GetProfileStats() const { return profile_stats_; }
361361

362+
/**
363+
* @brief Enable or disable profiling in HydroSystem.
364+
*
365+
* When enabled, HydroSystem measures timing for each force component.
366+
* Disabled by default to avoid overhead in normal runs.
367+
*
368+
* @param enabled True to enable profiling, false to disable
369+
*/
370+
void SetProfilingEnabled(bool enabled);
371+
362372
// Compare mode: legacy debugging feature, retained for API compatibility.
363373
// No longer affects behavior since the main path now uses HydroSystem exclusively.
364374
void SetCompareMode(bool enable) { compare_mode_ = enable; }
@@ -426,6 +436,9 @@ class TestHydro {
426436
// Legacy compare mode flag: retained for API compatibility; no longer used.
427437
bool compare_mode_ = false;
428438

439+
// Profiling enable flag: stored here because chrono_coupler_ is created lazily.
440+
bool profiling_enabled_ = false;
441+
429442
// Convolution kernel preprocessing (optional)
430443
RadiationConvolutionMode convolution_mode_ = RadiationConvolutionMode::Baseline;
431444
bool rirf_processed_ready_ = false;

src/hydro/chrono/chrono_hydro_coupler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ChronoHydroCoupler::ChronoHydroCoupler(
1818
assert(!bodies_.empty());
1919
}
2020

21-
BodyForces ChronoHydroCoupler::Evaluate(double time) const {
21+
BodyForces ChronoHydroCoupler::Evaluate(double time) {
2222
// Build SystemState from Chrono bodies
2323
SystemState system_state;
2424
BuildSystemStateFromChronoBodies(bodies_, system_state);

src/hydro/chrono/chrono_hydro_coupler.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ChronoHydroCoupler {
4242
* @param time Current simulation time
4343
* @return BodyForces Total forces (one GeneralizedForce per body, 6 DOF each)
4444
*/
45-
BodyForces Evaluate(double time) const;
45+
BodyForces Evaluate(double time);
4646

4747
/**
4848
* @brief Apply forces to Chrono bodies.
@@ -53,6 +53,26 @@ class ChronoHydroCoupler {
5353
*/
5454
void ApplyForcesToChrono(const BodyForces& forces);
5555

56+
/**
57+
* @brief Get profiling statistics from HydroSystem.
58+
*
59+
* Returns cumulative timing and call counts for each component type.
60+
*
61+
* @return HydroSystemProfileStats Profiling statistics
62+
*/
63+
HydroSystemProfileStats GetProfileStats() const {
64+
return hydro_system_->GetProfileStats();
65+
}
66+
67+
/**
68+
* @brief Enable or disable profiling in HydroSystem.
69+
*
70+
* @param enabled True to enable profiling, false to disable
71+
*/
72+
void SetProfilingEnabled(bool enabled) {
73+
hydro_system_->SetProfilingEnabled(enabled);
74+
}
75+
5676
private:
5777
std::shared_ptr<HydroSystem> hydro_system_;
5878
std::vector<std::shared_ptr<chrono::ChBody>> bodies_;

src/hydro/core/hydro_force_component.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010

1111
namespace hydrochrono::hydro {
1212

13+
/**
14+
* @brief Identifies the type of a hydrodynamic force component.
15+
*
16+
* Used for profiling to categorize execution time by component type.
17+
*/
18+
enum class HydroComponentType {
19+
Hydrostatics, ///< Hydrostatic restoring forces and buoyancy
20+
Radiation, ///< Radiation damping (RIRF convolution)
21+
Excitation ///< Wave excitation forces
22+
};
23+
1324
/**
1425
* @brief Interface for computing hydrodynamic forces.
1526
*
@@ -24,6 +35,15 @@ class IHydroForceComponent {
2435
public:
2536
virtual ~IHydroForceComponent() = default;
2637

38+
/**
39+
* @brief Get the type of this component.
40+
*
41+
* Used for profiling to categorize execution time by component type.
42+
*
43+
* @return Component type (Hydrostatics, Radiation, or Excitation)
44+
*/
45+
virtual HydroComponentType Type() const = 0;
46+
2747
/**
2848
* @brief Compute force contribution and add to inout_forces.
2949
*

src/hydro/core/hydro_system.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@
66
#include "hydro_system.h"
77

88
#include <cassert>
9+
#include <chrono>
910
#include <Eigen/Dense>
1011

1112
namespace hydrochrono::hydro {
1213

1314
HydroSystem::HydroSystem(int num_bodies,
1415
std::vector<std::unique_ptr<IHydroForceComponent>> components)
1516
: num_bodies_(num_bodies),
16-
components_(std::move(components)) {
17+
components_(std::move(components)),
18+
profile_stats_(),
19+
profiling_enabled_(false) {
1720
assert(num_bodies_ > 0);
1821
}
1922

20-
BodyForces HydroSystem::Evaluate(const SystemState& state, double time) const {
23+
BodyForces HydroSystem::Evaluate(const SystemState& state, double time) {
2124
// Initialize forces: one 6-DOF zero vector per body
2225
BodyForces forces(num_bodies_);
2326
for (int b = 0; b < num_bodies_; ++b) {
@@ -27,7 +30,31 @@ BodyForces HydroSystem::Evaluate(const SystemState& state, double time) const {
2730

2831
// Accumulate force contributions from all components
2932
for (const auto& component : components_) {
30-
component->Compute(state, time, forces);
33+
if (profiling_enabled_) {
34+
// Profiling path: measure timing for each component
35+
auto t0 = std::chrono::steady_clock::now();
36+
component->Compute(state, time, forces);
37+
auto t1 = std::chrono::steady_clock::now();
38+
double elapsed = std::chrono::duration<double>(t1 - t0).count();
39+
40+
switch (component->Type()) {
41+
case HydroComponentType::Hydrostatics:
42+
profile_stats_.hydrostatics_seconds += elapsed;
43+
profile_stats_.hydrostatics_calls++;
44+
break;
45+
case HydroComponentType::Radiation:
46+
profile_stats_.radiation_seconds += elapsed;
47+
profile_stats_.radiation_calls++;
48+
break;
49+
case HydroComponentType::Excitation:
50+
profile_stats_.excitation_seconds += elapsed;
51+
profile_stats_.excitation_calls++;
52+
break;
53+
}
54+
} else {
55+
// Fast path: no timing overhead
56+
component->Compute(state, time, forces);
57+
}
3158
}
3259

3360
return forces;

src/hydro/core/hydro_system.h

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@
1313

1414
namespace hydrochrono::hydro {
1515

16+
/**
17+
* @brief Profiling statistics for HydroSystem components.
18+
*
19+
* Tracks cumulative execution time and call counts for each component type.
20+
*/
21+
struct HydroSystemProfileStats {
22+
double hydrostatics_seconds = 0.0;
23+
double radiation_seconds = 0.0;
24+
double excitation_seconds = 0.0;
25+
int hydrostatics_calls = 0;
26+
int radiation_calls = 0;
27+
int excitation_calls = 0;
28+
29+
/// Reset all counters to zero
30+
void Reset() {
31+
hydrostatics_seconds = radiation_seconds = excitation_seconds = 0.0;
32+
hydrostatics_calls = radiation_calls = excitation_calls = 0;
33+
}
34+
};
35+
1636
/**
1737
* @brief HydroSystem: orchestrates force components to compute total forces.
1838
*
@@ -36,12 +56,13 @@ class HydroSystem {
3656
*
3757
* Computes force contributions from all components for the given
3858
* system state and time, accumulating them into a single result.
59+
* Also updates profiling statistics for each component type.
3960
*
4061
* @param state Current system state (positions, velocities for all bodies)
4162
* @param time Current simulation time
4263
* @return BodyForces Total forces (one GeneralizedForce per body, 6 DOF each)
4364
*/
44-
BodyForces Evaluate(const SystemState& state, double time) const;
65+
BodyForces Evaluate(const SystemState& state, double time);
4566

4667
/**
4768
* @brief Get number of bodies in the system.
@@ -50,9 +71,43 @@ class HydroSystem {
5071
*/
5172
int num_bodies() const { return num_bodies_; }
5273

74+
/**
75+
* @brief Get profiling statistics.
76+
*
77+
* Returns cumulative timing and call counts for each component type.
78+
*
79+
* @return HydroSystemProfileStats Profiling statistics
80+
*/
81+
HydroSystemProfileStats GetProfileStats() const { return profile_stats_; }
82+
83+
/**
84+
* @brief Reset profiling statistics.
85+
*
86+
* Clears all timing and call counts.
87+
*/
88+
void ResetProfileStats() { profile_stats_.Reset(); }
89+
90+
/**
91+
* @brief Enable or disable profiling.
92+
*
93+
* When disabled (default), Evaluate() skips timing measurements.
94+
*
95+
* @param enabled True to enable profiling, false to disable
96+
*/
97+
void SetProfilingEnabled(bool enabled) { profiling_enabled_ = enabled; }
98+
99+
/**
100+
* @brief Check if profiling is enabled.
101+
*
102+
* @return True if profiling is enabled
103+
*/
104+
bool ProfilingEnabled() const { return profiling_enabled_; }
105+
53106
private:
54107
int num_bodies_;
55108
std::vector<std::unique_ptr<IHydroForceComponent>> components_;
109+
mutable HydroSystemProfileStats profile_stats_;
110+
bool profiling_enabled_ = false; ///< Profiling disabled by default
56111
};
57112

58113
} // namespace hydrochrono::hydro

src/hydro/force_components/excitation_component.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ class ExcitationComponent : public IHydroForceComponent {
2929
*/
3030
ExcitationComponent(std::shared_ptr<WaveBase> waves, int num_bodies);
3131

32+
/**
33+
* @brief Get the component type.
34+
* @return HydroComponentType::Excitation
35+
*/
36+
HydroComponentType Type() const override { return HydroComponentType::Excitation; }
37+
3238
/**
3339
* @brief Compute wave excitation force contribution.
3440
*

src/hydro/force_components/hydrostatics_component.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class HydrostaticsComponent : public IHydroForceComponent {
3939
const std::vector<double>& cb_minus_cg,
4040
const Eigen::Vector3d& gravitational_acceleration);
4141

42+
/**
43+
* @brief Get the component type.
44+
* @return HydroComponentType::Hydrostatics
45+
*/
46+
HydroComponentType Type() const override { return HydroComponentType::Hydrostatics; }
47+
4248
/**
4349
* @brief Compute hydrostatic force contribution.
4450
*

src/hydro/force_components/radiation_component.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ class RadiationComponent : public IHydroForceComponent {
5555
const TaperedDirectOptions& tapered_opts,
5656
const std::string& diagnostics_output_dir);
5757

58+
/**
59+
* @brief Get the component type.
60+
* @return HydroComponentType::Radiation
61+
*/
62+
HydroComponentType Type() const override { return HydroComponentType::Radiation; }
63+
5864
/**
5965
* @brief Compute radiation damping force contribution.
6066
*

src/hydro_forces.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,11 @@ void TestHydro::EnsureHydroSystemAndCoupler() {
552552
// Construct ChronoHydroCoupler
553553
chrono_coupler_ = std::make_unique<hydrochrono::hydro::ChronoHydroCoupler>(
554554
hydro_system_shared, bodies_);
555+
556+
// Apply deferred profiling setting (may have been set before coupler was created)
557+
if (profiling_enabled_) {
558+
chrono_coupler_->SetProfilingEnabled(true);
559+
}
555560
}
556561

557562

@@ -721,6 +726,15 @@ double TestHydro::CoordinateFuncForBody(int b, int dof_index) {
721726
// Result: total = hydrostatics - radiation + waves
722727
hydrochrono::hydro::BodyForces body_forces = chrono_coupler_->Evaluate(prev_time);
723728

729+
// Copy profiling stats from HydroSystem to TestHydro's profile_stats_
730+
auto hydro_stats = chrono_coupler_->GetProfileStats();
731+
profile_stats_.hydrostatics_seconds = hydro_stats.hydrostatics_seconds;
732+
profile_stats_.hydrostatics_calls = hydro_stats.hydrostatics_calls;
733+
profile_stats_.radiation_seconds = hydro_stats.radiation_seconds;
734+
profile_stats_.radiation_calls = hydro_stats.radiation_calls;
735+
profile_stats_.waves_seconds = hydro_stats.excitation_seconds; // excitation == waves
736+
profile_stats_.waves_calls = hydro_stats.excitation_calls;
737+
724738
// Flatten BodyForces into total_force_ (legacy flat 6N format)
725739
std::fill(total_force_.begin(), total_force_.end(), 0.0);
726740
for (int body_idx = 0; body_idx < num_bodies_; ++body_idx) {
@@ -740,4 +754,11 @@ double TestHydro::CoordinateFuncForBody(int b, int dof_index) {
740754
}
741755

742756
return total_force_[body_num_offset + dof_index];
757+
}
758+
759+
void TestHydro::SetProfilingEnabled(bool enabled) {
760+
profiling_enabled_ = enabled;
761+
if (chrono_coupler_) {
762+
chrono_coupler_->SetProfilingEnabled(enabled);
763+
}
743764
}

0 commit comments

Comments
 (0)