Home | History | Annotate | Download | only in client
      1 /* Copyright 2017 The TensorFlow Authors All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #include "tensorflow/core/profiler/rpc/client/trace_events_to_json.h"
     17 #include "include/json/json.h"
     18 #include "tensorflow/core/lib/strings/strcat.h"
     19 #include "tensorflow/core/lib/strings/stringprintf.h"
     20 #include "tensorflow/core/profiler/trace_events.pb.h"
     21 
     22 namespace tensorflow {
     23 
     24 namespace profiler {
     25 namespace client {
     26 namespace {
     27 
     28 using ::tensorflow::strings::Appendf;
     29 using ::tensorflow::strings::StrAppend;
     30 
     31 constexpr double kPicosPerMicro = 1000000.0;
     32 
     33 inline void AppendEscapedName(string *json, const string &name) {
     34   StrAppend(json, "\"name\":", Json::valueToQuotedString(name.c_str()).c_str());
     35 }
     36 
     37 // Adds resource events for a single device.
     38 void AddResourceMetadata(uint32 device_id,
     39                          const std::map<uint32, const Resource *> &resources,
     40                          string *json) {
     41   for (const auto &pair : resources) {
     42     uint32 resource_id = pair.first;
     43     const Resource &resource = *pair.second;
     44     if (!resource.name().empty()) {
     45       Appendf(json,
     46               R"({"ph":"M","pid":%u,"tid":%u,)"
     47               R"("name":"thread_name","args":{)",
     48               device_id, resource_id);
     49       AppendEscapedName(json, resource.name());
     50       Appendf(json, "}},");
     51     }
     52     Appendf(json,
     53             R"({"ph":"M","pid":%u,"tid":%u,)"
     54             R"("name":"thread_sort_index","args":{"sort_index":%u}},)",
     55             device_id, resource_id, resource_id);
     56   }
     57 }
     58 
     59 void AddDeviceMetadata(const std::map<uint32, const Device *> &devices,
     60                        string *json) {
     61   for (const auto &pair : devices) {
     62     uint32 device_id = pair.first;
     63     const Device &device = *pair.second;
     64     if (!device.name().empty()) {
     65       Appendf(json,
     66               R"({"ph":"M","pid":%u,"name":"process_name",)"
     67               R"("args":{)",
     68               device_id);
     69       AppendEscapedName(json, device.name());
     70       StrAppend(json, "}},");
     71     }
     72     Appendf(json,
     73             R"({"ph":"M","pid":%u,"name":"process_sort_index",)"
     74             R"("args":{"sort_index":%u}},)",
     75             device_id, device_id);
     76     // Convert to a std::map so that devices are sorted by the device id.
     77     std::map<uint32, const Resource *> sorted_resources;
     78     for (const auto &pair : device.resources()) {
     79       sorted_resources[pair.first] = &pair.second;
     80     }
     81     AddResourceMetadata(device_id, sorted_resources, json);
     82   }
     83 }
     84 
     85 inline void AddTraceEvent(const TraceEvent &event, string *json) {
     86   Appendf(json, R"({"pid":%u,"tid":%u,"ts":%.5f,)", event.device_id(),
     87           event.resource_id(), event.timestamp_ps() / kPicosPerMicro);
     88   AppendEscapedName(json, event.name());
     89   StrAppend(json, ",");
     90   if (event.duration_ps() > 0) {
     91     Appendf(json, R"("ph":"X","dur":%.5f},)",
     92             event.duration_ps() / kPicosPerMicro);
     93   } else {
     94     StrAppend(json, R"("ph":"i","s":"t"},)");
     95   }
     96 }
     97 
     98 }  // namespace
     99 
    100 string TraceEventsToJson(const Trace &trace) {
    101   string json;
    102   Appendf(
    103       &json, R"({"displayTimeUnit":"ns","metadata":{"highres-ticks":true},)");
    104   Appendf(&json, R"("traceEvents":[)");
    105   // Convert to a std::map so that devices are sorted by the device id.
    106   std::map<uint32, const Device *> sorted_devices;
    107   for (const auto &pair : trace.devices()) {
    108     sorted_devices[pair.first] = &pair.second;
    109   }
    110   AddDeviceMetadata(sorted_devices, &json);
    111   for (const TraceEvent &event : trace.trace_events()) {
    112     AddTraceEvent(event, &json);
    113   }
    114   // Add one fake event to avoid dealing with no-trailing-comma rule.
    115   Appendf(&json, R"({}]})");
    116   return json;
    117 }
    118 
    119 }  // namespace client
    120 }  // namespace profiler
    121 }  // namespace tensorflow
    122