@@ -292,6 +292,7 @@ int RunHydroChronoFromYAML(int argc, char* argv[]) {
292292 bool enable_logging = false ; // default: only log when --log is supplied
293293 bool debug_mode = false ;
294294 bool trace_mode = false ;
295+ bool profile_mode = false ;
295296
296297 // Parse command line arguments
297298 for (int i = 1 ; i < argc; ++i) {
@@ -311,6 +312,8 @@ int RunHydroChronoFromYAML(int argc, char* argv[]) {
311312 } else if (arg == " --trace" ) {
312313 trace_mode = true ;
313314 debug_mode = true ; // trace implies debug
315+ } else if (arg == " --profile" ) {
316+ profile_mode = true ;
314317 } else if (arg == " --nobanner" ) {
315318 // Optional: could disable banner; currently handled by enable_cli_output
316319 } else if (arg == " --quiet" ) {
@@ -655,7 +658,14 @@ int RunHydroChronoFromYAML(int argc, char* argv[]) {
655658 // ---------------------------------------------------------------------
656659 // 7. Run simulation
657660 // ---------------------------------------------------------------------
658- auto start_time = std::chrono::steady_clock::now ();
661+ auto wall_start = std::chrono::steady_clock::now ();
662+ // Profiling accumulators
663+ std::chrono::steady_clock::time_point t;
664+ double prof_setup_seconds = 0.0 ;
665+ double prof_loop_seconds = 0.0 ;
666+ double prof_export_seconds = 0.0 ;
667+ double prof_other_seconds = 0.0 ;
668+ auto prof_section_start = std::chrono::steady_clock::now (); // setup section start
659669
660670
661671 // Log simulation loop entry
@@ -680,10 +690,14 @@ int RunHydroChronoFromYAML(int argc, char* argv[]) {
680690 while (system->GetChTime () < end_time_bound) {
681691 double current_time = system->GetChTime ();
682692 try {
693+ if (profile_mode) { t = std::chrono::steady_clock::now (); }
683694 system->DoStepDynamics (loop_dt);
695+ if (profile_mode) { prof_loop_seconds += std::chrono::duration_cast<std::chrono::duration<double >>(std::chrono::steady_clock::now () - t).count (); }
684696 step_count++;
685697 if (exporter) {
698+ if (profile_mode) { t = std::chrono::steady_clock::now (); }
686699 exporter->RecordStep (system.get ());
700+ if (profile_mode) { prof_export_seconds += std::chrono::duration_cast<std::chrono::duration<double >>(std::chrono::steady_clock::now () - t).count (); }
687701 }
688702 previous_time = current_time;
689703 } catch (const std::exception& e) {
@@ -734,10 +748,14 @@ int RunHydroChronoFromYAML(int argc, char* argv[]) {
734748
735749 try {
736750 // 🧯 Scoped try/catch around DoStepDynamics
751+ if (profile_mode) { t = std::chrono::steady_clock::now (); }
737752 system->DoStepDynamics (loop_dt);
753+ if (profile_mode) { prof_loop_seconds += std::chrono::duration_cast<std::chrono::duration<double >>(std::chrono::steady_clock::now () - t).count (); }
738754 step_count++;
739755 if (exporter) {
756+ if (profile_mode) { t = std::chrono::steady_clock::now (); }
740757 exporter->RecordStep (system.get ());
758+ if (profile_mode) { prof_export_seconds += std::chrono::duration_cast<std::chrono::duration<double >>(std::chrono::steady_clock::now () - t).count (); }
741759 }
742760
743761 // 🧯 After first step - check if simulation time advanced
@@ -875,21 +893,54 @@ int RunHydroChronoFromYAML(int argc, char* argv[]) {
875893 break ; // Exit simulation loop on exception
876894 }
877895 }
878- }
896+ }
879897 }
880898
881- auto end_time = std::chrono::steady_clock::now ();
882- auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time );
899+ auto wall_end = std::chrono::steady_clock::now ();
900+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(wall_end - wall_start );
883901
884902 // Final results display (CLI visible)
885903 hydroc::cli::ShowSimulationResults (system->GetChTime (), static_cast <int >(system->GetChTime () / loop_dt), duration.count () / 1000.0 );
886904
887905 // Finalize HDF5 output with runtime metadata
888906 if (exporter) {
889- double wall_s = std::chrono::duration_cast<std::chrono::duration<double >>(end_time - start_time ).count ();
907+ double wall_s = std::chrono::duration_cast<std::chrono::duration<double >>(wall_end - wall_start ).count ();
890908 exporter->SetRunMetadata (std::string (" " ), std::string (" " ), wall_s, step_count, loop_dt, system->GetChTime ());
891909 exporter->Finalize ();
892910 }
911+
912+ // Optional profiling summary
913+ if (profile_mode) {
914+ double wall_seconds = std::chrono::duration_cast<std::chrono::duration<double >>(wall_end - wall_start).count ();
915+ prof_other_seconds = std::max (0.0 , wall_seconds - (prof_setup_seconds + prof_loop_seconds + prof_export_seconds));
916+
917+ std::vector<std::string> prof_lines;
918+ auto pct = [&](double s){ return hydroc::FormatNumber (100.0 * (s / std::max (1e-12 , wall_seconds)), 1 ) + " %" ; };
919+
920+ // Top-level sections
921+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" 📦" , " Setup" , hydroc::FormatNumber (prof_setup_seconds, 3 ) + " s (" + pct (prof_setup_seconds) + " )" ));
922+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" ⚙️" , " Dynamics Loop" , hydroc::FormatNumber (prof_loop_seconds, 3 ) + " s (" + pct (prof_loop_seconds) + " )" ));
923+
924+ // Nested breakdown under Dynamics Loop
925+ if (test_hydro) {
926+ auto hp = test_hydro->GetProfileStats ();
927+ double hydro_total = hp.hydrostatics_seconds + hp.radiation_seconds + hp.waves_seconds ;
928+ double chrono_solver = std::max (0.0 , prof_loop_seconds - hydro_total);
929+
930+ auto loop_pct = [&](double s){ return hydroc::FormatNumber (100.0 * (s / std::max (1e-12 , prof_loop_seconds)), 1 ) + " %" ; };
931+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" 🔧" , " Chrono Solver" , hydroc::FormatNumber (chrono_solver, 4 ) + " s (" + loop_pct (chrono_solver) + " )" ));
932+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" ⚓" , " Hydrostatics" , hydroc::FormatNumber (hp.hydrostatics_seconds , 4 ) + " s (" + loop_pct (hp.hydrostatics_seconds ) + " ) [" + std::to_string (hp.hydrostatics_calls ) + " calls]" ));
933+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" 💧" , " Radiation Damping" , hydroc::FormatNumber (hp.radiation_seconds , 4 ) + " s (" + loop_pct (hp.radiation_seconds ) + " ) [" + std::to_string (hp.radiation_calls ) + " calls]" ));
934+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" 🌊" , " Wave Forces" , hydroc::FormatNumber (hp.waves_seconds , 4 ) + " s (" + loop_pct (hp.waves_seconds ) + " ) [" + std::to_string (hp.waves_calls ) + " calls]" ));
935+ }
936+
937+ if (exporter) {
938+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" 💾" , " Export" , hydroc::FormatNumber (prof_export_seconds, 3 ) + " s (" + pct (prof_export_seconds) + " )" ));
939+ }
940+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" ━━━" , " ━━━━━━━━━━━━━━━━━━━━━━" , " ━━━━━━━━━━━━━━━━━━━━" ));
941+ prof_lines.push_back (hydroc::cli::CreateAlignedLine (" 📈" , " Total Runtime" , hydroc::FormatNumber (wall_seconds, 3 ) + " s (100%)" ));
942+ hydroc::cli::ShowSectionBox (" 🔬 Performance Profiling" , prof_lines);
943+ }
893944
894945 // Display warnings section if any warnings were collected
895946 hydroc::cli::DisplayWarnings ();
0 commit comments