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