diff --git a/doc/v2/howto/capi/compile_paddle_lib_cn.md b/doc/v2/howto/capi/compile_paddle_lib_cn.md
index e223fd33a8420abcdfdad53d1cfc5ed160a1b37e..2c87e9afc6911526cd51d6c691f262960accc9e8 100644
--- a/doc/v2/howto/capi/compile_paddle_lib_cn.md
+++ b/doc/v2/howto/capi/compile_paddle_lib_cn.md
@@ -18,7 +18,7 @@
cpu_avx_openblas |
-暂无 |
+paddle.tgz |
cpu_noavx_openblas |
@@ -35,7 +35,12 @@
cuda8.0_cudnn7_avx_mkl |
paddle.tgz |
-
+
+
+cuda9.0_cudnn7_avx_mkl |
+paddle.tgz |
+
+
### 从源码编译
diff --git a/doc/v2/howto/capi/compile_paddle_lib_en.md b/doc/v2/howto/capi/compile_paddle_lib_en.md
index 6212a3081116d988630706e83d2349dd200b73ab..3fa8a18a9fbea21b494c416e6b938990fbb68337 100644
--- a/doc/v2/howto/capi/compile_paddle_lib_en.md
+++ b/doc/v2/howto/capi/compile_paddle_lib_en.md
@@ -17,7 +17,7 @@
cpu_avx_openblas |
-- |
+paddle.tgz |
cpu_noavx_openblas |
@@ -34,7 +34,12 @@
cuda8.0_cudnn7_avx_mkl |
paddle.tgz |
-
+
+
+cuda9.0_cudnn7_avx_mkl |
+paddle.tgz |
+
+
### From source
diff --git a/paddle/fluid/framework/details/data_balance_op_handle.cc b/paddle/fluid/framework/details/data_balance_op_handle.cc
index b914851fe0add74f6d85589f4686224b668b8064..d07235df5856591f8ad707c86fa5b3b65868c3d1 100644
--- a/paddle/fluid/framework/details/data_balance_op_handle.cc
+++ b/paddle/fluid/framework/details/data_balance_op_handle.cc
@@ -62,7 +62,7 @@ std::vector> DataBalanceOpHandle::GetBalancePlan(
}
if (total_size < device_num) {
// No enough data.
- PADDLE_THROW("There is no next data.");
+ PADDLE_THROW_EOF();
}
std::sort(size_device_vec.begin(), size_device_vec.end(),
[](const std::array &a, const std::array &b) {
diff --git a/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc b/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc
index b1706eb12d080364d04108c7ef4da31e1e7c1deb..99b10254a7961bf7b27b256acaece573a71c4115 100644
--- a/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc
+++ b/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc
@@ -98,9 +98,18 @@ FeedFetchList ThreadedSSAGraphExecutor::Run(
if (timeout) {
std::lock_guard l(exception_mu_);
if (exception_) {
- auto exp = *exception_;
- exception_.reset();
- throw exp;
+ std::exception *exp = exception_.get();
+ if (dynamic_cast(exp)) {
+ auto e = *static_cast(exp);
+ exception_.reset();
+ throw e;
+ } else if (dynamic_cast(exp)) {
+ auto e = *static_cast(exp);
+ exception_.reset();
+ throw e;
+ } else {
+ LOG(FATAL) << "Unknown exception.";
+ }
} else {
continue;
}
@@ -199,6 +208,12 @@ void ThreadedSSAGraphExecutor::RunOp(
running_ops_--;
ready_var_q->Extend(op->Outputs());
VLOG(10) << op << " " << op->Name() << "Signal posted";
+ } catch (platform::EOFException ex) {
+ std::lock_guard l(exception_mu_);
+ // EOFException will not cover up existing EnforceNotMet.
+ if (exception_.get() == nullptr) {
+ exception_.reset(new platform::EOFException(ex));
+ }
} catch (platform::EnforceNotMet ex) {
std::lock_guard l(exception_mu_);
exception_.reset(new platform::EnforceNotMet(ex));
diff --git a/paddle/fluid/framework/details/threaded_ssa_graph_executor.h b/paddle/fluid/framework/details/threaded_ssa_graph_executor.h
index 90430be996758364387b552019762d9c2e9dfe45..c69e0487e2e503a0d445300aa2fd6bb9c30b06c9 100644
--- a/paddle/fluid/framework/details/threaded_ssa_graph_executor.h
+++ b/paddle/fluid/framework/details/threaded_ssa_graph_executor.h
@@ -57,7 +57,7 @@ class ThreadedSSAGraphExecutor : public SSAGraphExecutor {
std::vector places_;
platform::DeviceContextPool fetch_ctxs_;
std::mutex exception_mu_;
- std::unique_ptr exception_;
+ std::unique_ptr exception_;
std::atomic running_ops_;
void InsertPendingOp(std::unordered_map *pending_ops,
diff --git a/paddle/fluid/operators/read_op.cc b/paddle/fluid/operators/read_op.cc
index 60e4eb757668e1482090f02aea529aaad3a674d8..695d7ea83df952d9f2212cc0aaca5c90c7b47ee7 100644
--- a/paddle/fluid/operators/read_op.cc
+++ b/paddle/fluid/operators/read_op.cc
@@ -68,7 +68,7 @@ class ReadOp : public framework::OperatorBase {
reader->ReadNext(&ins);
if (ins.empty()) {
if (Attr("throw_eof_exp")) {
- PADDLE_THROW("There is no next data.");
+ PADDLE_THROW_EOF();
} else {
ins.resize(out_arg_names.size());
for (auto& tensor : ins) {
diff --git a/paddle/fluid/platform/enforce.h b/paddle/fluid/platform/enforce.h
index 70bc9c4e8340b8e02ef2826d828faff3f6d11965..566485cd3c383640047d97f40b452735e8c8c171 100644
--- a/paddle/fluid/platform/enforce.h
+++ b/paddle/fluid/platform/enforce.h
@@ -102,6 +102,15 @@ struct EnforceNotMet : public std::exception {
const char* what() const noexcept { return err_str_.c_str(); }
};
+struct EOFException : public std::exception {
+ std::string err_str_;
+ EOFException(const char* err_msg, const char* f, int l) {
+ err_str_ = string::Sprintf("%s at [%s:%d]", err_msg, f, l);
+ }
+
+ const char* what() const noexcept { return err_str_.c_str(); }
+};
+
// 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.
@@ -242,6 +251,11 @@ inline void throw_on_error(T e) {
#define PADDLE_ENFORCE(...) ::paddle::platform::throw_on_error(__VA_ARGS__);
#endif
+#define PADDLE_THROW_EOF() \
+ do { \
+ throw ::paddle::platform::EOFException("There is no next data.", __FILE__, \
+ __LINE__); \
+ } while (false)
/*
* Some enforce helpers here, usage:
* int a = 1;
diff --git a/paddle/fluid/platform/enforce_test.cc b/paddle/fluid/platform/enforce_test.cc
index 57d751cc00b5f11f1ba1a3b0c9a6b7ce9e79f586..0e8684581a93f076b1a077cc52e966d3c88cf078 100644
--- a/paddle/fluid/platform/enforce_test.cc
+++ b/paddle/fluid/platform/enforce_test.cc
@@ -210,3 +210,14 @@ TEST(ENFORCE_USER_DEFINED_CLASS, NE) {
Dims a{{1, 2, 3, 4}}, b{{5, 6, 7, 8}};
ASSERT_THROW(PADDLE_ENFORCE_EQ(a, b), paddle::platform::EnforceNotMet);
}
+
+TEST(EOF_EXCEPTION, THROW_EOF) {
+ bool caught_eof = false;
+ try {
+ PADDLE_THROW_EOF();
+ } catch (paddle::platform::EOFException error) {
+ caught_eof = true;
+ EXPECT_TRUE(HasPrefix(StringPiece(error.what()), "There is no next data."));
+ }
+ EXPECT_TRUE(caught_eof);
+}
diff --git a/paddle/fluid/pybind/exception.cc b/paddle/fluid/pybind/exception.cc
index 08a2f185e117718d07ba984f76dfe5bf8229c33c..831f30e35fd3e01ce0f0524f6f85dd59494f5353 100644
--- a/paddle/fluid/pybind/exception.cc
+++ b/paddle/fluid/pybind/exception.cc
@@ -18,10 +18,13 @@ namespace paddle {
namespace pybind {
void BindException(pybind11::module* m) {
+ static pybind11::exception eof(*m, "EOFException");
static pybind11::exception exc(*m, "EnforceNotMet");
pybind11::register_exception_translator([](std::exception_ptr p) {
try {
if (p) std::rethrow_exception(p);
+ } catch (const platform::EOFException& e) {
+ eof(e.what());
} catch (const platform::EnforceNotMet& e) {
exc(e.what());
}
diff --git a/paddle/scripts/paddle_build.sh b/paddle/scripts/paddle_build.sh
index d8f0b76b7ba0fedfe411aa86f6f8a0c77a02beca..09bbe4185e1709d379a819a94a712820ac1e9d89 100755
--- a/paddle/scripts/paddle_build.sh
+++ b/paddle/scripts/paddle_build.sh
@@ -312,6 +312,20 @@ EOF
fi
}
+function assert_api_not_changed() {
+ mkdir -p ${PADDLE_ROOT}/build/.check_api_workspace
+ cd ${PADDLE_ROOT}/build/.check_api_workspace
+ virtualenv .env
+ source .env/bin/activate
+ pip install ${PADDLE_ROOT}/build/python/dist/*whl
+ curl ${PADDLE_API_SPEC_URL:-https://raw.githubusercontent.com/reyoung/FluidAPISpec/master/API.spec} \
+ > origin.spec
+ python ${PADDLE_ROOT}/tools/print_signatures.py paddle.fluid > new.spec
+ python ${PADDLE_ROOT}/tools/diff_api.py origin.spec new.spec
+ deactivate
+}
+
+
function single_test() {
TEST_NAME=$1
if [ -z "${TEST_NAME}" ]; then
@@ -550,6 +564,7 @@ function main() {
cicheck)
cmake_gen ${PYTHON_ABI:-""}
build
+ assert_api_not_changed
run_test
gen_capi_package
gen_fluid_inference_lib
diff --git a/python/paddle/fluid/framework.py b/python/paddle/fluid/framework.py
index 9dcd907451dacaf95a7fe0d3a510241bc3da7f95..ea3117e02bd993b06de39725b2c3296031065e3c 100644
--- a/python/paddle/fluid/framework.py
+++ b/python/paddle/fluid/framework.py
@@ -19,7 +19,16 @@ import re
import numpy as np
import proto.framework_pb2 as framework_pb2
-from . import core
+try:
+ from . import core
+except ImportError, e:
+ raise ImportError(
+ """NOTE: You may need to run \"export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH\"
+ if you encounters \"libmkldnn.so not found\" errors. If you have python
+ installed in other directory, replace \"/usr/local/lib\" with your own
+ directory. The original error is: \n""" + e.message)
+except Exception, e:
+ raise e
import unique_name
__all__ = [
diff --git a/python/paddle/fluid/tests/unittests/test_data_balance.py b/python/paddle/fluid/tests/unittests/test_data_balance.py
index b558d7c2ea172d9c7526c865a4bc54c32f8998b6..cffa3329ac556dc77f3cb508b807cbd49bb974f7 100644
--- a/python/paddle/fluid/tests/unittests/test_data_balance.py
+++ b/python/paddle/fluid/tests/unittests/test_data_balance.py
@@ -118,8 +118,7 @@ class TestDataBalance(unittest.TestCase):
try:
image_val, label_val = parallel_exe.run(fetch_list,
return_numpy=True)
- except fluid.core.EnforceNotMet as ex:
- self.assertIn("There is no next data.", ex.message)
+ except fluid.core.EOFException:
break
ins_num = image_val.shape[0]
broadcasted_label = np.ones(
@@ -162,8 +161,7 @@ class TestDataBalance(unittest.TestCase):
try:
ins_tensor, label_tensor = parallel_exe.run(
fetch_list, return_numpy=False)
- except fluid.core.EnforceNotMet as ex:
- self.assertIn("There is no next data.", ex.message)
+ except fluid.core.EOFException:
break
ins_val = np.array(ins_tensor)
diff --git a/python/paddle/fluid/tests/unittests/test_multi_file_reader.py b/python/paddle/fluid/tests/unittests/test_multi_file_reader.py
index 3f940203b9393d266d75b50c9cbf62e89c36cbdf..dbd510e64ffdd6f3b78b22bb0d37d9a7ba3fd9b5 100644
--- a/python/paddle/fluid/tests/unittests/test_multi_file_reader.py
+++ b/python/paddle/fluid/tests/unittests/test_multi_file_reader.py
@@ -64,8 +64,7 @@ class TestMultipleReader(unittest.TestCase):
while True:
try:
img_val, = exe.run(fetch_list=[img])
- except fluid.core.EnforceNotMet as ex:
- self.assertIn("There is no next data.", ex.message)
+ except fluid.core.EOFException:
break
batch_count += 1
self.assertLessEqual(img_val.shape[0], self.batch_size)
diff --git a/python/paddle/fluid/tests/unittests/test_multi_pass_reader.py b/python/paddle/fluid/tests/unittests/test_multi_pass_reader.py
index 52e7cc1ffbba40a63ce3cec645c7c0a7a499c1bf..7fc9f550440d3d0e1a8182a69f5692b3df0aa258 100644
--- a/python/paddle/fluid/tests/unittests/test_multi_pass_reader.py
+++ b/python/paddle/fluid/tests/unittests/test_multi_pass_reader.py
@@ -59,8 +59,7 @@ class TestMultipleReader(unittest.TestCase):
while True:
try:
img_val, = exe.run(fetch_list=[img])
- except fluid.core.EnforceNotMet as ex:
- self.assertIn("There is no next data.", ex.message)
+ except fluid.core.EOFException:
break
batch_count += 1
self.assertLessEqual(img_val.shape[0], self.batch_size)
diff --git a/python/paddle/fluid/tests/unittests/test_recordio_reader.py b/python/paddle/fluid/tests/unittests/test_recordio_reader.py
index f32050014d7ace5aee4aca75a47bfc6a75ff91c2..69a522e273db017ac55b408276b4a28f5f907c42 100644
--- a/python/paddle/fluid/tests/unittests/test_recordio_reader.py
+++ b/python/paddle/fluid/tests/unittests/test_recordio_reader.py
@@ -68,8 +68,7 @@ class TestRecordIO(unittest.TestCase):
while True:
try:
tmp, = exe.run(fetch_list=[avg_loss])
- except fluid.core.EnforceNotMet as ex:
- self.assertIn("There is no next data.", ex.message)
+ except fluid.core.EOFException:
break
avg_loss_np.append(tmp)
diff --git a/python/setup.py.in b/python/setup.py.in
index d92abf6088462b89ec0693d77211d15437b3029a..51380149d0b09224c02050902897f23f53600de2 100644
--- a/python/setup.py.in
+++ b/python/setup.py.in
@@ -5,7 +5,7 @@ class BinaryDistribution(Distribution):
return True
MAJOR = 0
-MINOR = 11
+MINOR = 14
PATCH = 0
RC = 0
ISTAGED = False
diff --git a/tools/diff_api.py b/tools/diff_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf9f2c72cb78ddf88ff2a7bb1c0ee4b00ec0ec96
--- /dev/null
+++ b/tools/diff_api.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+from __future__ import print_function
+import difflib
+import sys
+
+with open(sys.argv[1], 'r') as f:
+ origin = f.read()
+ origin = origin.splitlines()
+
+with open(sys.argv[2], 'r') as f:
+ new = f.read()
+ new = new.splitlines()
+
+differ = difflib.Differ()
+result = differ.compare(origin, new)
+
+error = False
+print('API Difference is: ')
+for each_diff in result:
+ if each_diff[0] in ['-', '?']: # delete or change API is not allowed
+ error = True
+ elif each_diff[0] == '+':
+ # only new layers is allowed.
+ if not each_diff.startswith('+ paddle.fluid.layers.'):
+ error = True
+
+ if each_diff[0] != ' ':
+ print(each_diff)
+
+if error:
+ sys.exit(1)