enforce.h 13.3 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

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. */

#pragma once

P
peizhilin 已提交
17 18 19 20 21
#ifdef _WIN32
#undef __AVX__
#undef __AVX2__
#endif

22 23 24 25
#ifdef __GNUC__
#include <cxxabi.h>  // for __cxa_demangle
#endif               // __GNUC__

D
dzhwinter 已提交
26 27 28
#if defined(_WIN32)
#define NOMINMAX  // msvc max/min macro conflict with std::min/max
#define GLOG_NO_ABBREVIATED_SEVERITIES  // msvc conflict logging with windows.h
D
dzhwinter 已提交
29
#define GOOGLE_GLOG_DLL_DECL
D
dzhwinter 已提交
30 31
#endif

32 33 34 35 36 37 38 39
#ifdef PADDLE_WITH_CUDA
#include <cublas_v2.h>
#include <cudnn.h>
#include <curand.h>
#include <thrust/system/cuda/error.h>
#include <thrust/system_error.h>
#endif  // PADDLE_WITH_CUDA

Y
Yu Yang 已提交
40
#include <iomanip>
L
liaogang 已提交
41
#include <memory>
42 43 44
#include <sstream>
#include <stdexcept>
#include <string>
45

46
#include "glog/logging.h"
Y
Yi Wang 已提交
47
#include "paddle/fluid/platform/macros.h"
D
dzhwinter 已提交
48
#include "paddle/fluid/platform/port.h"
49 50
#include "paddle/fluid/string/printf.h"
#include "paddle/fluid/string/to_string.h"
51

52
#ifdef PADDLE_WITH_CUDA
Y
Yi Wang 已提交
53 54 55
#include "paddle/fluid/platform/dynload/cublas.h"
#include "paddle/fluid/platform/dynload/cudnn.h"
#include "paddle/fluid/platform/dynload/curand.h"
D
dzhwinter 已提交
56
#if !defined(__APPLE__) && !defined(_WIN32)
Y
Yi Wang 已提交
57
#include "paddle/fluid/platform/dynload/nccl.h"
Y
Yi Wang 已提交
58 59
#endif  // __APPLE__
#endif  // PADDLE_WITH_CUDA
60 61 62 63

namespace paddle {
namespace platform {

L
liaogang 已提交
64 65 66 67 68 69 70 71 72 73 74
#ifdef __GNUC__
inline std::string demangle(std::string name) {
  int status = -4;  // some arbitrary value to eliminate the compiler warning
  std::unique_ptr<char, void (*)(void*)> res{
      abi::__cxa_demangle(name.c_str(), NULL, NULL, &status), std::free};
  return (status == 0) ? res.get() : name;
}
#else
inline std::string demangle(std::string name) { return name; }
#endif

75 76 77 78
struct EnforceNotMet : public std::exception {
  std::exception_ptr exp_;
  std::string err_str_;
  EnforceNotMet(std::exception_ptr e, const char* f, int l) : exp_(e) {
Y
Yu Yang 已提交
79
    static constexpr int TRACE_STACK_LIMIT = 100;
80 81 82
    try {
      std::rethrow_exception(exp_);
    } catch (const std::exception& exp) {
Y
Yu Yang 已提交
83
      std::ostringstream sout;
84

F
fengjiayi 已提交
85
      sout << string::Sprintf("%s at [%s:%d]", exp.what(), f, l) << std::endl;
86
      sout << "PaddlePaddle Call Stacks: " << std::endl;
D
dzhwinter 已提交
87
#if !defined(_WIN32)
Y
Yu Yang 已提交
88
      void* call_stack[TRACE_STACK_LIMIT];
89 90 91 92 93
      auto size = backtrace(call_stack, TRACE_STACK_LIMIT);
      auto symbols = backtrace_symbols(call_stack, size);

      Dl_info info;
      for (int i = 0; i < size; ++i) {
L
liaogang 已提交
94 95
        if (dladdr(call_stack[i], &info) && info.dli_sname) {
          auto demangled = demangle(info.dli_sname);
96 97 98 99 100
          auto addr_offset = static_cast<char*>(call_stack[i]) -
                             static_cast<char*>(info.dli_saddr);
          sout << string::Sprintf("%-3d %*0p %s + %zd\n", i,
                                  2 + sizeof(void*) * 2, call_stack[i],
                                  demangled, addr_offset);
101
        } else {
102
          sout << string::Sprintf("%-3d %*0p\n", i, 2 + sizeof(void*) * 2,
103 104
                                  call_stack[i]);
        }
Y
Yu Yang 已提交
105
      }
106
      free(symbols);
D
dzhwinter 已提交
107 108 109
#else
      sout << "Windows not support stack backtrace yet.";
#endif
Y
Yu Yang 已提交
110
      err_str_ = sout.str();
111 112 113 114 115 116
    }
  }

