cinn_compiler.cc 7.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright (c) 2021 PaddlePaddle 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 "paddle/fluid/framework/paddle2cinn/cinn_compiler.h"

17
#include <cstdint>
18
#include <iterator>
19 20 21
#include <map>
#include <memory>
#include <string>
22
#include <unordered_map>
23 24 25 26 27 28 29 30 31 32 33

#include "cinn/common/target.h"
#include "cinn/common/type.h"
#include "cinn/frontend/decomposer/use_decomposer.h"
#include "cinn/frontend/pass/use_program_pass.h"
#include "cinn/frontend/program_pass.h"
#include "cinn/frontend/syntax.h"
#include "cinn/hlir/framework/graph.h"
#include "cinn/hlir/framework/graph_compiler.h"
#include "cinn/hlir/framework/pass.h"
#include "cinn/hlir/pass/use_pass.h"
34
#include "paddle/fluid/framework/framework.pb.h"
35 36
#include "paddle/fluid/framework/ir/graph.h"
#include "paddle/fluid/framework/ir/graph_helper.h"
37
#include "paddle/fluid/framework/ir/node.h"
38 39 40
#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/framework/paddle2cinn/cinn_graph_symbolization.h"
#include "paddle/fluid/framework/program_desc.h"
41
#include "paddle/fluid/framework/rw_lock.h"
42
#include "paddle/fluid/framework/tensor.h"
43
#include "paddle/fluid/inference/analysis/dot.h"
44
#include "paddle/fluid/platform/enforce.h"
45
#include "paddle/fluid/string/string_helper.h"
46 47 48 49 50 51

