Files
FluidSimCpp/tools/scenario_profile.cpp

92 lines
5.0 KiB
C++

#include "FluidSim/Scenario.hpp"
#include "FluidSim/ScenarioCatalog.hpp"
#include "FluidSim/TwoStrokeScenario.hpp"
#include <chrono>
#include <algorithm>
#include <cmath>
#include <cmath>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
using namespace fluidsim::port;
using Clock = std::chrono::steady_clock;
template<class Scenario>
void measure_case(const ScenarioExample& definition, int density, PipeSolver solver,
int repetition, int warmup_frames, int measured_frames, Scenario& scenario, std::ostream& out) {
scenario.set_pipe_solver(solver);
float target_rpm=7000.f;
if constexpr (std::is_same_v<Scenario, FourStrokeScenario>) {
scenario.set_controls(.55f, .1f, 0.f);
target_rpm=definition.engine.initial_rpm > 0 ? definition.engine.initial_rpm : 4500.f;
} else {
scenario.set_controls(.55f, .1f, 0.f);
}
for (int i=0;i<warmup_frames;++i) { scenario.crankshaft.omega=target_rpm*2*pi/60; scenario.process(); }
scenario.enable_profiling(true);
const auto begin=Clock::now();
double audio_energy=0,audio_checksum=0;
float audio_peak=0;
for (int i=0;i<measured_frames;++i) {
scenario.crankshaft.omega=target_rpm*2*pi/60;
const auto frame=scenario.process();
if(!std::isfinite(frame.left)||!std::isfinite(frame.right)) throw std::runtime_error("nonfinite profiled audio");
audio_energy+=double(frame.left)*frame.left+double(frame.right)*frame.right;
audio_peak=std::max({audio_peak,std::abs(frame.left),std::abs(frame.right)});
audio_checksum+=double(frame.left)*(i+1)+double(frame.right)*(i%251+1);
}
const double wall=std::chrono::duration<double>(Clock::now()-begin).count();
const auto& profile=scenario.profile_totals();
std::size_t cells=0;
std::size_t scratch_bytes=0;
for(const auto& pipe:scenario.pipes) { cells+=pipe.cells.size();scratch_bytes+=pipe.scratch_bytes(); }
std::uint64_t repairs=0,fallbacks=0;
for(const auto& pipe:scenario.pipes) { repairs+=pipe.positivity_repairs; fallbacks+=pipe.hllc_fallbacks; }
double ms[7]{};
for(int i=0;i<7;++i) ms[i]=profile.sampled_steps ? profile.nanoseconds[i]/1e6/profile.sampled_steps : 0;
out<<definition.id<<','<<(definition.kind==ScenarioKind::TwoStroke?"two-stroke":"four-stroke")<<','<<density<<','
<<pipe_solver_name(solver)<<','<<repetition<<','<<scenario.pipes.size()<<','<<cells<<','<<measured_frames<<','
<<profile.sampled_steps<<','<<std::setprecision(8)<<wall<<','<<wall/measured_frames*1e6<<','<<wall/(measured_frames/44100.0)<<','
<<scratch_bytes<<',';
for(int i=0;i<7;++i) out<<ms[i]<<',';
out<<profile_percentile_ms(profile,.50)<<','<<profile_percentile_ms(profile,.95)<<','<<repairs<<','<<fallbacks<<','
<<std::sqrt(audio_energy/(2*measured_frames))<<','<<audio_peak<<','<<audio_checksum<<'\n';
}
int main(int argc,char** argv) {
const std::string output=argc>1?argv[1]:"scenario-profile.csv";
const int warmup=argc>2?std::stoi(argv[2]):5000;
const int frames=argc>3?std::stoi(argv[3]):22050;
const int reps=argc>4?std::stoi(argv[4]):2;
std::vector<std::string> ids={"single-450","twin","five","v8-h","yz-fat","saab-chambered"};
if(argc>6 && std::string(argv[6])!="all") ids={argv[6]};
const std::vector<int> densities=argc>5?std::vector<int>{std::stoi(argv[5])}:
std::vector<int>{10,20,40,50,80};
std::vector<PipeSolver> solvers={PipeSolver::Rusanov,PipeSolver::Hlle,PipeSolver::Hllc,PipeSolver::Muscl};
if(argc>7) solvers={parse_pipe_solver(argv[7])};
std::ofstream file(output);
if(!file) { std::cerr<<"cannot open output: "<<output<<'\n'; return 2; }
file<<"scenario,kind,cells_per_meter,solver,repetition,pipe_count,total_cells,frames,sampled_frames,wall_seconds,wall_us_per_frame,real_time_factor,scratch_bytes,total_ms_per_frame,controls_ms_per_frame,solver_ms_per_frame,boundary_ms_per_frame,pipe_ms_per_frame,components_ms_per_frame,audio_ms_per_frame,p50_frame_ms,p95_frame_ms,positivity_repairs,hllc_fallbacks,audio_rms,audio_peak,audio_checksum\n";
int completed=0, total=static_cast<int>(ids.size()*densities.size()*solvers.size()*reps);
for(const auto& id:ids) for(int density:densities) for(auto solver:solvers) for(int rep=1;rep<=reps;++rep) {
const auto& def=scenario_example(id);
auto config=def;
config.engine.cells_per_meter=static_cast<float>(density);
config.two.cells_per_meter=static_cast<float>(density);
if(def.kind==ScenarioKind::TwoStroke) {
config.two.exhaust_cell_length=1.0f/density;
TwoStrokeScenario scenario(44100,config.two);
measure_case(def,density,solver,rep,warmup,frames,scenario,file);
} else {
FourStrokeScenario scenario(44100,config);
measure_case(def,density,solver,rep,warmup,frames,scenario,file);
}
file.flush();
std::cerr<<"completed "<<++completed<<"/"<<total<<" "<<id<<" density="<<density<<" solver="<<pipe_solver_name(solver)<<" rep="<<rep<<'\n';
}
}