  const char* what() const noexcept { return err_str_.c_str(); }
};

117 118 119
struct EOFException : public std::exception {
  std::string err_str_;
  EOFException(const char* err_msg, const char* f, int l) {
F
fengjiayi 已提交
120
    err_str_ = string::Sprintf("%s at [%s:%d]", err_msg, f, l);
121 122 123 124 125
  }

  const char* what() const noexcept { return err_str_.c_str(); }
};

L
liaogang 已提交
126 127 128 129 130
// Because most enforce conditions would evaluate to true, we can use
// __builtin_expect to instruct the C++ compiler to generate code that
// always forces branch prediction of true.
// This generates faster binary code. __builtin_expect is since C++11.
// For more details, please check https://stackoverflow.com/a/43870188/724872.
D
dzhwinter 已提交
131
#if !defined(_WIN32)
132
#define UNLIKELY(condition) __builtin_expect(static_cast<bool>(condition), 0)
D
dzhwinter 已提交
133 134
#else
// there is no equivalent intrinsics in msvc.
135
#define UNLIKELY(condition) (condition == 0)
D
dzhwinter 已提交
136
#endif
137

138 139 140 141 142 143 144
#if !defined(_WIN32)
#define LIKELY(condition) __builtin_expect(static_cast<bool>(condition), 1)
#else
// there is no equivalent intrinsics in msvc.
#define LIKELY(condition) (condition != 0)
#endif

L
liaogang 已提交
145 146
template <typename... Args>
inline typename std::enable_if<sizeof...(Args) != 0, void>::type throw_on_error(
Y
Yu Yang 已提交
147
    bool stat, const Args&... args) {
L
liaogang 已提交
148
  if (UNLIKELY(!(stat))) {
149
#ifndef REPLACE_ENFORCE_GLOG
150
    throw std::runtime_error(string::Sprintf(args...));
151 152 153
#else
    LOG(FATAL) << string::Sprintf(args...);
#endif
L
liaogang 已提交
154 155 156
  }
}

157
#ifdef PADDLE_WITH_CUDA
158 159

template <typename... Args>
L
liaogang 已提交
160 161
inline typename std::enable_if<sizeof...(Args) != 0, void>::type throw_on_error(
    cudaError_t e, const Args&... args) {
L
liaogang 已提交
162
  if (UNLIKELY(e)) {
163
#ifndef REPLACE_ENFORCE_GLOG
164 165
    throw thrust::system_error(e, thrust::cuda_category(),
                               string::Sprintf(args...));
166 167 168
#else
    LOG(FATAL) << string::Sprintf(args...);
#endif
169 170 171 172
  }
}

template <typename... Args>
L
liaogang 已提交
173 174
inline typename std::enable_if<sizeof...(Args) != 0, void>::type throw_on_error(
    curandStatus_t stat, const Args&... args) {
175
  if (stat != CURAND_STATUS_SUCCESS) {
176
#ifndef REPLACE_ENFORCE_GLOG
177 178
    throw thrust::system_error(cudaErrorLaunchFailure, thrust::cuda_category(),
                               string::Sprintf(args...));
179 180 181
#else
    LOG(FATAL) << string::Sprintf(args...);
#endif
182 183 184 185
  }
}

template <typename... Args>
L
liaogang 已提交
186 187
inline typename std::enable_if<sizeof...(Args) != 0, void>::type throw_on_error(
    cudnnStatus_t stat, const Args&... args) {
188 189 190
  if (stat == CUDNN_STATUS_SUCCESS) {
    return;
  } else {
191
#ifndef REPLACE_ENFORCE_GLOG
192 193
    throw std::runtime_error(platform::dynload::cudnnGetErrorString(stat) +
                             string::Sprintf(args...));
194 195 196
#else
    LOG(FATAL) << string::Sprintf(args...);
#endif
197 198 199 200
  }
}

template <typename... Args>
L
liaogang 已提交
201 202
inline typename std::enable_if<sizeof...(Args) != 0, void>::type throw_on_error(
    cublasStatus_t stat, const Args&... args) {
L
liaogang 已提交
203
  std::string err;
204 205 206
  if (stat == CUBLAS_STATUS_SUCCESS) {
    return;
  } else if (stat == CUBLAS_STATUS_NOT_INITIALIZED) {
L
liaogang 已提交
207
    err = "CUBLAS: not initialized, ";
208
  } else if (stat == CUBLAS_STATUS_ALLOC_FAILED) {
L
liaogang 已提交
209
    err = "CUBLAS: alloc failed, ";
210
  } else if (stat == CUBLAS_STATUS_INVALID_VALUE) {
L
liaogang 已提交
211
    err = "CUBLAS: invalid value, ";
212
  } else if (stat == CUBLAS_STATUS_ARCH_MISMATCH) {
L
liaogang 已提交
213
    err = "CUBLAS: arch mismatch, ";
214
  } else if (stat == CUBLAS_STATUS_MAPPING_ERROR) {
L
liaogang 已提交
215
    err = "CUBLAS: mapping error, ";
216
  } else if (stat == CUBLAS_STATUS_EXECUTION_FAILED) {
L
liaogang 已提交
217
    err = "CUBLAS: execution failed, ";
218
  } else if (stat == CUBLAS_STATUS_INTERNAL_ERROR) {
L
liaogang 已提交
219
    err = "CUBLAS: internal error, ";
220
  } else if (stat == CUBLAS_STATUS_NOT_SUPPORTED) {
L
liaogang 已提交
221
    err = "CUBLAS: not supported, ";
222
  } else if (stat == CUBLAS_STATUS_LICENSE_ERROR) {
L
liaogang 已提交
223
    err = "CUBLAS: license error, ";
224
  }
225
#ifndef REPLACE_ENFORCE_GLOG
226
  throw std::runtime_error(err + string::Sprintf(args...));
227 228 229
#else
  LOG(FATAL) << err << string::Sprintf(args...);
#endif
230 231
}

D
done  
dzhwinter 已提交
232
#if !defined(__APPLE__) && !defined(_WIN32)
Y
Yu Yang 已提交
233 234 235 236 237 238
template <typename... Args>
inline typename std::enable_if<sizeof...(Args) != 0, void>::type throw_on_error(
    ncclResult_t stat, const Args&... args) {
  if (stat == ncclSuccess) {
    return;
  } else {
239
#ifndef REPLACE_ENFORCE_GLOG
Y
Yu Yang 已提交
240 241
    throw std::runtime_error(platform::dynload::ncclGetErrorString(stat) +
                             string::Sprintf(args...));
242 243 244 245
#else
    LOG(FATAL) << platform::dynload::ncclGetErrorString(stat)
               << string::Sprintf(args...);
#endif
Y
Yu Yang 已提交
246 247
  }
}
D
dzhwinter 已提交
248
#endif  // __APPLE__ and windows
249
#endif  // PADDLE_WITH_CUDA
250

L
liaogang 已提交
251 252 253 254 255
template <typename T>
inline void throw_on_error(T e) {
  throw_on_error(e, "");
}

D
dzhwinter 已提交
256
#if !defined(_WIN32)
Q
qijun 已提交
257 258 259 260 261 262
#define PADDLE_THROW(...)                                              \
  do {                                                                 \
    throw ::paddle::platform::EnforceNotMet(                           \
        std::make_exception_ptr(                                       \
            std::runtime_error(paddle::string::Sprintf(__VA_ARGS__))), \
        __FILE__, __LINE__);                                           \
Y
Yu Yang 已提交
263
  } while (false)
L
liaogang 已提交
264

265
#ifndef REPLACE_ENFORCE_GLOG
266 267 268 269 270 271 272 273
#define PADDLE_ENFORCE(...)                                             \
  do {                                                                  \
    try {                                                               \
      ::paddle::platform::throw_on_error(__VA_ARGS__);                  \
    } catch (...) {                                                     \
      throw ::paddle::platform::EnforceNotMet(std::current_exception(), \
                                              __FILE__, __LINE__);      \
    }                                                                   \
Y
Yu Yang 已提交
274
  } while (false)
275

D
dzhwinter 已提交
276
#else
D
dzhwinter 已提交
277
#define PADDLE_ENFORCE(...) ::paddle::platform::throw_on_error(__VA_ARGS__);
D
dzhwinter 已提交
278 279
#endif  // REPLACE_ENFORCE_GLOG

D
dzhwinter 已提交
280 281 282 283 284 285
#else  // !_WIN32
// disable enforce, caused by the varardic macro exception error
#define PADDLE_THROW(x)                                      \
  do {                                                       \
    throw std::make_exception_ptr(                           \
        std::runtime_error("Windows disable the enforce.")); \
D
dzhwinter 已提交
286 287
  } while (false)

D
dzhwinter 已提交
288
#define PADDLE_ENFORCE(x, ...) x
D
dzhwinter 已提交
289
#endif  // !_WIN32
D
dzhwinter 已提交
290

D
dzhwinter 已提交
291 292 293 294 295 296
#define PADDLE_THROW_EOF()                                                     \
  do {                                                                         \
    throw ::paddle::platform::EOFException("There is no next data.", __FILE__, \
                                           __LINE__);                          \
  } while (false)

S
Superjom 已提交
297 298 299 300 301 302 303
/*
 * Some enforce helpers here, usage:
 *    int a = 1;
 *    int b = 2;
 *    PADDLE_ENFORCE_EQ(a, b);
 *
 *    will raise an expression described as follows:
C
chenweihang 已提交
304
 *    "Enforce failed. Expected input a == b, but received a(1) != b(2)."
305
 *      with detailed stack information.
S
Superjom 已提交
306 307 308 309
 *
 *    extra messages is also supported, for example:
 *    PADDLE_ENFORCE(a, b, "some simple enforce failed between %d numbers", 2)
 */
D
dzhwinter 已提交
310
#if !defined(_WIN32)
S
Superjom 已提交
311 312 313 314 315 316 317 318 319 320 321 322
#define PADDLE_ENFORCE_EQ(__VAL0, __VAL1, ...) \
  __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, ==, !=, __VA_ARGS__)
#define PADDLE_ENFORCE_NE(__VAL0, __VAL1, ...) \
  __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, !=, ==, __VA_ARGS__)
