aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/cc/profiler
diff options
context:
space:
mode:
authorGravatar A. Unique TensorFlower <gardener@tensorflow.org>2018-01-09 17:05:15 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-01-09 17:13:03 -0800
commit118495de6165237a7027f5d8b77db833ac7210f2 (patch)
tree187b32bd553da19278096af2f210741d621a1b84 /tensorflow/cc/profiler
parentcf3fb6bc1dfe5862bf03af2a38d0a52463edd77a (diff)
profiler C++ API.
PiperOrigin-RevId: 181397308
Diffstat (limited to 'tensorflow/cc/profiler')
-rw-r--r--tensorflow/cc/profiler/BUILD36
-rw-r--r--tensorflow/cc/profiler/profiler.cc57
-rw-r--r--tensorflow/cc/profiler/profiler.h97
-rw-r--r--tensorflow/cc/profiler/profiler_test.cc177
4 files changed, 367 insertions, 0 deletions
diff --git a/tensorflow/cc/profiler/BUILD b/tensorflow/cc/profiler/BUILD
new file mode 100644
index 0000000000..00799526fc
--- /dev/null
+++ b/tensorflow/cc/profiler/BUILD
@@ -0,0 +1,36 @@
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test")
+
+tf_cuda_cc_test(
+ name = "profiler_test",
+ srcs = ["profiler_test.cc"],
+ deps = [
+ ":profiler",
+ "//tensorflow/cc:cc_ops",
+ "//tensorflow/core:core_cpu",
+ "//tensorflow/core:framework",
+ "//tensorflow/core:lib",
+ "//tensorflow/core:protos_all_cc",
+ "//tensorflow/core:tensorflow",
+ "//tensorflow/core:test",
+ "//tensorflow/core:test_main",
+ ],
+)
+
+cc_library(
+ name = "profiler",
+ srcs = ["profiler.cc"],
+ hdrs = ["profiler.h"],
+ deps = [
+ "//tensorflow/core:lib",
+ "//tensorflow/core:protos_all_cc",
+ "//tensorflow/core/profiler:protos_all_cc",
+ "//tensorflow/core/profiler:tfprof_options",
+ "//tensorflow/core/profiler/internal:tfprof_stats",
+ ],
+)
diff --git a/tensorflow/cc/profiler/profiler.cc b/tensorflow/cc/profiler/profiler.cc
new file mode 100644
index 0000000000..3e55bac73e
--- /dev/null
+++ b/tensorflow/cc/profiler/profiler.cc
@@ -0,0 +1,57 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+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 "tensorflow/cc/profiler/profiler.h"
+
+namespace tensorflow {
+namespace tfprof {
+
+Profiler::Profiler(const GraphDef& graph) {
+ std::unique_ptr<GraphDef> graph_ptr(new GraphDef());
+ *graph_ptr = graph;
+ stats_.reset(new TFStats(std::move(graph_ptr), nullptr, nullptr, nullptr));
+}
+
+void Profiler::AddStep(int64 step, const RunMetadata& run_meta) {
+ std::unique_ptr<RunMetadata> run_meta_ptr(new RunMetadata());
+ *run_meta_ptr = run_meta;
+ stats_->AddRunMeta(step, std::move(run_meta_ptr));
+}
+
+GraphNodeProto Profiler::ProfileGraph(const Options& options) {
+ stats_->BuildView(kCmds[1]);
+ return stats_->ShowGraphNode(kCmds[1], options);
+}
+
+GraphNodeProto Profiler::ProfileNameScope(const Options& options) {
+ stats_->BuildView(kCmds[0]);
+ return stats_->ShowGraphNode(kCmds[0], options);
+}
+
+MultiGraphNodeProto Profiler::ProfileOperations(const Options& options) {
+ stats_->BuildView(kCmds[3]);
+ return stats_->ShowMultiGraphNode(kCmds[3], options);
+}
+
+Status Profiler::SerializeToString(string* content) {
+ if (!content) {
+ return Status(error::Code::INVALID_ARGUMENT,
+ "Cannot use null string pointer for SerializeToString.");
+ }
+ stats_->SerializeToString(content);
+ return Status::OK();
+}
+
+} // namespace tfprof
+} // namespace tensorflow
diff --git a/tensorflow/cc/profiler/profiler.h b/tensorflow/cc/profiler/profiler.h
new file mode 100644
index 0000000000..e1ce315d3c
--- /dev/null
+++ b/tensorflow/cc/profiler/profiler.h
@@ -0,0 +1,97 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+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.
+==============================================================================*/
+
+#ifndef THIRD_PARTY_TENSORFLOW_CC_PROFILER_PROFILER_H_
+#define THIRD_PARTY_TENSORFLOW_CC_PROFILER_PROFILER_H_
+
+#include "tensorflow/core/framework/graph.pb.h"
+#include "tensorflow/core/lib/core/status.h"
+#include "tensorflow/core/profiler/internal/tfprof_stats.h"
+#include "tensorflow/core/profiler/tfprof_options.h"
+#include "tensorflow/core/profiler/tfprof_output.pb.h"
+
+namespace tensorflow {
+namespace tfprof {
+
+/// @addtogroup core
+/// @{
+
+/// A `Profiler` object lets the caller profile the execution of a graph.
+///
+/// Example:
+/// // First build a graph and run tracing.
+/// Scope root = Scope::NewRootScope();
+/// auto a = Placeholder(root, DT_INT32);
+/// auto c = Add(root, a, {41});
+///
+/// ClientSession session(root);
+/// std::vector<Tensor> outputs;
+/// RunOptions run_options;
+/// run_options.set_trace_level(RunOptions::FULL_TRACE);
+/// RunMetadata run_meta;
+/// Status s = session.Run(run_options, { {a, {1}} }, {c}, &outputs,
+/// &run_meta);
+/// if (!s.ok()) { ... }
+///
+/// // Then create profiler to do profiling.
+/// GraphDef graph;
+/// root.ToGraphDef(&graph);
+/// Profiler profiler(graph);
+/// profiler.AddStep(0, run_meta);
+/// Options opts = ... // TODO(xpan): Support option building API.
+/// MultiGraphNodeProto r = profiler.ProfileOperations(opts);
+///
+class Profiler {
+ public:
+ /// `graph` is the model's GraphDef.
+ Profiler(const GraphDef& graph);
+
+ /// Adds tracing information `run_meta` to profiler. A `run_meta` is
+ /// generated by a TensorFlow session run call. `step` is the key
+ /// to the `run_meta`. When calling ProfileXXX methods, caller can specify
+ /// `step` in `options` to seletively profile the corresponding `run_meta`.
+ /// Multiple different `run_meta` can be keyed by the same `step` in order
+ /// to group them together.
+ void AddStep(int64 step, const RunMetadata& run_meta);
+
+ /// Profiles the model by organizing nodes in graph structure.
+ /// Each node is an op and the nodes are contected by the op inputs/outputs.
+ GraphNodeProto ProfileGraph(const Options& options);
+
+ /// Profiles the model by organizing nodes in name scope structure.
+ /// Each node is an op, and nodes are organized by the ops' name
+ /// scope, similar to a filesystem tree.
+ /// E.g. /foo is the root of operation /foo/matmul_1 and foo/conv_2.
+ GraphNodeProto ProfileNameScope(const Options& options);
+
+ /// Profiles the model by organizing nodes by operation types.
+ /// Each node is an operation type (e.g. Conv2D or MatMul), containing all
+ /// ops belonging to that type in the model.
+ MultiGraphNodeProto ProfileOperations(const Options& options);
+
+ /// Serialize the profile content (ProfileProto) into a binary string,
+ /// User can write the string to file for offline analysis by
+ /// tfprof command-line tools or graphical user interface.
+ Status SerializeToString(string* content);
+
+ private:
+ std::unique_ptr<TFStats> stats_;
+};
+/// @}
+
+} // namespace tfprof
+} // namespace tensorflow
+
+#endif // THIRD_PARTY_TENSORFLOW_CC_PROFILER_PROFILER_H_
diff --git a/tensorflow/cc/profiler/profiler_test.cc b/tensorflow/cc/profiler/profiler_test.cc
new file mode 100644
index 0000000000..280cd74827
--- /dev/null
+++ b/tensorflow/cc/profiler/profiler_test.cc
@@ -0,0 +1,177 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+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 "tensorflow/core/platform/test.h"
+
+#include "tensorflow/cc/ops/standard_ops.h"
+#include "tensorflow/cc/profiler/profiler.h"
+#include "tensorflow/core/framework/graph.pb.h"
+#include "tensorflow/core/framework/tensor.h"
+#include "tensorflow/core/graph/default_device.h"
+#include "tensorflow/core/lib/io/path.h"
+#include "tensorflow/core/platform/env.h"
+#include "tensorflow/core/public/session.h"
+
+namespace tensorflow {
+namespace tfprof {
+
+class ProfilerTest : public ::testing::Test {
+ protected:
+ ProfilerTest() {}
+};
+
+GraphDef CreateGraphDef() {
+ Scope root = Scope::NewRootScope();
+
+ auto a = ops::Const<float>(root, {{3, 2}, {-1, 0}});
+
+ auto x = ops::Const(root.WithOpName("x"), {{1.f}, {1.f}});
+
+ auto y = ops::MatMul(root.WithOpName("y"), a, x);
+
+ auto y2 = ops::Square(root, y);
+
+ auto y2_sum = ops::Sum(root, y2, 0);
+
+ auto y_norm = ops::Sqrt(root, y2_sum);
+
+ auto y_div = ops::Div(root.WithOpName("y_normalized"), y, y_norm);
+
+ GraphDef def;
+ TF_CHECK_OK(root.ToGraphDef(&def));
+
+ return def;
+}
+
+Options Default() {
+ Options opts(1000, /* max_depth */
+ 0, /* min_bytes */
+ 0, /* min_peak_bytes */
+ 0, /* min_residual_bytes */
+ 0, /* min_output_bytes */
+ 0, /* min_micros */
+ 0, /* min_accelerator_micros */
+ 0, /* min_cpu_micros */
+ 0, /* min_params */
+ 0, /* min_float_ops */
+ 0, /* min_occurrence */
+ 0, /* step */
+ "name", /* order_by */
+ {".*"}, /* account_type_regexes */
+ {".*"}, /* start_name_regexes */
+ {}, /* trim_name_regexes */
+ {".*"}, {}, /* hide_name_regexes */
+ false, /* account_displayed_op_only */
+ {"micros"}, /* select */
+ {"none"}, /* output_type */
+ {});
+ return opts;
+}
+
+template <typename T>
+const T* ExtractNode(const T& pb, const string& name) {
+ if (pb.name() == name) {
+ return &pb;
+ }
+ for (const T& c : pb.children()) {
+ const T* ret = ExtractNode(c, name);
+ if (ret) return ret;
+ }
+ return nullptr;
+}
+
+TEST_F(ProfilerTest, Basics) {
+ SessionOptions options;
+ options.config.set_allow_soft_placement(true);
+ std::unique_ptr<Session> session(NewSession(options));
+ GraphDef def = CreateGraphDef();
+ if (options.target.empty()) {
+ graph::SetDefaultDevice("/gpu:0", &def);
+ }
+
+ TF_CHECK_OK(session->Create(def));
+
+ Tensor x(DT_FLOAT, TensorShape({2, 1}));
+ auto x_flat = x.flat<float>();
+ x_flat.setRandom();
+ Eigen::Tensor<float, 0, Eigen::RowMajor> inv_norm =
+ x_flat.square().sum().sqrt().inverse();
+ x_flat = x_flat * inv_norm();
+
+ std::vector<Tensor> outputs;
+ RunOptions run_options;
+ run_options.set_trace_level(RunOptions::FULL_TRACE);
+ RunMetadata run_metadata;
+ outputs.clear();
+
+ Profiler profiler(def);
+ for (int i = 0; i < 2; ++i) {
+ TF_CHECK_OK(session->Run(run_options, {{"x", x}}, {"y:0", "y_normalized:0"},
+ {}, &outputs, &run_metadata));
+ profiler.AddStep(i, run_metadata);
+ CHECK_EQ(size_t{2}, outputs.size());
+ }
+
+ std::vector<DeviceAttributes> resp;
+ TF_CHECK_OK(session->ListDevices(&resp));
+ bool has_gpu = false;
+ for (const auto& dev : resp) {
+ if (dev.device_type() == "GPU") {
+ has_gpu = true;
+ }
+ }
+
+ GraphNodeProto ret = profiler.ProfileNameScope(Default());
+ const GraphNodeProto* matmul = ExtractNode(ret, "y");
+ EXPECT_TRUE(matmul);
+ EXPECT_GT(matmul->exec_micros(), 0);
+ if (has_gpu) {
+ EXPECT_GT(matmul->accelerator_exec_micros(), 0);
+ } else {
+ EXPECT_EQ(matmul->accelerator_exec_micros(), 0);
+ }
+ const GraphNodeProto* square = ExtractNode(ret, "Square");
+ EXPECT_TRUE(square);
+ EXPECT_GT(square->exec_micros(), 0);
+ if (has_gpu) {
+ EXPECT_GT(square->accelerator_exec_micros(), 0);
+ } else {
+ EXPECT_EQ(square->accelerator_exec_micros(), 0);
+ }
+
+ Options opts2 = Default();
+ opts2.output_type = "timeline";
+ string timeline_file = io::JoinPath(testing::TmpDir(), "timeline");
+ opts2.output_options["outfile"] = timeline_file;
+ GraphNodeProto ret2 = profiler.ProfileGraph(opts2);
+ string s;
+ TF_CHECK_OK(ReadFileToString(Env::Default(), timeline_file + "_0", &s));
+ EXPECT_TRUE(s.find("Square") != s.npos);
+
+ MultiGraphNodeProto ret3 = profiler.ProfileOperations(Default());
+ const MultiGraphNodeProto* matmul2 = ExtractNode(ret3, "MatMul");
+ EXPECT_TRUE(matmul2);
+ EXPECT_GT(matmul2->exec_micros(), 0);
+ if (has_gpu) {
+ EXPECT_GT(matmul2->accelerator_exec_micros(), 0);
+ } else {
+ EXPECT_EQ(matmul2->accelerator_exec_micros(), 0);
+ }
+
+ TF_CHECK_OK(session->Close());
+}
+
+} // namespace tfprof
+} // namespace tensorflow