namespace paddle {
namespace framework {
namespace paddle2cinn {

using ir::Graph;
52 53
using ir::Node;
using inference::analysis::Dot;
54 55 56 57 58 59 60 61 62 63 64 65
using ::cinn::common::Target;
using ::cinn::common::Float;
using ::cinn::hlir::framework::GraphCompiler;
using ::cinn::hlir::framework::BuildScope;
using ::cinn::frontend::ProgramPass;
using ::cinn::hlir::framework::ApplyPass;

CinnCompiler* CinnCompiler::GetInstance() {
  static CinnCompiler instance;
  return &instance;
}

66 67 68
const CinnCompiledObject& CinnCompiler::Compile(
    const Graph& graph,
    const std::map<std::string, const LoDTensor*>& input_tensors,
69
    const Target& target, void* stream) {
70
  VLOG(1) << "-- The graph to be compiled is:\n" << VizGraph(graph);
71 72 73 74 75 76 77
  CinnCacheKey cur_key(graph, input_tensors, target.arch_str());
  bool exist = false;
  {
    AutoRDLock r_guard{&rwlock_};
    exist = cache_.count(cur_key) != 0;
  }
  if (!exist) {
78 79
    std::int64_t compiled_num = real_compiled_num_.fetch_add(1);
    auto compiled_res =
80
        CompileGraph(graph, input_tensors, target, compiled_num, stream);
81 82 83 84 85 86 87 88 89 90 91 92 93
    AutoWRLock w_guard{&rwlock_};
    if (!cache_.count(cur_key)) {
      cache_[cur_key] = std::move(compiled_res);
    }
  }
  AutoRDLock guard{&rwlock_};
  const auto& cached_boj = *cache_[cur_key];
  return cached_boj;
}

const CinnCompiledObject& CinnCompiler::Compile(
    const std::string& compilation_key,
    const std::map<std::string, const LoDTensor*>& input_tensors,
94
    const Target& target, void* stream) {
95
  const auto& graph = FindGraph(compilation_key);
96
  return Compile(graph, input_tensors, target, stream);
97 98
}

99 100 101 102 103
std::string CinnCompiler::AddGraph(std::unique_ptr<Graph> graph) {
  std::string graph_key;
  ProgramDesc program;
  GraphToProgram(*graph, &program);
  program.Proto()->SerializeToString(&graph_key);
104 105 106 107 108 109 110 111 112

  PADDLE_ENFORCE_EQ(
      graphs_.count(graph_key), 0,
      platform::errors::PreconditionNotMet(
          "The graph to be added is already in CinnCompiler, which is:\n",
          VizGraph(graph_key).c_str()));
  graphs_[graph_key] = std::move(graph);
  VLOG(4) << "-- Add a graph into CinnCompiler, which is:\n"
          << VizGraph(graph_key);
113 114 115 116 117 118
  return graph_key;
}

const Graph& CinnCompiler::FindGraph(const std::string& graph_key) const {
  PADDLE_ENFORCE_NE(
      graphs_.count(graph_key), 0,
119 120 121
      platform::errors::PreconditionNotMet(
          "Can not find the target graph, of which the key is:\n%s",
          ReadableKey(graph_key).c_str()));
122 123 124
  return *graphs_.at(graph_key);
}

125 126 127 128 129 130
std::string CinnCompiler::VizGraph(const std::string& graph_key) const {
  const Graph& graph = FindGraph(graph_key);
  return VizGraph(graph);
}

std::string CinnCompiler::VizGraph(const Graph& graph) const {
131 132 133 134 135 136 137 138 139 140 141
  Dot dot;
  std::unordered_map<const Node*, std::string> node2dot;
  int id = 0;
  // Create nodes
  for (const Node* n : graph.Nodes()) {
    std::string node_id = "Node" + std::to_string(id++);
    if (n->IsOp()) {
      dot.AddNode(
          node_id,
          {Dot::Attr("shape", "box"), Dot::Attr("style", "rounded,filled,bold"),
           Dot::Attr("color", "#303A3A"), Dot::Attr("fontcolor", "#ffffff")},
142
          n->Name(), true);
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    } else if (n->IsVar()) {
      auto label = n->Name();
      if (n->Var() && n->Var()->GetType() == proto::VarType::LOD_TENSOR) {
        auto shape = n->Var()->GetShape();
        std::vector<std::string> shape_str(shape.size());
        std::transform(shape.begin(), shape.end(), shape_str.begin(),
                       [](const auto& val) { return std::to_string(val); });
        label += "\n" + string::join_strings(shape_str, ',');
      }
      dot.AddNode(
          node_id,
          {Dot::Attr("shape", "box"), Dot::Attr("style", "rounded,filled,bold"),
           Dot::Attr("color", n->Var()->IsParameter() ? "#148b97" : "#dddddd"),
           Dot::Attr("fontcolor",
                     n->Var()->IsParameter() ? "#ffffff" : "#000000")},
158
          label, true);
159 160 161 162 163 164 165 166 167 168
    }
    node2dot[n] = node_id;
  }
  // Create edges
  for (const Node* n : graph.Nodes()) {
    const auto& src_id = node2dot.at(n);
    for (auto* out : n->outputs) {
      const auto& dest_id = node2dot.at(out);
      dot.AddEdge(src_id, dest_id, {});
    }
169
  }
170
  return dot.Build();
171 172
}

173 174
std::string CinnCompiler::ReadableKey(
    const std::string& compilation_key) const {
175
  proto::ProgramDesc desc;
176
  desc.ParseFromString(compilation_key);
177 178 179 180 181 182 183 184 185
  return desc.DebugString();
}

void CinnCompiler::Clear() {
  {
    AutoWRLock guard{&rwlock_};
    graphs_.clear();
    cache_.clear();
  }
H
Huihuang Zheng 已提交
186
  real_compiled_num_.store(0);
187 188 189 190 191
}

std::unique_ptr<CinnCompiledObject> CinnCompiler::CompileGraph(
    const ir::Graph& graph,
    const std::map<std::string, const LoDTensor*>& input_tensors,
192
    const Target& target, std::int64_t compiled_num, void* stream) const {
193
  CinnGraphSymbolization symbol{compiled_num, graph, target, input_tensors};
194 195 196 197
  auto frontend_program = symbol();
  ProgramPass::Apply(&frontend_program, target, {"Decomposer"});
  auto cinn_graph = std::make_shared<::cinn::hlir::framework::Graph>(
      frontend_program, target);
198
  VLOG(1) << "-- The " << compiled_num << "-th compilation ("
199 200 201 202
          << target.arch_str() << "), and its related graph:\n"
          << cinn_graph->Visualize();
  ApplyPass(cinn_graph.get(), "OpFusion");
  auto scope = BuildScope(target, cinn_graph);
203

204 205 206 207
  auto fetch_ids = symbol.GetFetchIds();
  VLOG(4) << "All fetch var ids in CINN: "
          << string::join_strings(fetch_ids, ',');

208 209
  auto graph_compiler =
      std::make_unique<GraphCompiler>(target, scope, cinn_graph);
210 211
  GraphCompiler::CompileOptions options;
  options.with_instantiate_variables = false;
212 213
  auto compiled_res =
      graph_compiler->Build(options, std::move(fetch_ids), stream);
214
  auto compiled_obj = std::make_unique<CinnCompiledObject>();
215 216
  *compiled_obj = {std::move(graph_compiler),
                   std::move(compiled_res.runtime_program), scope,
217 218 219 220 221 222 223
                   symbol.var_model_to_program_map()};
  return compiled_obj;
}

}  // namespace paddle2cinn
}  // namespace framework
}  // namespace paddle