#define PADDLE_ENFORCE_GT(__VAL0, __VAL1, ...) \
  __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, >, <=, __VA_ARGS__)
#define PADDLE_ENFORCE_GE(__VAL0, __VAL1, ...) \
  __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, >=, <, __VA_ARGS__)
#define PADDLE_ENFORCE_LT(__VAL0, __VAL1, ...) \
  __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, <, >=, __VA_ARGS__)
#define PADDLE_ENFORCE_LE(__VAL0, __VAL1, ...) \
  __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, <=, >, __VA_ARGS__)
D
dzhwinter 已提交
323

324 325 326 327 328 329 330 331 332 333
#define PADDLE_ENFORCE_NOT_NULL(__VAL, ...)                  \
  do {                                                       \
    if (UNLIKELY(nullptr == (__VAL))) {                      \
      PADDLE_THROW(#__VAL " should not be null\n%s",         \
                   paddle::string::Sprintf("" __VA_ARGS__)); \
    }                                                        \
  } while (0)

#define __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, __CMP, __INV_CMP, ...)  \
  do {                                                                  \
C
chengduo 已提交
334
    if (UNLIKELY(!((__VAL0)__CMP(__VAL1)))) {                           \
C
chenweihang 已提交
335
      PADDLE_THROW("Enforce failed. Expected %s " #__CMP                \
336 337 338
                   " %s, but received %s:%s " #__INV_CMP " %s:%s.\n%s", \
                   #__VAL0, #__VAL1, #__VAL0,                           \
                   paddle::string::to_string(__VAL0), #__VAL1,          \
339 340 341 342
                   paddle::string::to_string(__VAL1),                   \
                   paddle::string::Sprintf("" __VA_ARGS__));            \
    }                                                                   \
  } while (0)
