diff options
Diffstat (limited to 'tensorflow/tools/tfprof/internal')
24 files changed, 253 insertions, 138 deletions
diff --git a/tensorflow/tools/tfprof/internal/advisor/BUILD b/tensorflow/tools/tfprof/internal/advisor/BUILD index e4bd0f0015..629322373a 100644 --- a/tensorflow/tools/tfprof/internal/advisor/BUILD +++ b/tensorflow/tools/tfprof/internal/advisor/BUILD @@ -45,11 +45,20 @@ cc_library( ) cc_library( + name = "expensive_operation_checker", + hdrs = ["expensive_operation_checker.h"], + deps = [ + ":checker", + ], +) + +cc_library( name = "tfprof_advisor", hdrs = ["tfprof_advisor.h"], deps = [ ":accelerator_utilization_checker", ":checker", + ":expensive_operation_checker", ":internal_checker_runner_dummy", ":operation_checker", ], diff --git a/tensorflow/tools/tfprof/internal/advisor/accelerator_utilization_checker.h b/tensorflow/tools/tfprof/internal/advisor/accelerator_utilization_checker.h index fb7f65d7dc..074b8e57b0 100644 --- a/tensorflow/tools/tfprof/internal/advisor/accelerator_utilization_checker.h +++ b/tensorflow/tools/tfprof/internal/advisor/accelerator_utilization_checker.h @@ -33,10 +33,11 @@ struct ExecStats { class AcceleratorUtilizationChecker : public Checker { public: - string name() override { return "AcceleratorUtilizationChecker"; } + string name() const override { return kCheckers[0]; } private: - std::vector<string> Check(const TFStats* stats) override { + AdviceProto::Checker Check(const AdvisorOptionsProto::CheckerOption& options, + const TFStats* stats) override { if (!stats) { fprintf(stderr, "Missing profiles (e.g. graph, run_meta). Skip %s\n", name().c_str()); @@ -48,24 +49,21 @@ class AcceleratorUtilizationChecker : public Checker { return CheckInternal(); } - std::vector<string> CheckInternal() { + AdviceProto::Checker CheckInternal() { for (const auto& s : accelerator_exec_stats_) { const ExecStats& stat = s.second; int64 total_micros = stat.end_micros - stat.start_micros; if (total_micros <= 0) continue; double utilization = 1.0 * stat.exec_micros / total_micros; if (utilization >= 0.5) { - reports_.push_back(strings::Printf("%s: device: %s utilization: %.2f", - kLevel[0], s.first.c_str(), - utilization)); + reports_.add_reports(strings::Printf("device: %s utilization: %.2f", + s.first.c_str(), utilization)); } else if (utilization < 0.5 && utilization > 0.2) { - reports_.push_back( - strings::Printf("%s: device: %s low utilization: %.2f", kLevel[1], - s.first.c_str(), utilization)); + reports_.add_reports(strings::Printf("device: %s low utilization: %.2f", + s.first.c_str(), utilization)); } else if (utilization <= 0.2) { - reports_.push_back( - strings::Printf("%s: device: %s low utilization: %.2f", kLevel[2], - s.first.c_str(), utilization)); + reports_.add_reports(strings::Printf("device: %s low utilization: %.2f", + s.first.c_str(), utilization)); } } return reports_; @@ -102,7 +100,7 @@ class AcceleratorUtilizationChecker : public Checker { std::map<string, ExecStats> accelerator_exec_stats_; std::map<string, int64> ps_placement_; - std::vector<string> reports_; + AdviceProto::Checker reports_; }; } // namespace tfprof diff --git a/tensorflow/tools/tfprof/internal/advisor/checker.h b/tensorflow/tools/tfprof/internal/advisor/checker.h index b8b057be5b..3ce80cd8c4 100644 --- a/tensorflow/tools/tfprof/internal/advisor/checker.h +++ b/tensorflow/tools/tfprof/internal/advisor/checker.h @@ -18,27 +18,33 @@ limitations under the License. #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/tools/tfprof/internal/tfprof_stats.h" +#include "tensorflow/tools/tfprof/tfprof_options.pb.h" namespace tensorflow { namespace tfprof { -static const char* const kLevel[] = { - "NOTE", // Good to know. - "SUGGEST", // Might get better. - "WARN", // Please do it for better. +// Append only. +static const char* const kCheckers[] = { + "AcceleratorUtilizationChecker", "OperationChecker", + "ExpensiveOperationChecker", + "JobChecker", // Internal checker. }; class Checker { public: - virtual ~Checker(){}; + virtual ~Checker() {} - virtual string name() = 0; + virtual string name() const = 0; - std::vector<string> Run(const TFStats* stats) { return Check(stats); } + AdviceProto::Checker Run(const AdvisorOptionsProto::CheckerOption& options, + const TFStats* stats) { + return Check(options, stats); + } protected: - // Returns a vector of string, each one being an advice. - virtual std::vector<string> Check(const TFStats* stats) = 0; + virtual AdviceProto::Checker Check( + const AdvisorOptionsProto::CheckerOption& options, + const TFStats* stats) = 0; }; } // namespace tfprof } // namespace tensorflow diff --git a/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner.h b/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner.h index 1238b57f20..ed8ae571b6 100644 --- a/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner.h +++ b/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner.h @@ -17,13 +17,16 @@ limitations under the License. #define THIRD_PARTY_TENSORFLOW_TOOLS_TFPROF_INTERNAL_ADVISOR_INTERNAL_CHECKER_RUNNER_H_ #include "tensorflow/tools/tfprof/internal/tfprof_utils.h" +#include "tensorflow/tools/tfprof/tfprof_options.pb.h" +#include "tensorflow/tools/tfprof/tfprof_output.pb.h" namespace tensorflow { namespace tfprof { class TFStats; -std::map<string, std::vector<string>> RunInternalCheckers(const TFStats* stats); +AdviceProto RunInternalCheckers(const AdvisorOptionsProto& options, + const TFStats* stats); } // namespace tfprof } // namespace tensorflow diff --git a/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner_dummy.cc b/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner_dummy.cc index 8204d2b04e..67962c8e8b 100644 --- a/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner_dummy.cc +++ b/tensorflow/tools/tfprof/internal/advisor/internal_checker_runner_dummy.cc @@ -17,9 +17,9 @@ limitations under the License. namespace tensorflow { namespace tfprof { -std::map<string, std::vector<string>> RunInternalCheckers( - const TFStats* stats) { - return std::map<string, std::vector<string>>(); +AdviceProto RunInternalCheckers(const AdvisorOptionsProto& options, + const TFStats* stats) { + return AdviceProto(); } } // namespace tfprof diff --git a/tensorflow/tools/tfprof/internal/advisor/operation_checker.h b/tensorflow/tools/tfprof/internal/advisor/operation_checker.h index 2a05f9bfd0..4d0d68e3bf 100644 --- a/tensorflow/tools/tfprof/internal/advisor/operation_checker.h +++ b/tensorflow/tools/tfprof/internal/advisor/operation_checker.h @@ -24,10 +24,11 @@ namespace tfprof { class OperationChecker : public Checker { public: - string name() override { return "OperationChecker"; } + string name() const override { return kCheckers[1]; } private: - std::vector<string> Check(const TFStats* stats) override { + AdviceProto::Checker Check(const AdvisorOptionsProto::CheckerOption& options, + const TFStats* stats) override { if (!stats) { fprintf(stderr, "Missing profiles (e.g. graph, run_meta). Skip %s\n", name().c_str()); @@ -53,22 +54,20 @@ class OperationChecker : public Checker { } } if (use_batch_norm && !use_fused_batch_norm) { - reports_.push_back(strings::Printf( - "%s: Maybe use faster FusedBatchNorm instead of BatchNorm", - kLevel[1])); + reports_.add_reports( + "Maybe use faster FusedBatchNorm instead of BatchNorm"); } if (recommend_nchw) { // TODO(xpan): Maybe print which Op supports NCHW. - reports_.push_back(strings::Printf( - "%s: Found operation using NHWC data_format on GPU. Maybe " - "NCHW is faster.", - kLevel[1])); + reports_.add_reports( + "Found operation using NHWC data_format on GPU. Maybe " + "NCHW is faster."); } return reports_; } private: - std::vector<string> reports_; + AdviceProto::Checker reports_; }; } // namespace tfprof diff --git a/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor.h b/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor.h index 856f515459..d2257fb9b5 100644 --- a/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor.h +++ b/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor.h @@ -18,8 +18,10 @@ limitations under the License. #include "tensorflow/tools/tfprof/internal/advisor/accelerator_utilization_checker.h" #include "tensorflow/tools/tfprof/internal/advisor/checker.h" +#include "tensorflow/tools/tfprof/internal/advisor/expensive_operation_checker.h" #include "tensorflow/tools/tfprof/internal/advisor/internal_checker_runner.h" #include "tensorflow/tools/tfprof/internal/advisor/operation_checker.h" +#include "tensorflow/tools/tfprof/tfprof_options.pb.h" namespace tensorflow { namespace tfprof { @@ -29,23 +31,44 @@ class Advisor { public: Advisor(const TFStats* stats) : stats_(stats) {} - std::map<string, std::vector<string>> Advise() { + static AdvisorOptionsProto DefaultOptions() { + AdvisorOptionsProto options; + std::vector<string> checkers( + kCheckers, kCheckers + sizeof(kCheckers) / sizeof(*kCheckers)); + for (const string& checker : checkers) { + (*options.mutable_checkers())[checker]; + } + return options; + } + + AdviceProto Advise(const AdvisorOptionsProto& options) { // Note: Release a checker's memory ASAP. - std::map<string, std::vector<string>> reports = RunInternalCheckers(stats_); - // TODO(xpan): Think of a way to turn off/on specific checkers. - AcceleratorUtilizationChecker au_checker; - reports[au_checker.name()] = au_checker.Run(stats_); - OperationChecker op_checker; - reports[op_checker.name()] = op_checker.Run(stats_); - - for (const auto& checker_r : reports) { - fprintf(stdout, "%s reports:\n", checker_r.first.c_str()); - for (const auto& r : checker_r.second) { + AdviceProto ret = RunInternalCheckers(options, stats_); + + if (options.checkers().find(kCheckers[0]) != options.checkers().end()) { + AcceleratorUtilizationChecker au_checker; + (*ret.mutable_checkers())[kCheckers[0]].MergeFrom( + au_checker.Run(options.checkers().at(kCheckers[0]), stats_)); + } + if (options.checkers().find(kCheckers[1]) != options.checkers().end()) { + OperationChecker op_checker; + (*ret.mutable_checkers())[kCheckers[1]].MergeFrom( + op_checker.Run(options.checkers().at(kCheckers[1]), stats_)); + } + if (options.checkers().find(kCheckers[2]) != options.checkers().end()) { + ExpensiveOperationChecker expensive_op_checker; + (*ret.mutable_checkers())[kCheckers[2]].MergeFrom( + expensive_op_checker.Run(options.checkers().at(kCheckers[2]), + stats_)); + } + for (const auto& checker : ret.checkers()) { + fprintf(stdout, "\n%s:\n", checker.first.c_str()); + for (const string& r : checker.second.reports()) { fprintf(stdout, "%s\n", r.c_str()); } } fflush(stdout); - return reports; + return ret; } private: diff --git a/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor_test.cc b/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor_test.cc index b41d0770dc..3b40253954 100644 --- a/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor_test.cc +++ b/tensorflow/tools/tfprof/internal/advisor/tfprof_advisor_test.cc @@ -29,15 +29,16 @@ class TFProfAdvisorTest : public ::testing::Test { nullptr, nullptr)); stats_->AddNodeForTest( - "n1", CreateNode("n1", "Conv2D", {{"data_format", "NHWC"}}, 10, 2)); - stats_->AddNodeForTest("n2", CreateNode("n2", "Conv2D", {}, 20, 2)); + 0, CreateNode("n1", "Conv2D", {{"data_format", "NHWC"}}, 0, 10, 2)); + stats_->AddNodeForTest(0, CreateNode("n2", "Conv2D", {}, 0, 20, 2)); + stats_->BuildAllViews(); advisor_.reset(new Advisor(stats_.get())); } std::unique_ptr<TFGraphNode> CreateNode(const string& name, const string& type, std::map<string, string> attrs, - int64 start_miros, + int64 step, int64 start_miros, int64 end_rel_micros) { node_defs_.push_back(std::unique_ptr<NodeDef>(new NodeDef())); NodeDef* def = node_defs_.back().get(); @@ -52,10 +53,10 @@ class TFProfAdvisorTest : public ::testing::Test { NodeExecStats node_stat; node_stat.set_all_start_micros(start_miros); node_stat.set_op_end_rel_micros(end_rel_micros); - node->AddStepStat(0, "/job:localhost/replica:0/task:0/gpu:0", node_stat); - node->AddStepStat(0, "/job:localhost/replica:0/task:0/gpu:0:stream:all", + node->AddStepStat(step, "/job:localhost/replica:0/task:0/gpu:0", node_stat); + node->AddStepStat(step, "/job:localhost/replica:0/task:0/gpu:0:stream:all", node_stat); - node->AddStepStat(0, "/job:localhost/replica:0/task:0/gpu:0:stream:0", + node->AddStepStat(step, "/job:localhost/replica:0/task:0/gpu:0:stream:0", node_stat); return node; } @@ -66,23 +67,38 @@ class TFProfAdvisorTest : public ::testing::Test { }; TEST_F(TFProfAdvisorTest, Basics) { - std::map<string, std::vector<string>> reports = advisor_->Advise(); - EXPECT_TRUE(reports.find("AcceleratorUtilizationChecker") != reports.end()); - EXPECT_TRUE(reports.find("OperationChecker") != reports.end()); + AdvisorOptionsProto options = Advisor::DefaultOptions(); + AdviceProto advice = advisor_->Advise(options); + EXPECT_TRUE(advice.checkers().find(kCheckers[0]) != advice.checkers().end()); + EXPECT_TRUE(advice.checkers().find(kCheckers[1]) != advice.checkers().end()); + EXPECT_TRUE(advice.checkers().find(kCheckers[2]) != advice.checkers().end()); } TEST_F(TFProfAdvisorTest, OperationChecker) { - std::map<string, std::vector<string>> reports = advisor_->Advise(); - EXPECT_EQ(reports["OperationChecker"].size(), 1); - EXPECT_TRUE(StringPiece(reports["OperationChecker"][0]).contains("NCHW")); + AdvisorOptionsProto options; + (*options.mutable_checkers())[kCheckers[1]]; + AdviceProto advice = advisor_->Advise(options); + EXPECT_EQ(advice.checkers().at(kCheckers[1]).reports_size(), 1); + EXPECT_TRUE(StringPiece(advice.checkers().at(kCheckers[1]).reports(0)) + .contains("NCHW")); } TEST_F(TFProfAdvisorTest, UtilizationChecker) { - std::map<string, std::vector<string>> reports = advisor_->Advise(); - EXPECT_EQ(reports["AcceleratorUtilizationChecker"].size(), 1); - EXPECT_TRUE(StringPiece(reports["AcceleratorUtilizationChecker"][0]) + AdvisorOptionsProto options; + (*options.mutable_checkers())[kCheckers[0]]; + AdviceProto advice = advisor_->Advise(options); + EXPECT_EQ(advice.checkers().at(kCheckers[0]).reports_size(), 1); + EXPECT_TRUE(StringPiece(advice.checkers().at(kCheckers[0]).reports(0)) .contains("low utilization")); } +TEST_F(TFProfAdvisorTest, ExpensiveOperationChecker) { + AdvisorOptionsProto options; + (*options.mutable_checkers())[kCheckers[2]]; + AdviceProto advice = advisor_->Advise(options); + EXPECT_TRUE(StringPiece(advice.checkers().at(kCheckers[2]).reports(0)) + .contains("top 1 operation type: Conv2D")); +} + } // namespace tfprof } // namespace tensorflow diff --git a/tensorflow/tools/tfprof/internal/print_model_analysis.cc b/tensorflow/tools/tfprof/internal/print_model_analysis.cc index 37d01db3a1..5a9c44d8e6 100644 --- a/tensorflow/tools/tfprof/internal/print_model_analysis.cc +++ b/tensorflow/tools/tfprof/internal/print_model_analysis.cc @@ -27,6 +27,7 @@ limitations under the License. #include "tensorflow/tools/tfprof/internal/tfprof_options.h" #include "tensorflow/tools/tfprof/internal/tfprof_stats.h" #include "tensorflow/tools/tfprof/tfprof_log.pb.h" +#include "tensorflow/tools/tfprof/tfprof_options.pb.h" #include "tensorflow/tools/tfprof/tfprof_output.pb.h" namespace tensorflow { @@ -36,6 +37,18 @@ TFStats* tf_stat = nullptr; string RunProfile(const string& command, const string& options, TFStats* tf_stats) { + if (command == kCmds[4]) { + AdvisorOptionsProto option_pb; + if (!option_pb.ParseFromString(options)) { + fprintf(stderr, "Cannot parse AdvisorOptionsProto\n"); + return ""; + } + tf_stats->BuildAllViews(); + return Advisor(tf_stats).Advise(option_pb).SerializeAsString(); + } else { + tf_stats->BuildView(command); + } + Options opts; tensorflow::Status s = Options::FromProtoStr(options, &opts); if (!s.ok()) { @@ -97,14 +110,14 @@ void AddStep(int64 step, const string* run_meta, const string* op_log) { // TODO(xpan): Better error handling. std::unique_ptr<RunMetadata> run_meta_ptr(new RunMetadata()); run_meta_ptr->ParseFromString(*run_meta); - tf_stat->ParseRunMeta(step, std::move(run_meta_ptr)); + tf_stat->AddRunMeta(step, std::move(run_meta_ptr)); std::unique_ptr<OpLog> op_log_ptr; if (op_log && !op_log->empty()) { op_log_ptr.reset(new OpLog()); op_log_ptr->ParseFromString(*op_log); } - tf_stat->ParseOpLog(std::move(op_log_ptr)); + tf_stat->AddOpLog(std::move(op_log_ptr)); } string Profile(const string* command, const string* options) { @@ -144,7 +157,5 @@ string PrintModelAnalysis(const string* graph, const string* run_meta, return RunProfile(*command, *options, &tf_stats); } -void Advise() { Advisor(tf_stat).Advise(); } - } // namespace tfprof } // namespace tensorflow diff --git a/tensorflow/tools/tfprof/internal/print_model_analysis.h b/tensorflow/tools/tfprof/internal/print_model_analysis.h index 84165e542d..46db63646d 100644 --- a/tensorflow/tools/tfprof/internal/print_model_analysis.h +++ b/tensorflow/tools/tfprof/internal/print_model_analysis.h @@ -39,8 +39,6 @@ void AddStep(int64 step, const string* run_meta, const string* op_log); string Profile(const string* command, const string* options); -void Advise(); - // Single-step Profiler. // // Interface defined for Python API swig. Calls the tfprof core API. diff --git a/tensorflow/tools/tfprof/internal/tfprof_graph.h b/tensorflow/tools/tfprof/internal/tfprof_graph.h index fbeae8673d..194a21f0cc 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_graph.h +++ b/tensorflow/tools/tfprof/internal/tfprof_graph.h @@ -54,8 +54,8 @@ class TFGraph : public TFShow { const ShowNode* ShowInternal(const Options& opts, Timeline* timeline) override; - bool ShouldShowIfExtra(ShowNode* node, const Options& opts, - int depth) override { + bool ShouldShowIfExtra(const ShowNode* node, const Options& opts, + int depth) const override { return true; } diff --git a/tensorflow/tools/tfprof/internal/tfprof_op.cc b/tensorflow/tools/tfprof/internal/tfprof_op.cc index 6a7077c085..77a2593623 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_op.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_op.cc @@ -126,6 +126,7 @@ const ShowMultiNode* TFOp::ShowInternal(const Options& opts, } nodes = SortNodes(nodes, opts); + // pre keeps track of previous visited node. OpNode* pre = nullptr; std::vector<OpNode*> account_nodes; for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) { @@ -170,16 +171,20 @@ const ShowMultiNode* TFOp::ShowInternal(const Options& opts, root_->ResetTotalStats(); if (pre) { root_->AggregateTotalStats(pre); - root_->mutable_proto()->add_children()->MergeFrom(pre->proto()); - pre->mutable_proto()->clear_children(); } } + if (pre) { + root_->mutable_proto()->add_children()->MergeFrom(pre->proto()); + pre->mutable_proto()->clear_children(); + } if (opts.output_type == kOutput[1] || opts.output_type == kOutput[2]) { string display_str = FormatLegend(opts); for (OpNode* node : show_nodes) { display_str += FormatNode(node, root_.get(), opts); } + // In op view, we don't show root (total). But it will still in proto. + // TODO(xpan): Is it the right choice? root_->formatted_str = display_str; } return root_.get(); @@ -201,7 +206,7 @@ int64 TFOp::SearchRoot(const std::vector<OpNode*> nodes, return i; } -string TFOp::FormatNode(OpNode* node, OpNode* root, const Options& opts) { +string TFOp::FormatNode(OpNode* node, OpNode* root, const Options& opts) const { std::vector<string> attrs; if (opts.select.find(kShown[0]) != opts.select.end()) { diff --git a/tensorflow/tools/tfprof/internal/tfprof_op.h b/tensorflow/tools/tfprof/internal/tfprof_op.h index 5b16490363..34812f54be 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_op.h +++ b/tensorflow/tools/tfprof/internal/tfprof_op.h @@ -56,15 +56,15 @@ class TFOp : public TFMultiShow { int64 SearchRoot(const std::vector<OpNode*> nodes, const std::vector<string>& regexes); - bool ShouldShowIfExtra(ShowMultiNode* node, const Options& opts, - int depth) override { + bool ShouldShowIfExtra(const ShowMultiNode* node, const Options& opts, + int depth) const override { if (opts.min_occurrence > node->node->graph_nodes().size()) { return false; } return true; } - string FormatNode(OpNode* node, OpNode* root, const Options& opts); + string FormatNode(OpNode* node, OpNode* root, const Options& opts) const; std::unique_ptr<OpNode> root_; std::map<string, std::unique_ptr<OpNode>> cnodes_map_; diff --git a/tensorflow/tools/tfprof/internal/tfprof_options.h b/tensorflow/tools/tfprof/internal/tfprof_options.h index 6c9db24342..d39333e3fc 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_options.h +++ b/tensorflow/tools/tfprof/internal/tfprof_options.h @@ -59,10 +59,10 @@ static const char* const kShown[] = { "cpu_micros"}; static const char* const kCmds[] = { - "scope", "graph", "code", "op", "set", "help", + "scope", "graph", "code", "op", "advise", "set", "help", }; -static const char* const kOutput[] = {"timeline", "stdout", "file"}; +static const char* const kOutput[] = {"timeline", "stdout", "file", "none"}; static const char* const kTimelineOpts[] = { "outfile", diff --git a/tensorflow/tools/tfprof/internal/tfprof_show.cc b/tensorflow/tools/tfprof/internal/tfprof_show.cc index 40cc56fb22..6c1183a4d5 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_show.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_show.cc @@ -26,7 +26,9 @@ namespace tensorflow { namespace tfprof { const TFGraphNodeProto& TFShow::Show(const Options& opts) { - if (opts.output_type == kOutput[0]) { + if (opts.output_type == kOutput[3]) { + return ShowInternal(opts, nullptr)->proto(); + } else if (opts.output_type == kOutput[0]) { Timeline timeline(opts.step, opts.output_options.at(kTimelineOpts[0])); return ShowInternal(opts, &timeline)->proto(); } else if (opts.output_type == kOutput[2]) { @@ -64,7 +66,8 @@ bool TFShow::LookUpCheckPoint(const string& name, return true; } -bool TFShow::ShouldShow(ShowNode* node, const Options& opts, int depth) { +bool TFShow::ShouldShow(const ShowNode* node, const Options& opts, + int depth) const { // Always show kTFProfRoot. if (node->name() == kTFProfRoot) return true; @@ -97,7 +100,8 @@ bool TFShow::ShouldShow(ShowNode* node, const Options& opts, int depth) { return true; } -bool TFShow::ShouldTrim(ShowNode* node, const std::vector<string>& regexes) { +bool TFShow::ShouldTrim(const ShowNode* node, + const std::vector<string>& regexes) const { for (const string& regex : regexes) { if (RE2::FullMatch(node->name(), regex)) { return true; @@ -122,7 +126,7 @@ bool TFShow::ReAccount(ShowNode* node, const Options& opts) { return false; } -string TFShow::FormatNode(ShowNode* node, const Options& opts) { +string TFShow::FormatNode(ShowNode* node, const Options& opts) const { std::vector<string> info; if (opts.select.find(kShown[2]) != opts.select.end()) { const string shape = FormatShapes(node->node->shape()); @@ -210,7 +214,7 @@ string TFShow::FormatNode(ShowNode* node, const Options& opts) { str_util::Join(info, ", ").c_str()); } -string TFShow::FormatLegend(const Options& opts) { +string TFShow::FormatLegend(const Options& opts) const { std::vector<string> legends; if (opts.select.find(kShown[2]) != opts.select.end()) { legends.push_back("# parameters"); diff --git a/tensorflow/tools/tfprof/internal/tfprof_show.h b/tensorflow/tools/tfprof/internal/tfprof_show.h index 2c61b4fd73..95513e086f 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_show.h +++ b/tensorflow/tools/tfprof/internal/tfprof_show.h @@ -54,20 +54,21 @@ class TFShow { std::unique_ptr<TFProfTensor>* tensor); // Overridden by subclass if extra requirements need to be met. - virtual bool ShouldShowIfExtra(ShowNode* node, const Options& opts, - int depth) { + virtual bool ShouldShowIfExtra(const ShowNode* node, const Options& opts, + int depth) const { return true; } - bool ShouldShow(ShowNode* node, const Options& opts, int depth); + bool ShouldShow(const ShowNode* node, const Options& opts, int depth) const; - bool ShouldTrim(ShowNode* node, const std::vector<string>& regexes); + bool ShouldTrim(const ShowNode* node, + const std::vector<string>& regexes) const; bool ReAccount(ShowNode* node, const Options& opts); - string FormatNode(ShowNode* node, const Options& opts); + string FormatNode(ShowNode* node, const Options& opts) const; - string FormatLegend(const Options& opts); + string FormatLegend(const Options& opts) const; template <typename T> std::vector<T*> SortNodes(const std::vector<T*>& nodes, const Options& opts) { diff --git a/tensorflow/tools/tfprof/internal/tfprof_show_multi.cc b/tensorflow/tools/tfprof/internal/tfprof_show_multi.cc index 7545b3d48b..84d542714a 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_show_multi.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_show_multi.cc @@ -28,7 +28,9 @@ namespace tensorflow { namespace tfprof { const TFMultiGraphNodeProto& TFMultiShow::Show(const Options& opts) { - if (opts.output_type == kOutput[0]) { + if (opts.output_type == kOutput[3]) { + return ShowInternal(opts, nullptr)->proto(); + } else if (opts.output_type == kOutput[0]) { Timeline timeline(opts.step, opts.output_options.at(kTimelineOpts[0])); return ShowInternal(opts, &timeline)->proto(); } else if (opts.output_type == kOutput[2]) { @@ -48,8 +50,8 @@ const TFMultiGraphNodeProto& TFMultiShow::Show(const Options& opts) { } } -bool TFMultiShow::ShouldShow(ShowMultiNode* node, const Options& opts, - int depth) { +bool TFMultiShow::ShouldShow(const ShowMultiNode* node, const Options& opts, + int depth) const { // Always show kTFProfRoot. if (node->name() == kTFProfRoot) return true; @@ -88,8 +90,8 @@ bool TFMultiShow::ShouldShow(ShowMultiNode* node, const Options& opts, return true; } -bool TFMultiShow::ShouldTrim(ShowMultiNode* node, - const std::vector<string>& regexes) { +bool TFMultiShow::ShouldTrim(const ShowMultiNode* node, + const std::vector<string>& regexes) const { for (const string& regex : regexes) { if (RE2::FullMatch(node->name(), regex)) { return true; @@ -102,7 +104,7 @@ bool TFMultiShow::ReAccount(ShowMultiNode* node, const Options& opts) { return node->ReInit(opts.step, opts.account_type_regexes); } -string TFMultiShow::FormatLegend(const Options& opts) { +string TFMultiShow::FormatLegend(const Options& opts) const { std::vector<string> legends; if (opts.select.find(kShown[0]) != opts.select.end()) { legends.push_back("output bytes"); @@ -142,7 +144,8 @@ string TFMultiShow::FormatLegend(const Options& opts) { str_util::Join(legends, " | ").c_str()); } -string TFMultiShow::FormatInputShapes(const TFMultiGraphNodeProto& proto) { +string TFMultiShow::FormatInputShapes( + const TFMultiGraphNodeProto& proto) const { // input_shape string -> (static defined count, run count, run_micros) std::map<string, std::tuple<int64, int64, int64>> input_shapes_attr; for (int i = 0; i < proto.graph_nodes_size(); ++i) { @@ -199,7 +202,7 @@ string TFMultiShow::FormatInputShapes(const TFMultiGraphNodeProto& proto) { } std::vector<string> TFMultiShow::FormatTimes(const ShowMultiNode* node, - const Options& opts) { + const Options& opts) const { std::vector<string> attrs; if (opts.select.find(kShown[1]) != opts.select.end()) { attrs.push_back(FormatTotalExecTime(node, opts)); diff --git a/tensorflow/tools/tfprof/internal/tfprof_show_multi.h b/tensorflow/tools/tfprof/internal/tfprof_show_multi.h index e6faf1231d..ce309816a9 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_show_multi.h +++ b/tensorflow/tools/tfprof/internal/tfprof_show_multi.h @@ -55,21 +55,23 @@ class TFMultiShow { std::unique_ptr<TFProfTensor>* tensor); // Overridden by subclass if extra requirements need to be met. - virtual bool ShouldShowIfExtra(ShowMultiNode* node, const Options& opts, - int depth) { + virtual bool ShouldShowIfExtra(const ShowMultiNode* node, const Options& opts, + int depth) const { return true; } - bool ShouldShow(ShowMultiNode* node, const Options& opts, int depth); + bool ShouldShow(const ShowMultiNode* node, const Options& opts, + int depth) const; - bool ShouldTrim(ShowMultiNode* node, const std::vector<string>& regexes); + bool ShouldTrim(const ShowMultiNode* node, + const std::vector<string>& regexes) const; bool ReAccount(ShowMultiNode* node, const Options& opts); - string FormatLegend(const Options& opts); - string FormatInputShapes(const TFMultiGraphNodeProto& proto); + string FormatLegend(const Options& opts) const; + string FormatInputShapes(const TFMultiGraphNodeProto& proto) const; std::vector<string> FormatTimes(const ShowMultiNode* node, - const Options& opts); + const Options& opts) const; template <typename T> std::vector<T*> SortNodes(const std::vector<T*>& nodes, const Options& opts) { diff --git a/tensorflow/tools/tfprof/internal/tfprof_show_test.cc b/tensorflow/tools/tfprof/internal/tfprof_show_test.cc index 18a7c51a20..46b6ebc09a 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_show_test.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_show_test.cc @@ -65,6 +65,7 @@ class TFProfShowTest : public ::testing::Test { tf_stats_.reset(new TFStats(std::move(graph_pb), std::move(run_meta_pb), std::move(op_log_pb), std::move(ckpt_reader))); + tf_stats_->BuildAllViews(); } std::unique_ptr<TFStats> tf_stats_; diff --git a/tensorflow/tools/tfprof/internal/tfprof_stats.cc b/tensorflow/tools/tfprof/internal/tfprof_stats.cc index f5b8dad4e2..64da7ae7cf 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_stats.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_stats.cc @@ -29,16 +29,17 @@ TFStats::TFStats(std::unique_ptr<GraphDef> graph, std::unique_ptr<RunMetadata> run_meta, std::unique_ptr<OpLog> op_log, std::unique_ptr<checkpoint::CheckpointReader> ckpt_reader) - : graph_(std::move(graph)), + : has_code_traces_(false), + graph_(std::move(graph)), ckpt_reader_(std::move(ckpt_reader)) { CHECK(graph_) << "Must at least have GraphDef"; printf("Parsing Inputs...\n"); ParseGraph(); if (run_meta && run_meta->has_step_stats()) { - ParseRunMeta(0, std::move(run_meta)); + AddRunMeta(0, std::move(run_meta)); } - ParseOpLog(std::move(op_log)); + AddOpLog(std::move(op_log)); if (ckpt_reader_) { for (const auto& v : ckpt_reader_->GetVariableToShapeMap()) { @@ -48,27 +49,48 @@ TFStats::TFStats(std::unique_ptr<GraphDef> graph, } } } +} - printf("Preparing Views...\n"); - scope_view_ = std::unique_ptr<TFScope>(new TFScope(ckpt_reader_.get())); - graph_view_ = std::unique_ptr<TFGraph>(new TFGraph(ckpt_reader_.get())); - code_view_ = std::unique_ptr<TFCode>(new TFCode()); - op_view_ = std::unique_ptr<TFOp>(new TFOp()); +void TFStats::BuildView(const string& cmd) { + if (cmd == kCmds[0] && !scope_view_) { + scope_view_.reset(new TFScope(ckpt_reader_.get())); + for (auto it = nodes_map_.begin(); it != nodes_map_.end(); it++) { + scope_view_->AddNode(it->second.get()); + } + scope_view_->Build(); + } + if (cmd == kCmds[1] && !graph_view_) { + graph_view_.reset(new TFGraph(ckpt_reader_.get())); + for (auto it = nodes_map_.begin(); it != nodes_map_.end(); it++) { + graph_view_->AddNode(it->second.get()); + } + graph_view_->Build(); + } + if (cmd == kCmds[2] && !code_view_) { + code_view_.reset(new TFCode()); + for (auto it = nodes_map_.begin(); it != nodes_map_.end(); it++) { + code_view_->AddNode(it->second.get()); + } + code_view_->Build(); + } + if (cmd == kCmds[3] && !op_view_) { + op_view_.reset(new TFOp()); + for (auto it = nodes_map_.begin(); it != nodes_map_.end(); it++) { + op_view_->AddNode(it->second.get()); + } + op_view_->Build(); + } +} - for (auto it = nodes_map_.begin(); it != nodes_map_.end(); it++) { - scope_view_->AddNode(it->second.get()); - graph_view_->AddNode(it->second.get()); - code_view_->AddNode(it->second.get()); - op_view_->AddNode(it->second.get()); - } - scope_view_->Build(); - graph_view_->Build(); - code_view_->Build(); - op_view_->Build(); +void TFStats::BuildAllViews() { + std::vector<string> cmds_str(kCmds, kCmds + sizeof(kCmds) / sizeof(*kCmds)); + for (const string& cmd : cmds_str) { + BuildView(cmd); + } } const TFGraphNodeProto& TFStats::ShowGraphNode(const string& cmd, - const Options& opts) { + const Options& opts) const { if (!Validate(opts)) { return empty_graph_node_; } @@ -82,8 +104,8 @@ const TFGraphNodeProto& TFStats::ShowGraphNode(const string& cmd, } } -const TFMultiGraphNodeProto& TFStats::ShowMultiGraphNode(const string& cmd, - const Options& opts) { +const TFMultiGraphNodeProto& TFStats::ShowMultiGraphNode( + const string& cmd, const Options& opts) const { if (!Validate(opts)) { return empty_multi_graph_node_; } @@ -130,7 +152,7 @@ void TFStats::ParseGraph() { } } -void TFStats::ParseOpLog(std::unique_ptr<OpLog> op_log) { +void TFStats::AddOpLog(std::unique_ptr<OpLog> op_log) { if (!op_log) { return; } @@ -144,12 +166,13 @@ void TFStats::ParseOpLog(std::unique_ptr<OpLog> op_log) { node->second->AddFloatOps(entry.float_ops()); } if (entry.has_code_def()) { + has_code_traces_ = true; node->second->AddCode(entry.code_def()); } } } -void TFStats::ParseRunMeta(int64 step, std::unique_ptr<RunMetadata> run_meta) { +void TFStats::AddRunMeta(int64 step, std::unique_ptr<RunMetadata> run_meta) { if (!run_meta || !run_meta->has_step_stats()) { fprintf(stderr, "Invalid RunMetadata for step %lld\n", step); return; @@ -176,7 +199,7 @@ void TFStats::ParseRunMeta(int64 step, std::unique_ptr<RunMetadata> run_meta) { } } -bool TFStats::Validate(const Options& opts) { +bool TFStats::Validate(const Options& opts) const { if (opts.step >= 0 && steps_.find(opts.step) == steps_.end()) { fprintf(stderr, "Options -step=%lld not found\n", opts.step); return false; @@ -184,9 +207,9 @@ bool TFStats::Validate(const Options& opts) { return true; } -void TFStats::AddNodeForTest(const string& name, - std::unique_ptr<TFGraphNode> node) { - nodes_map_[name] = std::move(node); +void TFStats::AddNodeForTest(int64 step, std::unique_ptr<TFGraphNode> node) { + steps_.insert(step); + nodes_map_[node->name()] = std::move(node); } } // namespace tfprof } // namespace tensorflow diff --git a/tensorflow/tools/tfprof/internal/tfprof_stats.h b/tensorflow/tools/tfprof/internal/tfprof_stats.h index dfb190e703..b26d274f80 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_stats.h +++ b/tensorflow/tools/tfprof/internal/tfprof_stats.h @@ -59,28 +59,38 @@ class TFStats { const std::map<string, std::unique_ptr<TFGraphNode>>& nodes() const { return nodes_map_; } + const std::set<int64>& steps() const { return steps_; } + bool has_code_traces() const { return has_code_traces_; } + void BuildView(const string& cmd); + void BuildAllViews(); + + // Note: Must first BuildView(view_foo) before ShowXXX(view_foo) methods. + // // Organize the TensorFlow model as different types of views, and generate // outputs for profiling. - const TFGraphNodeProto& ShowGraphNode(const string& cmd, const Options& opts); + // TODO(xpan): Should it return reference here? + const TFGraphNodeProto& ShowGraphNode(const string& cmd, + const Options& opts) const; const TFMultiGraphNodeProto& ShowMultiGraphNode(const string& cmd, - const Options& opts); + const Options& opts) const; // Add a step of run time meta data. - void ParseRunMeta(int64 step, std::unique_ptr<RunMetadata> run_meta); + void AddRunMeta(int64 step, std::unique_ptr<RunMetadata> run_meta); // Add tfprof operation meta data, such as customized op type, float_ops, // and code traces. - void ParseOpLog(std::unique_ptr<OpLog> op_log); + void AddOpLog(std::unique_ptr<OpLog> op_log); // For test purpose only. - void AddNodeForTest(const string& name, std::unique_ptr<TFGraphNode> node); + void AddNodeForTest(int64 step, std::unique_ptr<TFGraphNode> node); private: - bool Validate(const Options& opts); + bool Validate(const Options& opts) const; void ParseGraph(); std::set<int64> steps_; + bool has_code_traces_; std::unique_ptr<GraphDef> graph_; std::unique_ptr<TFScope> scope_view_; std::unique_ptr<TFGraph> graph_view_; diff --git a/tensorflow/tools/tfprof/internal/tfprof_stats_test.cc b/tensorflow/tools/tfprof/internal/tfprof_stats_test.cc index bcd1147c69..00d5d8cdb3 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_stats_test.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_stats_test.cc @@ -66,6 +66,7 @@ class TFProfStatsTest : public ::testing::Test { tf_stats_.reset(new TFStats(std::move(graph_pb), std::move(run_meta_pb), std::move(op_log_pb), std::move(ckpt_reader))); + tf_stats_->BuildAllViews(); } std::unique_ptr<TFStats> tf_stats_; diff --git a/tensorflow/tools/tfprof/internal/tfprof_tensor_test.cc b/tensorflow/tools/tfprof/internal/tfprof_tensor_test.cc index d7cfe7dade..0482657ca5 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_tensor_test.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_tensor_test.cc @@ -50,6 +50,7 @@ class TFProfTensorTest : public ::testing::Test { tf_stats_.reset(new TFStats(std::move(graph_pb), std::move(run_meta_pb), std::move(op_log_pb), std::move(ckpt_reader))); + tf_stats_->BuildAllViews(); } std::unique_ptr<TFStats> tf_stats_; diff --git a/tensorflow/tools/tfprof/internal/tfprof_timeline_test.cc b/tensorflow/tools/tfprof/internal/tfprof_timeline_test.cc index 0e9bb9658c..cad31050a9 100644 --- a/tensorflow/tools/tfprof/internal/tfprof_timeline_test.cc +++ b/tensorflow/tools/tfprof/internal/tfprof_timeline_test.cc @@ -52,6 +52,7 @@ class TFProfTimelineTest : public ::testing::Test { tf_stats_.reset(new TFStats(std::move(graph_pb), std::move(run_meta_pb), nullptr, nullptr)); + tf_stats_->BuildAllViews(); } std::unique_ptr<TFStats> tf_stats_; |