엄격 수렴 기준 실행 보존과 한정 HHT 개발 계측 기록
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
#ifndef FESA_ANALYSIS_HHT_DEVELOPMENT_PROBE_H_
|
||||
#define FESA_ANALYSIS_HHT_DEVELOPMENT_PROBE_H_
|
||||
|
||||
// This header is compiled out of normal builds, including environment/file I/O.
|
||||
#if defined(FESA_HHT_DEVELOPMENT_PROBE)
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "fesa/solvers/linear/linear_solver.h"
|
||||
#include "fesa/solvers/linear/tangent_solver.h"
|
||||
|
||||
namespace fesa::hht_development_probe {
|
||||
enum Stage { kProcedure, kInner, kAssembly, kOuterSolve, kRates,
|
||||
kFactor, kSolve, kStageCount };
|
||||
enum Counter { kOuterCorrection, kInnerCorrection, kInternalEvaluation,
|
||||
kInertiaEvaluation, kFactorCall, kSolveCall, kRhs,
|
||||
kConstraintInternalEvaluation, kInternalFailure, kCounterCount };
|
||||
struct Statistics {
|
||||
std::array<std::atomic<std::uint64_t>, kCounterCount> counts{};
|
||||
// Timers/stage attribution are serial procedure-thread data. Only the three
|
||||
// element counters below and internal failures may be touched by workers.
|
||||
std::array<std::int64_t, kStageCount> inclusive_ns{};
|
||||
std::array<std::int64_t, kStageCount> exclusive_ns{};
|
||||
std::array<std::uint64_t, kStageCount> stage_calls{};
|
||||
std::array<std::array<std::uint64_t, kCounterCount>, kStageCount> by_stage{};
|
||||
};
|
||||
inline Statistics* active = nullptr;
|
||||
class Scope {
|
||||
public:
|
||||
explicit Scope(Stage stage) : stage_(stage), parent_(current_),
|
||||
start_(std::chrono::steady_clock::now()) {
|
||||
current_ = this;
|
||||
if (active != nullptr) ++active->stage_calls[stage_];
|
||||
}
|
||||
~Scope() {
|
||||
const auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now() - start_).count();
|
||||
if (active != nullptr) {
|
||||
active->inclusive_ns[stage_] += elapsed;
|
||||
active->exclusive_ns[stage_] += elapsed - children_;
|
||||
}
|
||||
if (parent_ != nullptr) parent_->children_ += elapsed;
|
||||
current_ = parent_;
|
||||
}
|
||||
static Stage Current() { return current_ == nullptr ? kProcedure : current_->stage_; }
|
||||
private:
|
||||
Stage stage_;
|
||||
Scope* parent_;
|
||||
std::chrono::steady_clock::time_point start_;
|
||||
std::int64_t children_ = 0;
|
||||
inline static thread_local Scope* current_ = nullptr;
|
||||
};
|
||||
inline void Count(Counter counter, std::uint64_t count = 1U) {
|
||||
if (active == nullptr) return;
|
||||
active->counts[counter].fetch_add(count, std::memory_order_relaxed);
|
||||
// Element callbacks are parallel; their totals use only the atomics above.
|
||||
if (counter != kInternalEvaluation && counter != kInertiaEvaluation &&
|
||||
counter != kConstraintInternalEvaluation && counter != kInternalFailure)
|
||||
active->by_stage[Scope::Current()][counter] += count;
|
||||
}
|
||||
class Session {
|
||||
public:
|
||||
Session() : previous_(active) { active = &statistics_; }
|
||||
~Session() {
|
||||
active = previous_;
|
||||
#if defined(_WIN32)
|
||||
char* environment = nullptr;
|
||||
std::size_t size = 0U;
|
||||
if (_dupenv_s(&environment, &size, "FESA_HHT_PROBE_OUTPUT") != 0) return;
|
||||
const std::string path = environment == nullptr ? "" : environment;
|
||||
std::free(environment);
|
||||
#else
|
||||
const char* environment = std::getenv("FESA_HHT_PROBE_OUTPUT");
|
||||
const std::string path = environment == nullptr ? "" : environment;
|
||||
#endif
|
||||
if (path.empty()) return;
|
||||
std::ofstream output(path, std::ios::out | std::ios::binary);
|
||||
constexpr const char* counters[] = {"outer_applied_correction", "inner_applied_correction",
|
||||
"assembly_internal_evaluation", "assembly_inertia_evaluation",
|
||||
"logical_factor_call", "logical_solve_call", "logical_rhs",
|
||||
"constraint_internal_evaluation", "assembly_internal_failure"};
|
||||
constexpr const char* stages[] = {"procedure_other", "inner_graph", "assembly",
|
||||
"outer_linear", "physical_rates", "factor", "solve"};
|
||||
for (int c = 0; c < kCounterCount; ++c)
|
||||
output << counters[c] << '=' << statistics_.counts[c].load() << '\n';
|
||||
output << "procedure_inclusive_ns=" << statistics_.inclusive_ns[kProcedure] << '\n';
|
||||
for (int s = 0; s < kStageCount; ++s) {
|
||||
output << stages[s] << "_calls=" << statistics_.stage_calls[s] << '\n';
|
||||
output << stages[s] << "_exclusive_ns=" << statistics_.exclusive_ns[s] << '\n';
|
||||
for (int c = 0; c < kCounterCount; ++c)
|
||||
if (statistics_.by_stage[s][c] != 0U)
|
||||
output << stages[s] << '_' << counters[c] << '='
|
||||
<< statistics_.by_stage[s][c] << '\n';
|
||||
}
|
||||
}
|
||||
private:
|
||||
Statistics statistics_;
|
||||
Statistics* previous_;
|
||||
};
|
||||
class PositiveSolver final : public LinearSolver {
|
||||
public:
|
||||
explicit PositiveSolver(LinearSolver& solver) : solver_(solver) {}
|
||||
Status Factorize(const SparseMatrix& matrix) override {
|
||||
Count(kFactorCall); Scope scope{kFactor}; return solver_.Factorize(matrix);
|
||||
}
|
||||
Status Solve(const Vector& rhs, Vector& solution) const override {
|
||||
Count(kSolveCall); Count(kRhs); Scope scope{kSolve};
|
||||
return solver_.Solve(rhs, solution);
|
||||
}
|
||||
private:
|
||||
LinearSolver& solver_;
|
||||
};
|
||||
class CorrectionSolver final : public TangentSolver {
|
||||
public:
|
||||
explicit CorrectionSolver(TangentSolver& solver) : solver_(solver) {}
|
||||
Status FactorizeFresh(const SparseMatrix& matrix) override {
|
||||
Count(kFactorCall); Scope scope{kFactor}; return solver_.FactorizeFresh(matrix);
|
||||
}
|
||||
Status SolveCorrection(const Vector& rhs, Vector& solution) const override {
|
||||
Count(kSolveCall); Count(kRhs); Scope scope{kSolve};
|
||||
return solver_.SolveCorrection(rhs, solution);
|
||||
}
|
||||
private:
|
||||
TangentSolver& solver_;
|
||||
};
|
||||
} // namespace fesa::hht_development_probe
|
||||
#define FESA_HHT_PROBE_COUNT(counter) \
|
||||
::fesa::hht_development_probe::Count(::fesa::hht_development_probe::counter)
|
||||
#define FESA_HHT_PROBE_SCOPE(stage) \
|
||||
::fesa::hht_development_probe::Scope probe_scope{ \
|
||||
::fesa::hht_development_probe::stage}
|
||||
#else
|
||||
#define FESA_HHT_PROBE_COUNT(counter) ((void)0)
|
||||
#define FESA_HHT_PROBE_SCOPE(stage) ((void)0)
|
||||
#endif
|
||||
#endif // FESA_ANALYSIS_HHT_DEVELOPMENT_PROBE_H_
|
||||
Reference in New Issue
Block a user