D
dzhwinter 已提交
343
#else
D
dzhwinter 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
#define PADDLE_ENFORCE_EQ(__VAL0, __VAL1, ...) ((__VAL0) == (__VAL1))
#define PADDLE_ENFORCE_NE(__VAL0, __VAL1, ...) ((__VAL0) != (__VAL1))
#define PADDLE_ENFORCE_GT(__VAL0, __VAL1, ...) ((__VAL0) > (__VAL1))
#define PADDLE_ENFORCE_GE(__VAL0, __VAL1, ...) ((__VAL0) >= (__VAL1))
#define PADDLE_ENFORCE_LT(__VAL0, __VAL1, ...) ((__VAL0) < (__VAL1))
#define PADDLE_ENFORCE_LE(__VAL0, __VAL1, ...) ((__VAL0) <= (__VAL1))

#define __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, __CMP, __INV_CMP, ...) \
  do {                                                                 \
    if (!((__VAL0)__CMP(__VAL1))) {                                    \
      PADDLE_THROW("Windows disable the enforce. Enforce failed.");    \
    }                                                                  \
  } while (0)
#define PADDLE_ENFORCE_NOT_NULL(__VAL1, ...)                       \
  do {                                                             \
    if (nullptr == (__VAL1)) {                                     \
D
dzhwinter 已提交
360
      PADDLE_THROW("Windows disable the enforce. Enforce failed"); \
D
dzhwinter 已提交
361 362 363
    }                                                              \
  } while (0)
#endif  // !_WIN32
S
add EQ  
Superjom 已提交
364

365 366
}  // namespace platform
}  // namespace paddle