blob: ef0870e34253b6fab9bddcbe3ef6d0c1fddec633 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/export_json.h"
#include "src/trace_processor/metadata.h"
#include <json/value.h>
#include <json/writer.h>
#include <stdio.h>
#include "src/trace_processor/trace_storage.h"
namespace {
class TraceFormatWriter {
public:
TraceFormatWriter(FILE* output) : output_(output), first_event_(true) {
WriteHeader();
}
~TraceFormatWriter() { WriteFooter(); }
void WriteSlice(int64_t begin_ts_us,
int64_t duration_us,
const char* cat,
const char* name,
uint32_t tid,
uint32_t pid) {
if (!first_event_) {
fputs(",", output_);
}
Json::FastWriter writer;
Json::Value value;
value["ph"] = "X";
value["cat"] = cat;
value["name"] = name;
value["tid"] = Json::UInt(tid);
value["pid"] = Json::UInt(pid);
value["ts"] = Json::Int64(begin_ts_us);
value["dur"] = Json::Int64(duration_us);
fputs(writer.write(value).c_str(), output_);
first_event_ = false;
}
void WriteMetadataEvent(const char* metadata_type,
const char* metadata_value,
uint32_t tid,
uint32_t pid) {
if (!first_event_) {
fputs(",", output_);
}
Json::FastWriter writer;
Json::Value value;
value["ph"] = "M";
value["cat"] = "__metadata";
value["ts"] = 0;
value["name"] = metadata_type;
value["tid"] = Json::UInt(tid);
value["pid"] = Json::UInt(pid);
Json::Value args;
args["name"] = metadata_value;
value["args"] = args;
fputs(writer.write(value).c_str(), output_);
first_event_ = false;
}
void AppendTelemetryMetadataString(const char* key, const char* value) {
metadata_["telemetry"][key].append(value);
}
void AppendTelemetryMetadataInt(const char* key, int64_t value) {
metadata_["telemetry"][key].append(Json::Int64(value));
}
void AppendTelemetryMetadataBool(const char* key, bool value) {
metadata_["telemetry"][key].append(value);
}
void SetTelemetryMetadataTimestamp(const char* key, int64_t value) {
metadata_["telemetry"][key] = value / 1000.0;
}
private:
void WriteHeader() { fputs("{\"traceEvents\":[\n", output_); }
void WriteFooter() {
fputs("],\n\"metadata\":", output_);
Json::FastWriter writer;
fputs(writer.write(metadata_).c_str(), output_);
fputs("\n}", output_);
fflush(output_);
}
FILE* output_;
bool first_event_;
Json::Value metadata_;
};
} // anonymous namespace
namespace perfetto {
namespace trace_processor {
namespace json {
ResultCode ExportJson(const TraceStorage* storage, FILE* output) {
const StringPool& string_pool = storage->string_pool();
TraceFormatWriter writer(output);
// Write thread names.
for (UniqueTid i = 1; i < storage->thread_count(); ++i) {
auto thread = storage->GetThread(i);
if (thread.name_id > 0) {
const char* thread_name = string_pool.Get(thread.name_id).c_str();
uint32_t pid = thread.upid ? storage->GetProcess(*thread.upid).pid : 0;
writer.WriteMetadataEvent("thread_name", thread_name, thread.tid, pid);
}
}
// Write process names.
for (UniquePid i = 1; i < storage->process_count(); ++i) {
auto process = storage->GetProcess(i);
if (process.name_id > 0) {
const char* process_name = string_pool.Get(process.name_id).c_str();
writer.WriteMetadataEvent("process_name", process_name, 0, process.pid);
}
}
// Write slices.
const auto& slices = storage->nestable_slices();
for (size_t i = 0; i < slices.slice_count(); ++i) {
if (slices.types()[i] == RefType::kRefUtid) {
int64_t begin_ts_us = slices.start_ns()[i] / 1000;
int64_t duration_us = slices.durations()[i] / 1000;
const char* cat = string_pool.Get(slices.cats()[i]).c_str();
const char* name = string_pool.Get(slices.names()[i]).c_str();
UniqueTid utid = static_cast<UniqueTid>(slices.refs()[i]);
auto thread = storage->GetThread(utid);
uint32_t pid = thread.upid ? storage->GetProcess(*thread.upid).pid : 0;
writer.WriteSlice(begin_ts_us, duration_us, cat, name, thread.tid, pid);
} else {
return kResultWrongRefType;
}
}
// Add metadata to be written in the footer
const auto& trace_metadata = storage->metadata();
if (!trace_metadata[metadata::benchmark_description].empty()) {
auto desc_id =
trace_metadata[metadata::benchmark_description][0].string_value;
writer.AppendTelemetryMetadataString("benchmarkDescriptions",
string_pool.Get(desc_id).c_str());
}
if (!trace_metadata[metadata::benchmark_name].empty()) {
auto name_id = trace_metadata[metadata::benchmark_name][0].string_value;
writer.AppendTelemetryMetadataString("benchmarks",
string_pool.Get(name_id).c_str());
}
if (!trace_metadata[metadata::benchmark_start_time_us].empty()) {
auto start_ts =
trace_metadata[metadata::benchmark_start_time_us][0].int_value;
writer.SetTelemetryMetadataTimestamp("benchmarkStart", start_ts);
}
if (!trace_metadata[metadata::benchmark_had_failures].empty()) {
auto had_failures =
trace_metadata[metadata::benchmark_had_failures][0].int_value;
writer.AppendTelemetryMetadataBool("hadFailures", had_failures);
}
if (!trace_metadata[metadata::benchmark_label].empty()) {
auto label_id = trace_metadata[metadata::benchmark_label][0].string_value;
writer.AppendTelemetryMetadataString("labels",
string_pool.Get(label_id).c_str());
}
if (!trace_metadata[metadata::benchmark_story_name].empty()) {
auto name_id =
trace_metadata[metadata::benchmark_story_name][0].string_value;
writer.AppendTelemetryMetadataString("stories",
string_pool.Get(name_id).c_str());
}
if (!trace_metadata[metadata::benchmark_story_run_index].empty()) {
auto run_index =
trace_metadata[metadata::benchmark_story_run_index][0].int_value;
writer.AppendTelemetryMetadataInt("storysetRepeats", run_index);
}
if (!trace_metadata[metadata::benchmark_story_run_time_us].empty()) {
auto story_ts =
trace_metadata[metadata::benchmark_story_run_time_us][0].int_value;
writer.SetTelemetryMetadataTimestamp("traceStart", story_ts);
}
for (auto tag : trace_metadata[metadata::benchmark_story_tags]) {
auto tag_id = tag.string_value;
writer.AppendTelemetryMetadataString("storyTags",
string_pool.Get(tag_id).c_str());
}
return kResultOk;
}
} // namespace json
} // namespace trace_processor
} // namespace perfetto