Home | History | Annotate | Download | only in internal
      1 /* Copyright 2016 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/internal/tfprof_show_multi.h"
     17 
     18 #include <memory>
     19 #include <set>
     20 
     21 #include "tensorflow/core/lib/strings/str_util.h"
     22 #include "tensorflow/core/lib/strings/stringprintf.h"
     23 #include "tensorflow/core/platform/env.h"
     24 #include "tensorflow/core/platform/regexp.h"
     25 #include "tensorflow/core/profiler/internal/tfprof_scope.h"
     26 
     27 namespace tensorflow {
     28 namespace tfprof {
     29 
     30 const MultiGraphNodeProto& TFMultiShow::Show(const string& prefix,
     31                                              const Options& opts) {
     32   if (opts.output_type == kOutput[0]) {
     33     Timeline timeline(opts.step, opts.output_options.at(kTimelineOpts[0]));
     34     return ShowInternal(opts, &timeline)->proto();
     35   } else {
     36     const ShowMultiNode* ret = ShowInternal(opts, nullptr);
     37     if (opts.output_type == kOutput[1]) {
     38       printf("%s", (prefix + ret->formatted_str).c_str());
     39       fflush(stdout);
     40     } else if (opts.output_type == kOutput[2]) {
     41       Status s = WriteStringToFile(Env::Default(),
     42                                    opts.output_options.at(kFileOpts[0]),
     43                                    prefix + ret->formatted_str);
     44       if (!s.ok()) {
     45         fprintf(stderr, "%s\n", s.ToString().c_str());
     46       }
     47     } else if (opts.output_type == kOutput[3] ||
     48                opts.output_type == kOutput[4]) {
     49     } else {
     50       fprintf(stderr, "Unknown output type: %s\n", opts.output_type.c_str());
     51     }
     52     return ret->proto();
     53   }
     54 }
     55 
     56 bool TFMultiShow::ShouldShow(const ShowMultiNode* node, const Options& opts,
     57                              int depth) const {
     58   // Always show kTFProfRoot.
     59   if (node->name() == kTFProfRoot) return true;
     60 
     61   // TODO(xpan): Think more carefully about node filtering in code view.
     62   // Unlike graph/scope view, which users want to see the exact leaf op.
     63   // In code view, users want to see the middle code traces they wrote.
     64   //
     65   // This is a subtle difference from scope/graph view. Usually mostly
     66   // want to see the middle code traces (i.e. their own codes.), instead
     67   // of the TensorFlow internal codes traces.
     68   if (node->proto().total_requested_bytes() < opts.min_bytes ||
     69       node->proto().total_peak_bytes() < opts.min_peak_bytes ||
     70       node->proto().total_residual_bytes() < opts.min_residual_bytes ||
     71       node->proto().total_output_bytes() < opts.min_output_bytes ||
     72       node->proto().total_exec_micros() < opts.min_micros ||
     73       node->proto().total_accelerator_exec_micros() <
     74           opts.min_accelerator_micros ||
     75       node->proto().total_cpu_exec_micros() < opts.min_cpu_micros ||
     76       node->proto().total_parameters() < opts.min_params ||
     77       node->proto().total_float_ops() < opts.min_float_ops ||
     78       depth > opts.max_depth || !ShouldShowIfExtra(node, opts, depth)) {
     79     return false;
     80   }
     81 
     82   bool show = false;
     83   if (opts.show_name_regexes.size() == 1 && opts.show_name_regexes[0] == ".*") {
     84     show = true;
     85   } else {
     86     for (const string& regex : opts.show_name_regexes) {
     87       if (RE2::FullMatch(node->name(), regex)) {
     88         show = true;
     89         break;
     90       }
     91     }
     92   }
     93   // Don't show if show_name_regexes don't cover it.
     94   if (!show) return false;
     95   // Don't show if hide_name_regexes cover it.
     96   for (const string& regex : opts.hide_name_regexes) {
     97     if (RE2::FullMatch(node->name(), regex)) return false;
     98   }
     99   return true;
    100 }
    101 
    102 bool TFMultiShow::ShouldTrim(const ShowMultiNode* node,
    103                              const std::vector<string>& regexes) const {
    104   for (const string& regex : regexes) {
    105     if (RE2::FullMatch(node->name(), regex)) {
    106       return true;
    107     }
    108   }
    109   return false;
    110 }
    111 
    112 bool TFMultiShow::ReAccount(ShowMultiNode* node, const Options& opts) {
    113   return node->ReInit(opts.step, opts.account_type_regexes);
    114 }
    115 
    116 string TFMultiShow::FormatLegend(const Options& opts) const {
    117   std::vector<string> legends;
    118   if (opts.select.find(kShown[0]) != opts.select.end()) {
    119     legends.push_back("requested bytes");
    120   }
    121   if (opts.select.find(kShown[11]) != opts.select.end()) {
    122     legends.push_back("peak bytes");
    123   }
    124   if (opts.select.find(kShown[12]) != opts.select.end()) {
    125     legends.push_back("residual bytes");
    126   }
    127   if (opts.select.find(kShown[13]) != opts.select.end()) {
    128     legends.push_back("output bytes");
    129   }
    130   if (opts.select.find(kShown[1]) != opts.select.end()) {
    131     legends.push_back("total execution time");
    132     legends.push_back("accelerator execution time");
    133     legends.push_back("cpu execution time");
    134   }
    135   if (opts.select.find(kShown[9]) != opts.select.end() &&
    136       opts.select.find(kShown[1]) == opts.select.end()) {
    137     legends.push_back("accelerator execution time");
    138   }
    139   if (opts.select.find(kShown[10]) != opts.select.end() &&
    140       opts.select.find(kShown[1]) == opts.select.end()) {
    141     legends.push_back("cpu execution time");
    142   }
    143   if (opts.select.find(kShown[2]) != opts.select.end()) {
    144     legends.push_back("# parameters");
    145   }
    146   if (opts.select.find(kShown[3]) != opts.select.end()) {
    147     legends.push_back("# float_ops");
    148   }
    149   if (opts.select.find(kShown[5]) != opts.select.end()) {
    150     legends.push_back("assigned devices");
    151   }
    152   if (opts.select.find(kShown[6]) != opts.select.end()) {
    153     legends.push_back("op types");
    154   }
    155   if (opts.select.find(kShown[7]) != opts.select.end()) {
    156     legends.push_back("op occurrence (run|defined)");
    157   }
    158   if (opts.select.find(kShown[8]) != opts.select.end()) {
    159     legends.push_back("input shapes");
    160   }
    161   return strings::Printf("node name | %s\n",
    162                          str_util::Join(legends, " | ").c_str());
    163 }
    164 
    165 string TFMultiShow::FormatInputShapes(const MultiGraphNodeProto& proto) const {
    166   // input_shape string -> (static defined count, run count, run_micros)
    167   std::map<string, std::tuple<int64, int64, int64>> input_shapes_attr;
    168   for (int i = 0; i < proto.graph_nodes_size(); ++i) {
    169     const GraphNodeProto& gnode = proto.graph_nodes(i);
    170     // Convert and sort by input_idx.
    171     std::map<int, std::vector<int64>> input_shapes;
    172     for (const auto& inp : gnode.input_shapes()) {
    173       input_shapes[inp.first] = ShapeProtoToVec(inp.second);
    174     }
    175 
    176     std::vector<string> input_vec;
    177     for (const auto& s : input_shapes) {
    178       if (s.second.empty()) {
    179         input_vec.push_back(strings::Printf("%d:unknown", s.first));
    180       } else {
    181         input_vec.push_back(strings::Printf(
    182             "%d:%s", s.first, str_util::Join(s.second, "x").c_str()));
    183       }
    184     }
    185     string shape_type_str = strings::Printf(
    186         "input_type: %s", str_util::Join(input_vec, ",\t").c_str());
    187     auto t = input_shapes_attr.find(shape_type_str);
    188     if (t == input_shapes_attr.end()) {
    189       input_shapes_attr.insert(
    190           std::make_pair(shape_type_str, std::make_tuple(0, 0, 0)));
    191       t = input_shapes_attr.find(shape_type_str);
    192     }
    193     input_shapes_attr[shape_type_str] = std::make_tuple(
    194         std::get<0>(t->second) + 1, std::get<1>(t->second) + gnode.run_count(),
    195         std::get<2>(t->second) + gnode.exec_micros());
    196   }
    197   if (input_shapes_attr.empty()) {
    198     return "";
    199   }
    200 
    201   std::vector<std::pair<string, std::tuple<int64, int64, int64>>>
    202       shape_count_vec(input_shapes_attr.begin(), input_shapes_attr.end());
    203   std::sort(
    204       shape_count_vec.begin(), shape_count_vec.end(),
    205       [](const std::pair<const string, std::tuple<int64, int64, int64>>& a,
    206          const std::pair<const string, std::tuple<int64, int64, int64>>& b) {
    207         return std::get<1>(a.second) > std::get<1>(b.second);
    208       });
    209 
    210   std::vector<string> input_types;
    211   input_types.reserve(shape_count_vec.size());
    212   for (const auto& s : shape_count_vec) {
    213     std::tuple<int64, int64, int64> t = s.second;
    214     input_types.push_back(strings::Printf(
    215         "%s\t(run*%lld|defined*%lld)\texec_time: %s", s.first.c_str(),
    216         std::get<1>(t), std::get<0>(t), FormatTime(std::get<2>(t)).c_str()));
    217   }
    218   return str_util::Join(input_types, "\n");
    219 }
    220 
    221 std::vector<string> TFMultiShow::FormatTimes(const ShowMultiNode* node,
    222                                              const Options& opts) const {
    223   std::vector<string> attrs;
    224   if (opts.select.find(kShown[1]) != opts.select.end()) {
    225     attrs.push_back(FormatTotalExecTime(node, opts));
    226     attrs.push_back(FormatAcceleratorExecTime(node, opts));
    227     attrs.push_back(FormatCPUExecTime(node, opts));
    228   }
    229   if (opts.select.find(kShown[9]) != opts.select.end() &&
    230       opts.select.find(kShown[1]) == opts.select.end()) {
    231     attrs.push_back(FormatAcceleratorExecTime(node, opts));
    232   }
    233   if (opts.select.find(kShown[10]) != opts.select.end() &&
    234       opts.select.find(kShown[1]) == opts.select.end()) {
    235     attrs.push_back(FormatCPUExecTime(node, opts));
    236   }
    237   return attrs;
    238 }
    239 
    240 }  // namespace tfprof
    241 }  // namespace tensorflow
    242