| // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // TODO(asharif): Move this and other utilities to contrib/ dir. |
| #include "chromiumos-wide-profiling/conversion_utils.h" |
| |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| |
| #include "chromiumos-wide-profiling/compat/proto.h" |
| #include "chromiumos-wide-profiling/compat/string.h" |
| #include "chromiumos-wide-profiling/perf_parser.h" |
| #include "chromiumos-wide-profiling/perf_protobuf_io.h" |
| #include "chromiumos-wide-profiling/perf_reader.h" |
| #include "chromiumos-wide-profiling/utils.h" |
| |
| namespace quipper { |
| |
| namespace { |
| |
| // Parse options from the format strings, set the options, and return the base |
| // format. Returns the empty string if options are not recognized. |
| string ParseFormatOptions(string format, PerfParserOptions* options) { |
| auto dot = format.find('.'); |
| if (dot != string::npos) { |
| string opt = format.substr(dot+1); |
| format = format.substr(0, dot); |
| if (opt == "remap") { |
| options->do_remap = true; |
| } else if (opt == "discard") { |
| options->discard_unused_events = true; |
| } else if (opt == "remap.discard") { |
| options->do_remap = true; |
| options->discard_unused_events = true; |
| } else { |
| LOG(ERROR) << "Unknown option: " << opt; |
| return ""; |
| } |
| } |
| return format; |
| } |
| |
| // ReadInput reads the input and stores it within |reader|. |
| bool ReadInput(const FormatAndFile& input, |
| PerfReader* reader, |
| PerfParserOptions* options) { |
| LOG(INFO) << "Reading input."; |
| |
| string format = ParseFormatOptions(input.format, options); |
| if (format == kPerfFormat) { |
| return reader->ReadFile(input.filename); |
| } |
| |
| if (format == kProtoTextFormat) { |
| PerfDataProto perf_data_proto; |
| std::vector<char> data; |
| if (!FileToBuffer(input.filename, &data)) |
| return false; |
| string text(data.begin(), data.end()); |
| if (!TextFormat::ParseFromString(text, &perf_data_proto)) |
| return false; |
| |
| return reader->Deserialize(perf_data_proto); |
| } |
| |
| LOG(ERROR) << "Unimplemented read format: " << input.format; |
| return false; |
| } |
| |
| // WriteOutput reads from |reader| and writes the output to the file |
| // within |output|. |
| bool WriteOutput(const FormatAndFile& output, |
| const PerfParserOptions& options, |
| PerfReader* reader) { |
| LOG(INFO) << "Writing output."; |
| string output_string; |
| if (output.format == kPerfFormat) { |
| return reader->WriteFile(output.filename); |
| } |
| |
| if (output.format == kProtoTextFormat) { |
| PerfParser parser(reader, options); |
| if (!parser.ParseRawEvents()) |
| return false; |
| |
| PerfDataProto perf_data_proto; |
| reader->Serialize(&perf_data_proto); |
| |
| // Serialize the parser stats as well. |
| PerfSerializer::SerializeParserStats(parser.stats(), &perf_data_proto); |
| |
| // Reset the timestamp field since it causes reproducability issues when |
| // testing. |
| perf_data_proto.set_timestamp_sec(0); |
| if (!TextFormat::PrintToString(perf_data_proto, &output_string)) |
| return false; |
| std::vector<char> data(output_string.begin(), output_string.end()); |
| return BufferToFile(output.filename, data); |
| } |
| |
| LOG(ERROR) << "Unimplemented write format: " << output.format; |
| return false; |
| } |
| |
| } // namespace |
| |
| // Format string for perf.data. |
| const char kPerfFormat[] = "perf"; |
| |
| // Format string for protobuf text format. |
| const char kProtoTextFormat[] = "text"; |
| |
| bool ConvertFile(const FormatAndFile& input, const FormatAndFile& output) { |
| PerfReader reader; |
| PerfParserOptions options; |
| if (!ReadInput(input, &reader, &options)) |
| return false; |
| if (!WriteOutput(output, options, &reader)) |
| return false; |
| return true; |
| } |
| |
| } // namespace quipper |