.. _program_listing_file_src_flamegpu_io_JSONLogger.cu: Program Listing for File JSONLogger.cu ====================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/flamegpu/io/JSONLogger.cu``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "flamegpu/io/JSONLogger.h" #include #include #include #include #include #include #include "flamegpu/simulation/RunPlan.h" #include "flamegpu/simulation/LogFrame.h" namespace flamegpu { namespace io { JSONLogger::JSONLogger(const std::string &outPath, bool _prettyPrint, bool _truncateFile) : out_path(outPath) , prettyPrint(_prettyPrint) , truncateFile(_truncateFile) { } void JSONLogger::log(const RunLog &log, const RunPlan &plan, bool logSteps, bool logExit, bool logStepTime, bool logExitTime) const { logCommon(log, &plan, false, logSteps, logExit, logStepTime, logExitTime); } void JSONLogger::log(const RunLog &log, bool logConfig, bool logSteps, bool logExit, bool logStepTime, bool logExitTime) const { logCommon(log, nullptr, logConfig, logSteps, logExit, logStepTime, logExitTime); } template void JSONLogger::writeAny(T &writer, const detail::Any &value, const unsigned int elements) const { // Output value if (elements > 1) { writer.StartArray(); } // Loop through elements, to construct array for (unsigned int el = 0; el < elements; ++el) { if (value.type == std::type_index(typeid(float))) { writer.Double(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(double))) { writer.Double(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(int64_t))) { writer.Int64(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(uint64_t))) { writer.Uint64(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(int32_t))) { writer.Int(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(uint32_t))) { writer.Uint(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(int16_t))) { writer.Int(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(uint16_t))) { writer.Uint(static_cast(value.ptr)[el]); } else if (value.type == std::type_index(typeid(int8_t))) { writer.Int(static_cast(static_cast(value.ptr)[el])); // Char outputs weird if being used as an integer } else if (value.type == std::type_index(typeid(uint8_t))) { writer.Uint(static_cast(static_cast(value.ptr)[el])); // Char outputs weird if being used as an integer } else if (value.type == std::type_index(typeid(char))) { writer.Int(static_cast(static_cast(value.ptr)[el])); // Char outputs weird if being used as an integer } else { THROW exception::RapidJSONError("Attempting to export value of unsupported type '%s', " "in JSONLogger::writeAny()\n", value.type.name()); } } if (elements > 1) { writer.EndArray(); } } template void JSONLogger::writeLogFrame(T& writer, const StepLogFrame& frame, bool logTime) const { writer.StartObject(); { if (logTime) { writer.Key("step_time"); writer.Double(frame.getStepTime()); } writeCommonLogFrame(writer, frame); } writer.EndObject(); } template void JSONLogger::writeLogFrame(T& writer, const ExitLogFrame& frame, bool logTime) const { writer.StartObject(); { if (logTime) { writer.Key("rtc_time"); writer.Double(frame.getRTCTime()); writer.Key("init_time"); writer.Double(frame.getInitTime()); writer.Key("exit_time"); writer.Double(frame.getExitTime()); writer.Key("total_time"); writer.Double(frame.getTotalTime()); } writeCommonLogFrame(writer, frame); } writer.EndObject(); } template void JSONLogger::writeCommonLogFrame(T &writer, const LogFrame &frame) const { // Add static items writer.Key("step_index"); writer.Uint(frame.getStepCount()); if (frame.getEnvironment().size()) { // Add dynamic environment values writer.Key("environment"); writer.StartObject(); { for (const auto &prop : frame.getEnvironment()) { writer.Key(prop.first.c_str()); // Log value writeAny(writer, prop.second, prop.second.elements); } } writer.EndObject(); } if (frame.getAgents().size()) { // Add dynamic agent values writer.Key("agents"); writer.StartObject(); { // This assumes that sort order places all agents of same name, different state consecutively std::string current_agent; for (const auto &agent : frame.getAgents()) { // Start/end new agent if (current_agent != agent.first.first) { if (!current_agent.empty()) writer.EndObject(); current_agent = agent.first.first; writer.Key(current_agent.c_str()); writer.StartObject(); } // Start new state writer.Key(agent.first.second.c_str()); writer.StartObject(); { // Log agent count if provided if (agent.second.second != UINT_MAX) { writer.Key("count"); writer.Uint(agent.second.second); } if (agent.second.first.size()) { writer.Key("variables"); writer.StartObject(); // This assumes that sort order places all variables of same name, different reduction consecutively std::string current_variable; // Log each reduction for (auto &var : agent.second.first) { // Start/end new variable if (current_variable != var.first.name) { if (!current_variable.empty()) writer.EndObject(); current_variable = var.first.name; writer.Key(current_variable.c_str()); writer.StartObject(); } // Build name key for the variable writer.Key(LoggingConfig::toString(var.first.reduction)); // Log value writeAny(writer, var.second, 1); } if (!current_variable.empty()) writer.EndObject(); writer.EndObject(); } } writer.EndObject(); } if (!current_agent.empty()) writer.EndObject(); } writer.EndObject(); } } template void JSONLogger::logConfig(T &writer, const RunLog &log) const { writer.Key("config"); writer.StartObject(); { writer.Key("random_seed"); writer.Uint64(log.getRandomSeed()); } writer.EndObject(); } template void JSONLogger::logConfig(T &writer, const RunPlan &plan) const { writer.Key("config"); writer.StartObject(); { // Add static items writer.Key("random_seed"); writer.Uint64(plan.getRandomSimulationSeed()); writer.Key("steps"); writer.Uint(plan.getSteps()); // Add dynamic environment overrides writer.Key("environment"); writer.StartObject(); { for (const auto &prop : plan.property_overrides) { const EnvironmentData::PropData &env_prop = plan.environment->at(prop.first); writer.Key(prop.first.c_str()); writeAny(writer, prop.second, env_prop.data.elements); } } writer.EndObject(); } writer.EndObject(); } template void JSONLogger::logPerformanceSpecs(T& writer, const RunLog& log) const { writer.Key("performance_specs"); writer.StartObject(); { // Add static items writer.Key("device_name"); writer.String(log.getPerformanceSpecs().device_name.c_str()); writer.Key("device_cc_major"); writer.Int(log.getPerformanceSpecs().device_cc_major); writer.Key("device_cc_minor"); writer.Int(log.getPerformanceSpecs().device_cc_minor); writer.Key("cuda_version"); writer.Int(log.getPerformanceSpecs().cuda_version); writer.Key("seatbelts"); writer.Bool(log.getPerformanceSpecs().seatbelts); writer.Key("flamegpu_version"); writer.String(log.getPerformanceSpecs().flamegpu_version.c_str()); } writer.EndObject(); } template void JSONLogger::logSteps(T &writer, const RunLog &log, bool logTime) const { writer.Key("steps"); writer.StartArray(); { for (const auto &step : log.getStepLog()) { writeLogFrame(writer, step, logTime); } } writer.EndArray(); } template void JSONLogger::logExit(T &writer, const RunLog &log, bool logTime) const { writer.Key("exit"); writeLogFrame(writer, log.getExitLog(), logTime); } template void JSONLogger::logCommon(T &writer, const RunLog &log, const RunPlan *plan, bool doLogConfig, bool doLogSteps, bool doLogExit, bool doLogStepTime, bool doLogExitTime) const { // Begin json output object writer->StartObject(); { // Log config if (plan) { logConfig(*writer, *plan); } else if (doLogConfig) { logConfig(*writer, log); } if (doLogStepTime || doLogExitTime) { logPerformanceSpecs(*writer, log); } // Log step log if (doLogSteps) { logSteps(*writer, log, doLogStepTime); } // Log exit log if (doLogExit) { logExit(*writer, log, doLogExitTime); } } // End Json file writer->EndObject(); } void JSONLogger::logCommon(const RunLog &log, const RunPlan *plan, bool doLogConfig, bool doLogSteps, bool doLogExit, bool doLogStepTime, bool doLogExitTime) const { // Init writer rapidjson::StringBuffer s; if (prettyPrint) { // rapidjson::Writer doesn't have virtual methods, so can't pass rapidjson::PrettyWriter around as ptr to rapidjson::writer auto writer = new rapidjson::PrettyWriter, rapidjson::UTF8<>, rapidjson::CrtAllocator, rapidjson::kWriteNanAndInfFlag>(s); writer->SetIndent('\t', 1); logCommon(writer, log, plan, doLogConfig, doLogSteps, doLogExit, doLogStepTime, doLogExitTime); delete writer; } else { auto *writer = new rapidjson::Writer, rapidjson::UTF8<>, rapidjson::CrtAllocator, rapidjson::kWriteNanAndInfFlag>(s); logCommon(writer, log, plan, doLogConfig, doLogSteps, doLogExit, doLogStepTime, doLogExitTime); delete writer; } // Perform output std::ofstream out(out_path, truncateFile ? std::ofstream::trunc : std::ofstream::app); if (!out.is_open()) { THROW exception::RapidJSONError("Unable to open file '%s' for writing\n", out_path.c_str()); } out << s.GetString(); out << "\n"; out.close(); } } // namespace io } // namespace flamegpu