-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Repair nccl op test #8575
Repair nccl op test #8575
Changes from 8 commits
a4b71e9
614914e
0e43e2c
eb6ff79
70b71c8
93f10fc
0a0c7ed
fad09a9
eeaf562
e32f306
000c756
9a42d3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -14,19 +14,15 @@ limitations under the License. */ | |||||||||||||||
|
||||||||||||||||
#include <glog/logging.h> | ||||||||||||||||
#include <gtest/gtest.h> | ||||||||||||||||
#include <algorithm> | ||||||||||||||||
#include <memory> | ||||||||||||||||
#include <mutex> | ||||||||||||||||
#include <thread> | ||||||||||||||||
#include <utility> | ||||||||||||||||
#include <vector> | ||||||||||||||||
|
||||||||||||||||
#include "paddle/fluid/framework/block_desc.h" | ||||||||||||||||
#include "paddle/fluid/framework/init.h" | ||||||||||||||||
#include "paddle/fluid/framework/op_desc.h" | ||||||||||||||||
#include "paddle/fluid/framework/op_registry.h" | ||||||||||||||||
#include "paddle/fluid/framework/program_desc.h" | ||||||||||||||||
#include "paddle/fluid/framework/var_desc.h" | ||||||||||||||||
#include "paddle/fluid/operators/nccl/nccl_gpu_common.h" | ||||||||||||||||
#include "paddle/fluid/platform/device_context.h" | ||||||||||||||||
#include "paddle/fluid/platform/enforce.h" | ||||||||||||||||
|
@@ -41,15 +37,24 @@ USE_CUDA_ONLY_OP(ncclBcast); | |||||||||||||||
namespace f = paddle::framework; | ||||||||||||||||
namespace p = paddle::platform; | ||||||||||||||||
|
||||||||||||||||
static std::vector<int> gpu_list; | ||||||||||||||||
|
||||||||||||||||
// test data amount | ||||||||||||||||
const f::DDim kDims = {100, 100}; | ||||||||||||||||
const f::DDim kDims = {20, 20}; | ||||||||||||||||
|
||||||||||||||||
// nccl op common tester, init communicator. | ||||||||||||||||
class NCCLTester : public ::testing::Test { | ||||||||||||||||
public: | ||||||||||||||||
virtual void SetUp() override { | ||||||||||||||||
int count = p::GetCUDADeviceCount(); | ||||||||||||||||
if (count <= 1) { | ||||||||||||||||
LOG(WARNING) | ||||||||||||||||
<< "Cannot test multi-gpu nccl, because the CUDA device count is " | ||||||||||||||||
<< count; | ||||||||||||||||
exit(0); | ||||||||||||||||
} | ||||||||||||||||
for (int i = 0; i < count; ++i) { | ||||||||||||||||
gpu_list.emplace_back(i); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
paddle::platform::CPUPlace cpu_place; | ||||||||||||||||
for (size_t i = 0; i < gpu_list.size(); ++i) { | ||||||||||||||||
p::CUDAPlace place(i); | ||||||||||||||||
|
@@ -70,18 +75,24 @@ class NCCLTester : public ::testing::Test { | |||||||||||||||
std::unique_ptr<f::OpDesc> op1(new f::OpDesc); | ||||||||||||||||
|
||||||||||||||||
op1->SetType("ncclInit"); | ||||||||||||||||
op1->SetInput("parallel_scopes", {"p_scopes"}); | ||||||||||||||||
op1->SetOutput("Communicator", {"comm"}); | ||||||||||||||||
op1->SetAttr("gpus", {gpu_list}); | ||||||||||||||||
|
||||||||||||||||
auto *var = g_scope.Var("comm"); | ||||||||||||||||
var->GetMutable<p::Communicator>(); | ||||||||||||||||
|
||||||||||||||||
auto *scope_var = g_scope.Var("p_scopes"); | ||||||||||||||||
auto *p_scopes = scope_var->GetMutable<std::vector<f::Scope *>>(); | ||||||||||||||||
(*p_scopes).resize(gpu_list.size()); | ||||||||||||||||
|
||||||||||||||||
auto op = f::OpRegistry::CreateOp(*op1); | ||||||||||||||||
VLOG(1) << "invoke NCCLInitOp."; | ||||||||||||||||
op->Run(g_scope, cpu_place); | ||||||||||||||||
VLOG(1) << "NCCLInitOp finished."; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
int GetGPUData(int gpu_id) { return gpu_id + 42; } | ||||||||||||||||
|
||||||||||||||||
template <class T> | ||||||||||||||||
void PerThreadProgram(int gpu_id, const f::OpDesc &op_desc, f::Scope *scope) { | ||||||||||||||||
std::unique_lock<std::mutex> lk(mu); | ||||||||||||||||
|
@@ -97,7 +108,7 @@ class NCCLTester : public ::testing::Test { | |||||||||||||||
send_tensor->Resize(kDims); | ||||||||||||||||
send_tensor->mutable_data<T>(kDims, place); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe line 108 is unnecessary. |
||||||||||||||||
|
||||||||||||||||
std::vector<T> send_vector(f::product(kDims), gpu_id); | ||||||||||||||||
std::vector<T> send_vector(f::product(kDims), GetGPUData(gpu_id)); | ||||||||||||||||
paddle::framework::TensorFromVector<T>(send_vector, *ctx, send_tensor); | ||||||||||||||||
ctx->Wait(); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary to synchronize here? I think the copying will synchronize the GPU and CPU in line 179. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The copying is Paddle/paddle/fluid/memory/memcpy.cc Lines 30 to 36 in 0d49b92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so because the memory is pageable in CPU side, the copying doesn't return immediately until the copy has completed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||||||||||||
VLOG(1) << "Send Tensor filled with elements " << send_tensor->numel(); | ||||||||||||||||
|
@@ -121,27 +132,11 @@ class NCCLTester : public ::testing::Test { | |||||||||||||||
std::vector<p::DeviceContext *> dev_ctxs; | ||||||||||||||||
f::Scope g_scope; | ||||||||||||||||
std::mutex mu; | ||||||||||||||||
std::vector<int> gpu_list; | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Data members of classes should be with a trailing underscore. |
||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
// ncclInitOp with desc | ||||||||||||||||
TEST(NCCL, ncclInitOp) { | ||||||||||||||||
std::unique_ptr<f::OpDesc> op_desc(new f::OpDesc); | ||||||||||||||||
|
||||||||||||||||
op_desc->SetType("ncclInit"); | ||||||||||||||||
op_desc->SetOutput("Communicator", {"x1"}); | ||||||||||||||||
op_desc->SetAttr("gpus", {gpu_list}); | ||||||||||||||||
|
||||||||||||||||
f::Scope g_scope; | ||||||||||||||||
paddle::platform::CPUPlace cpu_place; | ||||||||||||||||
|
||||||||||||||||
auto *var = g_scope.Var("x1"); | ||||||||||||||||
var->GetMutable<p::Communicator>(); | ||||||||||||||||
|
||||||||||||||||
auto op = f::OpRegistry::CreateOp(*op_desc); | ||||||||||||||||
VLOG(1) << "invoke NCCLInitOp."; | ||||||||||||||||
op->Run(g_scope, cpu_place); | ||||||||||||||||
VLOG(1) << "NCCLInitOp finished."; | ||||||||||||||||
} | ||||||||||||||||
TEST_F(NCCLTester, ncclInitOp) {} | ||||||||||||||||
|
||||||||||||||||
// ncclAllReduceOp with desc | ||||||||||||||||
TEST_F(NCCLTester, ncclAllReduceOp) { | ||||||||||||||||
|
@@ -166,8 +161,10 @@ TEST_F(NCCLTester, ncclAllReduceOp) { | |||||||||||||||
ths[i].join(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// check results | ||||||||||||||||
float result = std::accumulate(gpu_list.begin(), gpu_list.end(), 0); | ||||||||||||||||
float expected_result = 0.0; | ||||||||||||||||
for (int gpu_id : gpu_list) { | ||||||||||||||||
expected_result = expected_result + GetGPUData(gpu_id); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
for (size_t i = 0; i < dev_scopes.size(); ++i) { | ||||||||||||||||
p::CPUPlace cpu_place; | ||||||||||||||||
|
@@ -185,7 +182,7 @@ TEST_F(NCCLTester, ncclAllReduceOp) { | |||||||||||||||
static_cast<p::CUDADeviceContext *>(dev_ctxs[i])->stream()); | ||||||||||||||||
|
||||||||||||||||
for (int64_t j = 0; j < f::product(kDims); ++j) { | ||||||||||||||||
ASSERT_NEAR(ct[j], result, 1e-5); | ||||||||||||||||
ASSERT_NEAR(ct[j], expected_result, 1e-5); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
@@ -215,8 +212,10 @@ TEST_F(NCCLTester, ncclReduceOp) { | |||||||||||||||
ths[i].join(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// check results on | ||||||||||||||||
float result = std::accumulate(gpu_list.begin(), gpu_list.end(), 0); | ||||||||||||||||
float expected_result = 0.0; | ||||||||||||||||
for (int gpu_id : gpu_list) { | ||||||||||||||||
expected_result = expected_result + GetGPUData(gpu_id); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
p::CPUPlace cpu_place; | ||||||||||||||||
p::CUDAPlace gpu_place(gpu_list[kRoot]); | ||||||||||||||||
|
@@ -234,7 +233,7 @@ TEST_F(NCCLTester, ncclReduceOp) { | |||||||||||||||
static_cast<p::CUDADeviceContext *>(dev_ctxs[kRoot])->stream()); | ||||||||||||||||
|
||||||||||||||||
for (int64_t j = 0; j < f::product(kDims); ++j) { | ||||||||||||||||
ASSERT_NEAR(ct[j], result, 1e-5); | ||||||||||||||||
ASSERT_NEAR(ct[j], expected_result, 1e-5); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
|
@@ -264,8 +263,7 @@ TEST_F(NCCLTester, ncclBcastOp) { | |||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
const int idx = 1; | ||||||||||||||||
// check results on | ||||||||||||||||
float result = kRoot; | ||||||||||||||||
float result = GetGPUData(kRoot); | ||||||||||||||||
|
||||||||||||||||
p::CPUPlace cpu_place; | ||||||||||||||||
p::CUDAPlace gpu_place(gpu_list[idx]); | ||||||||||||||||
|
@@ -285,34 +283,3 @@ TEST_F(NCCLTester, ncclBcastOp) { | |||||||||||||||
ASSERT_NEAR(ct[j], result, 1e-5); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
int main(int argc, char **argv) { | ||||||||||||||||
// FIXME(tonyyang-svail): | ||||||||||||||||
// Due to the driver issue on our CI, disable for now | ||||||||||||||||
return 0; | ||||||||||||||||
const int dev_count = p::GetCUDADeviceCount(); | ||||||||||||||||
if (dev_count <= 1) { | ||||||||||||||||
LOG(WARNING) | ||||||||||||||||
<< "Cannot test multi-gpu nccl, because the CUDA device count is " | ||||||||||||||||
<< dev_count; | ||||||||||||||||
return 0; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
std::vector<paddle::platform::Place> places; | ||||||||||||||||
|
||||||||||||||||
places.emplace_back(paddle::platform::CPUPlace()); | ||||||||||||||||
int count = paddle::platform::GetCUDADeviceCount(); | ||||||||||||||||
for (int i = 0; i < count; ++i) { | ||||||||||||||||
places.emplace_back(paddle::platform::CUDAPlace(i)); | ||||||||||||||||
gpu_list.emplace_back(i); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
VLOG(0) << " DeviceCount " << count; | ||||||||||||||||
paddle::platform::DeviceContextPool::Init(places); | ||||||||||||||||
|
||||||||||||||||
testing::InitGoogleTest(&argc, argv); | ||||||||||||||||
|
||||||||||||||||
// device context should be release before scope. | ||||||||||||||||
// otherwise driver will down. | ||||||||||||||||
return RUN_ALL_TESTS(); | ||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is necessary, because
Simply set GPU data = gpu_id won't expose the incorrect linking error. More specifically, Paddle might be compiled with NCCL1.3 header while dynamically linked with NCCL2.so.