basic_profiler.h 6.0 KB
Newer Older
Y
Yan Chunwei 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// Copyright (c) 2019 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.

/*
 * This file implements BasicProfile, a profiler that helps to profile the basic
 * CPU execution. It can display the min, max, average lantency of the execution
 * of each kernel.
 */
#pragma once
21
#include <gflags/gflags.h>
Y
Yan Chunwei 已提交
22 23 24
#include <time.h>
#include <algorithm>
#include <chrono>  // NOLINT
25
#include <fstream>
Y
Yan Chunwei 已提交
26
#include <limits>
27
#include <map>
Y
Yan Chunwei 已提交
28 29 30 31 32 33 34 35 36 37 38
#include <memory>
#include <string>
#include <vector>
#include "lite/utils/cp_logging.h"
#include "lite/utils/replace_stl/stream.h"
#include "lite/utils/string.h"

namespace paddle {
namespace lite {
namespace profile {

39
struct TimerInfo {
40 41 42 43 44
  uint64_t total_{0};
  uint64_t count_{0};
  uint64_t max_{std::numeric_limits<uint64_t>::min()};
  uint64_t min_{std::numeric_limits<uint64_t>::max()};
  uint64_t timer_{0};
45 46 47 48 49 50 51 52

  double ave() const { return total_ * 1. / count_; }
  double max() const { return max_; }
  double min() const { return min_; }
  uint64_t total() const { return total_; }
  uint64_t count() const { return count_; }
};

Y
Yan Chunwei 已提交
53 54 55 56
/* Base class of all the profile records */
template <typename ChildT>
class TimerBase {
 public:
57 58
  void Start(const std::string& key) { self()->Start(key); }
  void Stop(const std::string& key) { self()->Stop(key); }
59
  void Log(TimerInfo* timer_info, uint64_t x) {
60 61
    return self()->Log(timer_info, x);
  }
Y
Yan Chunwei 已提交
62 63 64
  std::string basic_repr() const { return const_self()->basic_repr(); }

  void SetId(int id) { self()->SetId(id); }
65
  void SetKey(const std::string& key) { self()->SetKey(key); }
Y
Yan Chunwei 已提交
66 67 68 69

  int id() const { return const_self()->id(); }

 protected:
70 71 72
  ChildT* self() { return reinterpret_cast<ChildT*>(this); }
  const ChildT* const_self() const {
    return reinterpret_cast<const ChildT*>(this);
Y
Yan Chunwei 已提交
73 74 75 76 77
  }
};

class BasicTimer : TimerBase<BasicTimer> {
  int id_{-1};
78
  int warmup_{0};
Y
Yan Chunwei 已提交
79
  std::string key_;
80 81
  std::map<std::string, TimerInfo> timer_infos_;
  std::map<std::string, std::string> custom_infos_;
Y
Yan Chunwei 已提交
82 83 84 85 86 87 88

  // TODO(Superjomn) make static
  static const int name_w;
  static const int data_w;

 public:
  BasicTimer() = default;
89
  BasicTimer(int id, const std::string& key) : id_(id), key_(key) {}
Y
Yan Chunwei 已提交
90 91

  void SetId(int id) { id_ = id; }
92

93 94 95
  int id() const {
    CHECK_GE(id_, 0) << "id is not inited";
    return id_;
96 97
  }

98 99
  void SetKey(const std::string& key) { key_ = key; }
  const std::string& key() const { return key_; }
Y
Yan Chunwei 已提交
100

101 102
  void Start(const std::string& timer_key);
  void Stop(const std::string& timer_key);
Y
Yan Chunwei 已提交
103

104
  void Log(TimerInfo* timer_info, uint64_t timespan);
Y
Yan Chunwei 已提交
105

106 107
  void SetCustomInfo(const std::string& key, const std::string& value);
  std::string GetCustomInfo(const std::string& key) const;
Y
Yan Chunwei 已提交
108

109
  const TimerInfo& GetTimerInfo(const std::string& key) const;
Y
Yan Chunwei 已提交
110

111 112
  static std::string basic_repr_header();
  std::string basic_repr() const;
Y
Yan Chunwei 已提交
113 114

