| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/performance/cpuperf/session_result_spec.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <rapidjson/document.h> |
| #include <rapidjson/error/en.h> |
| #include <rapidjson/schema.h> |
| #include <rapidjson/stringbuffer.h> |
| #include <rapidjson/writer.h> |
| |
| #include "src/lib/files/file.h" |
| #include "src/lib/fxl/strings/string_printf.h" |
| #include "src/lib/json_parser/rapidjson_validation.h" |
| |
| namespace cpuperf { |
| |
| namespace { |
| |
| // Top-level schema. |
| const char kRootSchema[] = R"({ |
| "type": "object", |
| "additionalProperties": false, |
| "properties": { |
| "config_name": { |
| "type": "string" |
| }, |
| "model_name": { |
| "type": "string" |
| }, |
| "num_iterations": { |
| "type": "integer", |
| "minimum": 1 |
| }, |
| "num_traces": { |
| "type": "integer", |
| "minimum": 1 |
| }, |
| "output_path_prefix": { |
| "type": "string" |
| } |
| } |
| })"; |
| |
| const char kConfigNameKey[] = "config_name"; |
| const char kModelNameKey[] = "model_name"; |
| const char kNumIterationsKey[] = "num_iterations"; |
| const char kNumTracesKey[] = "num_traces"; |
| const char kOutputPathPrefixKey[] = "output_path_prefix"; |
| |
| } // namespace |
| |
| SessionResultSpec::SessionResultSpec(const std::string& config_name, const std::string& model_name, |
| size_t num_iterations, size_t num_traces, |
| const std::string& output_path_prefix) |
| : config_name(config_name), |
| model_name(model_name), |
| num_iterations(num_iterations), |
| num_traces(num_traces), |
| output_path_prefix(output_path_prefix) {} |
| |
| // Given an iteration number and trace number, return the output file. |
| std::string SessionResultSpec::GetTraceFilePath(size_t iter_num, size_t trace_num) const { |
| return fxl::StringPrintf("%s.%zu.%zu.cpuperf", output_path_prefix.c_str(), iter_num, trace_num); |
| } |
| |
| bool DecodeSessionResultSpec(const std::string& json, SessionResultSpec* out_spec) { |
| // Initialize schemas for JSON validation. |
| auto root_schema_result = json_parser::InitSchema(kRootSchema); |
| if (root_schema_result.is_error()) { |
| FX_LOGS(ERROR) << "Invalid schema: " << root_schema_result.error_value().ToString(); |
| return false; |
| } |
| |
| SessionResultSpec result; |
| rapidjson::Document document; |
| document.Parse<rapidjson::kParseCommentsFlag>(json.c_str(), json.size()); |
| if (document.HasParseError()) { |
| auto offset = document.GetErrorOffset(); |
| auto code = document.GetParseError(); |
| FX_LOGS(ERROR) << "Couldn't parse the session result spec file: offset " << offset << ", " |
| << GetParseError_En(code); |
| return false; |
| } |
| auto root_schema = std::move(root_schema_result.value()); |
| auto validation_result = |
| json_parser::ValidateSchema(document, root_schema, "session result spec"); |
| if (validation_result.is_error()) { |
| FX_LOGS(ERROR) << "json validation failed: " << validation_result.error_value(); |
| return false; |
| } |
| |
| if (document.HasMember(kConfigNameKey)) { |
| result.config_name = document[kConfigNameKey].GetString(); |
| } |
| |
| if (document.HasMember(kModelNameKey)) { |
| result.model_name = document[kModelNameKey].GetString(); |
| } |
| |
| if (document.HasMember(kNumIterationsKey)) { |
| result.num_iterations = document[kNumIterationsKey].GetUint(); |
| } |
| |
| if (document.HasMember(kNumTracesKey)) { |
| result.num_traces = document[kNumTracesKey].GetUint(); |
| } |
| |
| if (document.HasMember(kOutputPathPrefixKey)) { |
| result.output_path_prefix = document[kOutputPathPrefixKey].GetString(); |
| } |
| |
| *out_spec = std::move(result); |
| return true; |
| } |
| |
| bool WriteSessionResultSpec(const std::string& output_file_path, const SessionResultSpec& spec) { |
| rapidjson::StringBuffer string_buffer; |
| rapidjson::Writer<rapidjson::StringBuffer> writer(string_buffer); |
| |
| writer.StartObject(); |
| |
| if (!spec.config_name.empty()) { |
| writer.Key(kConfigNameKey); |
| writer.String(spec.config_name.c_str()); |
| } |
| |
| if (!spec.model_name.empty()) { |
| writer.Key(kModelNameKey); |
| writer.String(spec.model_name.c_str()); |
| } |
| |
| writer.Key(kNumIterationsKey); |
| writer.Uint(spec.num_iterations); |
| |
| writer.Key(kNumTracesKey); |
| writer.Uint(spec.num_traces); |
| |
| writer.Key(kOutputPathPrefixKey); |
| writer.String(spec.output_path_prefix.c_str()); |
| |
| writer.EndObject(); |
| |
| std::string encoded = string_buffer.GetString(); |
| if (!files::WriteFile(output_file_path, encoded.data(), encoded.size())) { |
| FX_LOGS(ERROR) << "Error writing to: " << output_file_path; |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace cpuperf |