  // BasicRecord(const BasicRecord &) = delete;
115
  void operator=(const BasicTimer&) = delete;
116 117

  void SetWarmup(int warmup_times);
Y
Yan Chunwei 已提交
118 119 120 121 122 123 124 125
};

/*
 * A basic profiler, with each record logs the total latency.
 */
template <typename TimerT>
class BasicProfiler {
 public:
126
  explicit BasicProfiler(const std::string& name) : name_(name) {}
Y
Yan Chunwei 已提交
127 128
  using record_t = TimerT;

129
  static BasicProfiler& Global() {
Y
Yan Chunwei 已提交
130 131 132 133
    static std::unique_ptr<BasicProfiler> x(new BasicProfiler("[global]"));
    return *x;
  }

134
  record_t& NewRcd(const std::string& key) {
Y
Yan Chunwei 已提交
135 136 137
    records_.emplace_back();
    records_.back().SetId(records_.size() - 1);
    records_.back().SetKey(key);
138
    records_.back().SetWarmup(warmup_);
Y
Yan Chunwei 已提交
139 140 141
    return records_.back();
  }

142
  const record_t& record(int id) {
Y
Yan Chunwei 已提交
143 144 145 146 147
    CHECK_LT(id, records_.size());
    CHECK_GE(id, 0);
    return records_[id];
  }

148
  record_t* mutable_record(int id) {
Y
Yan Chunwei 已提交
149 150 151 152 153 154 155
    CHECK_GE(id, 0);
    CHECK_LT(static_cast<size_t>(id), records_.size());
    return &records_[id];
  }

  std::string basic_repr() const {
    STL::stringstream ss;
156
    for (const auto& rcd : records_) {
Y
Yan Chunwei 已提交
157 158 159 160 161
      ss << rcd.basic_repr() << "\n";
    }
    return ss.str();
  }

162 163
  std::string summary_repr_header() const;
  std::string summary_repr() const;
164

165 166 167 168 169 170 171 172 173
  void SetWarmup(int warmup_times) {
    CHECK_GE(warmup_times, 0) << "warmup times must >= 0";
    // Instruction and kernel share the common BasicTimer instance, so the
    // warmup count
    // will be decrease twice when instruction execute once
    // TODO(sangoly): fix the ugly code.
    warmup_ = warmup_times * 2;
  }

174 175
  ~BasicProfiler();

Y
Yan Chunwei 已提交
176 177 178
 private:
  std::string name_;
  std::vector<record_t> records_;
179
  int warmup_{0};
Y
Yan Chunwei 已提交
180 181 182
};

struct ProfileBlock {
183 184 185 186 187 188 189 190 191 192
  explicit ProfileBlock(int id, const std::string& key) : id_(id), key_(key) {
    BasicProfiler<BasicTimer>::Global().mutable_record(id_)->Start(key_);
  }

  void Record() {
    if (has_recorded_) {
      LOG(FATAL) << "You can only call Record() once";
    }
    BasicProfiler<BasicTimer>::Global().mutable_record(id_)->Stop(key_);
    has_recorded_ = true;
Y
Yan Chunwei 已提交
193 194 195
  }

  ~ProfileBlock() {
196 197 198
    if (!has_recorded_) {
      BasicProfiler<BasicTimer>::Global().mutable_record(id_)->Stop(key_);
    }
Y
Yan Chunwei 已提交
199 200 201 202
  }

 private:
  int id_{};
203 204
  bool has_recorded_{false};
  std::string key_{};
Y
Yan Chunwei 已提交
205 206
};

207 208 209 210 211 212 213 214
#define LITE_PROFILE_ONE(key__)                            \
  static int key__##__profiler_id =                        \
      ::paddle::lite::profile::BasicProfiler<              \
          ::paddle::lite::profile::BasicTimer>::Global()   \
          .NewRcd(#key__)                                  \
          .id();                                           \
  ::paddle::lite::profile::ProfileBlock key__##profiler__( \
      key__##__profiler_id, #key__);
Y
Yan Chunwei 已提交
215 216 217 218

}  // namespace profile
}  // namespace lite
}  // namespace paddle