Skip to content
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

Async GRPC sendrecv #7133

Merged
merged 39 commits into from
Jan 11, 2018
Merged

Async GRPC sendrecv #7133

merged 39 commits into from
Jan 11, 2018

Conversation

gongweibao
Copy link
Contributor

Fix #7041

using grpc::ClientWriter;
using grpc::Status;
using sendrecv::SendRecvService;
using sendrecv::VariableMessage;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use C++ often, so I am likely to be wrong. I personally feel that:

void Run(const framework::Scope* scope, const std::string name,
               sendrecv::VariableMessage* msg) {

is easier to understand than:

void Run(const framework::Scope* scope, const std::string name,
               VariableMessage* msg) {

Since sendrecv::VariableMessage tells us that VariableMessage is from a different module, and that module does things like send and recv, so I can infer that VariableMessage is the message used for send and recv.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

framework::DeserializeFromStream(iss, &ret_tensor);
auto* outvar = scope->FindVar(name);
framework::LoDTensor* out_tensor =
outvar->GetMutable<framework::LoDTensor>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that the variable type for send/recv is not framework::LoDTensor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.Add FixME comments.
Done.


// Block until the next result is available
// in the completion queue "cq".
cq.Next(&which, &ok);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to check the value of ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

namespace operators {
namespace detail {

struct Var {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have Variable, to avoid confusion, maybe change name to something like VarHandle.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

new RequestSend(service_, cq_);

// The actual processing.
// std::string prefix("Hello ");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No commented out code please :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.Done.

service_->RequestSendVariable(&ctx_, &request_, &responder_, cq_, cq_,
this);
} else if (status_ == PROCESS) {
new RequestSend(service_, cq_);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could not understand what does this code block do, why does it not use request_?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A detail comments is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the status is not useful also. I'll test it later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我的理解:

  1. CREATE的时候注册消息处理的类。
  2. PROCESS的时候是完成队列通知request已经准备好,可以处理了。
  3. FINISH的时候是完成队列通知reply已经发送完了。

所以这个PROCEED从完成队列中重入两次。

namespace operators {
namespace detail {

enum CallStatus { CREATE, PROCESS, FINISH };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to understand what CREATE, PROCESS, FINISH does, but where are they used by the client?

Copy link
Contributor Author

@gongweibao gongweibao Jan 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A detail comments is here.

#include "grpc_client.h"
#include <future>

using grpc::Server;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unnecessary using lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
};

class AsyncGRPCClient {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just call this class RPCClient the same as before since we only use just one client and remove the previous implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// is sent completely and don't wait all.
protected:
template <typename send_t, typename recv_t, typename Msg_t>
bool Call(const framework::Scope* scope, const std::vector<Var>& in,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call has no meaning, change to some function names that mean something, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

AsyncGRPCClient() {}

void AddEndPoint(std::string ep);
void AddEndPoint(const std::vector<std::string>& ep);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete AddEndPoint, and put the initialization into two overloaded ctors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will refactor client interface.

const framework::Scope* scope, std::string name) {}

template <typename send_t, typename recv_t>
void Call(grpc::CompletionQueue* cq,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SendMsg have Run and Call which is confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

responder_.Finish(reply_, Status::OK, this);
} else {
GPR_ASSERT(status_ == FINISH);
delete this;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this should be used very carefully or never use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will test later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this cause core down.

const time_point deadline = s.start + std::chrono::milliseconds(5000);

// context
ClientContext* context = new ClientContext();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use unique_ptr to avoid memory leak.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already in.

};

template <typename send_t, typename recv_t, typename Msg_t>
bool AsyncGRPCClient::Call(const framework::Scope* scope,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Templates should be placed at .h

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

}
};

template <typename send_t, typename recv_t, typename Msg_t>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typenames should be capitalized.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

typedef std::chrono::system_clock::time_point time_point;

for (int64_t i = 0; i < (int64_t)in.size(); i++) {
PADDLE_ENFORCE(channels_.find(in[i].endpoint) != channels_.end());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not manage channels in a single client, let the caller manage this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or you can write a multi-client class to do multi send.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@gongweibao
Copy link
Contributor Author

Reconstruction grpc_client.

@@ -1 +1 @@
grpc_library(sendrecvop_grpc SRCS recv_impl.cc send_impl.cc PROTO send_recv.proto DEPS lod_tensor selected_rows)
grpc_library(sendrecvop_grpc SRCS recv_impl.cc send_impl.cc grpc_client.cc grpc_server.cc PROTO send_recv.proto DEPS lod_tensor selected_rows)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove recv_impl.cc send_impl.cc if they are nolonger used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

// one tensor
bool Send(const std::vector<std::string>& ep, const framework::Scope* scope,
const std::vector<std::string>& ins, int64_t time_out) {
detail::RPCClients c;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating new client object in each send is inefficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

SendStatus send_status_;
};

class RPCClients {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still believe that send_op should be responsible to determine which endpoint should each variable send to. Client is only responsible for how to do communication, send_op is responsible for how to manage the send, if we are going to implement something like "ring-based all reduce", will only need to write a new send_op and do not need to change this client implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

SendStatus GetSendStatus() { return send_status_; }

private:
void _Request(const framework::Scope* scope, const std::string name,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

ch_ = ch;
ep_ = ep;
stub_ = sendrecv::SendRecvService::NewStub(ch);
context_.reset(new grpc::ClientContext());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context should be created before every rpc send call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.Thanks.

}
};

class ClientBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would an RPCClient implementing SendVariable and GetVariable be sufficient?

members are the same and send, get should be called on the same RPC client stub

+  std::shared_ptr<grpc::CompletionQueue> cq_;
 +  std::shared_ptr<grpc::Channel> ch_;
 +  std::string ep_;
 +  std::unique_ptr<sendrecv::SendRecvService::Stub> stub_;
 +  std::unique_ptr<grpc::ClientContext> context_;
 +  std::unique_ptr<grpc::Status> status_;
 +  std::unique_ptr<sendrecv::VoidMessage> reply_;
 +  std::unique_ptr<grpc::ClientAsyncResponseReader<sendrecv::VoidMessage>> rpc_;
 +  SendStatus send_status_;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.thanks.

@Yancey1989
Copy link
Contributor

#7161 add some features about send/recv op, so please fix the conflict first.

@gongweibao gongweibao changed the title [WIP]Async GRPC sendrecv Async GRPC sendrecv Jan 8, 2018
bool wait();

private:
bool Proceed();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By Proceed do you mean Process, proceed means go on with something. The sample code use proceed maybe because it's a stream request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

private:
grpc::CompletionQueue cq_;
std::map<std::string, std::shared_ptr<grpc::Channel>> channels_;
int64_t count_ = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

count_ is a name with less information, use xxx_count_ instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

public:
bool AsyncSendVariable(const std::string& ep,
const platform::DeviceContext& ctx,
const framework::Scope* scope,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be const framework::Scope&

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

auto ch = GetChannel(ep);
SendProcessor* s = new SendProcessor(ch);
s->Prepare(var_h, time_out);
s->response_call_back = ProcSendResponse;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since ProcSendResponse is doing nothing, pass NULL here should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

typedef std::function<void(const VarHandle&, const sendrecv::VoidMessage&)>
RequestSendCallBack;

struct SendProcessor : public ClientBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my point of view, thought below definition would be simpler to implement:

typedef void (*rpc_response_callback)(const framework::Scope&, void* message);

class RPCClient {
....

private:
  struct RPCResponse {
    rpc_response_callback callback_;
    const framework::Scope& scope_;
    std::string varname_;
    int ret_msg_type_;
    grpc::Status status_;
  };
};

Then AsyncSendVariable and AsyncGetVariable can use ret_msg_type_ to get whether to cast message to VoidMessage or VariableMessage. VarHandle can also be ommited.

Copy link
Contributor Author

@gongweibao gongweibao Jan 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then AsyncSendVariable and AsyncGetVariable can use ret_msg_type_ to get whether to cast message to VoidMessage or VariableMessage.

这个我试过了。需要暴露类型的变量有两个,这是不能用一个struct解决的。

sendrecv::XXXMessageType reply;
RequestXXXCallBack response_call_back

根据ret_msg_type_是不够的,不方便以后的扩展,而是应该根据action_type来判断哪种操作类型。有两个问题

  1. 代码写起来很丑陋,需要各处switch。
    2.扩展起来不方便。

异步的情况下:VarHandle里边的信息还是有用的:

struct VarHandle {
    std::string ep;
    const platform::DeviceContext* ctx;
    const framework::Scope& scope;
    std::string name;
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要暴露类型的变量有两个,这是不能用一个struct解决的。

嗯。感觉这个也不是主要原因,从扩展来讲,用继承会比较好。

异步的情况下:VarHandle里边的信息还是有用的:

我理解应该是为了减少callback中的参数个数。这样的话,可以直接把callback定义成void(void* ret_msg, void* user_data),在不同的继承的Processor中再cast到实际的类型,扩展性会更好。

enum CallStatus { PROCESS = 0, FINISH };

// reference:
// https://stackoverflow.com/questions/41732884/grpc-multiple-services-in-cpp-async-server
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact we only have one service: service SendRecvService

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For more than two types of calls, you could achieve the same behavior with an enum instead of a bool.
A more flexible approach would be to have a different CallData-like class for each RPC. However when you get a tag from cq_->Next()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation, now I figure it out!

* https://stackoverflow.com/questions/35708348/grpc-what-is-the-recommended-way-to-shut-down-an-asynchronous-server-in-c
*/
void AsyncGRPCServer::ShutDown() {
ShutdownGetQueue();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

namespace operators {
namespace detail {

void SerializeToMessage(const std::string& name, const framework::Variable* var,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please put these two function into grpc_client.h, file name util.h have less information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样的话grpc_server.cc需要依赖grpc_client.h了。。。。


std::mutex cq_get_mutex_;
mutable bool is_get_shut_down_ = false;
std::unique_ptr<grpc::ServerCompletionQueue> cq_get_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can server-side use one single ServerCompletionQueue? And two threads to deal with different message make this implement complicated. Since we have var_recv_queue_ so the backend can use multiple threads to deal with incoming requests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in another way.Done.

@@ -1 +1 @@
grpc_library(sendrecvop_grpc SRCS recv_impl.cc send_impl.cc PROTO send_recv.proto DEPS lod_tensor selected_rows)
grpc_library(sendrecvop_grpc SRCS utils.cc grpc_client.cc grpc_server.cc PROTO send_recv.proto DEPS lod_tensor selected_rows)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utils.cc => sendrecvop_utils, I think it's not a common utils.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


// stub context
auto ch = GetChannel(ep);
SendProcessor* s = new SendProcessor(ch);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think std::unique_ptr<SendProcessor> s(new SendProcessor(ch)); is a better way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The memory should not be released and should transformed to Completion queue.

rpc->Finish(&s->reply, &s->status, (void*)s);

PADDLE_ENFORCE(tag);

// TODO(gongwb): add more retries.
ClientBase* c = (ClientBase*)tag;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClientBase* c = (ClientBase*)tag
=>
ClientBase* c = static_cast<ClientBase *>(tag)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


virtual void Proceed() = 0;

std::unique_ptr<sendrecv::SendRecvService::Stub> stub;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following https://google.github.io/styleguide/cppguide.html#Variable_Names, please add the underscore at end of the variable name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see Struct Data Members section.


bool AsyncGetVariable(const std::string& ep,
const platform::DeviceContext& ctx,
const framework::Scope* scope,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The save as above
const framework::Scope* scope
=>
const framework::Scope& scope

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

explicit RequestBase(sendrecv::SendRecvService::AsyncService* service,
grpc::ServerCompletionQueue* cq)
: service_(service), cq_(cq) {
status_ = PROCESS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move status_ = PROCESS to the constructor initializer list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// proc request.
std::string var_name = request_.varname();
auto* var = scope_->FindVar(var_name);
// FIXME(gongwb): device context?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can not understand what's the meaning of FIXME comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@typhoonzero typhoonzero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some tiny comments, can be merged soon!

void ProcGetResponse(const VarHandle& var_h,
const sendrecv::VariableMessage& msg);

struct ClientBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

typedef std::function<void(const VarHandle&, const sendrecv::VoidMessage&)>
RequestSendCallBack;

struct SendProcessor : public ClientBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要暴露类型的变量有两个,这是不能用一个struct解决的。

嗯。感觉这个也不是主要原因,从扩展来讲,用继承会比较好。

异步的情况下:VarHandle里边的信息还是有用的:

我理解应该是为了减少callback中的参数个数。这样的话,可以直接把callback定义成void(void* ret_msg, void* user_data),在不同的继承的Processor中再cast到实际的类型,扩展性会更好。

enum CallStatus { PROCESS = 0, FINISH };

// reference:
// https://stackoverflow.com/questions/41732884/grpc-multiple-services-in-cpp-async-server
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation, now I figure it out!

virtual ~RequestSend() {}

virtual void Process() {
// proc request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the comment line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (is_shut_down_) {
return;
}
// base->RegisterNewOne();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/*
* This URL explains why shutdown is complicate:
* https://stackoverflow.com/questions/35708348/grpc-what-is-the-recommended-way-to-shut-down-an-asynchronous-server-in-c
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


private:
std::mutex cq_mutex_;
mutable bool is_shut_down_ = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mutable is for const functions, and there is no const functions?

break;
}
case FINISH: {
VLOG(4) << cq_name << " status:" << base->Status();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the same VLOG level in RPC implements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -136,11 +136,21 @@ void StartServerNet(bool is_sparse) {
attrs.insert({"OptimizeProgram", program_proto});
recv_op = f::OpRegistry::CreateOp("recv", {{"RX", {"x1"}}}, {}, attrs);
recv_op->Run(scope, place);

std::cout << "servernet end" << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unit test printing code.

@@ -138,9 +138,17 @@ void StartServerNet(bool is_sparse) {
recv_op->Run(scope, place);
}

void PrintTop(std::string name, float *data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove printing in the unit test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些print在出现错误的时候用来查找错误还是非常有用的。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctest可以在错误的时候输出对比的数据。不需要print。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只能看到一个,其实很不利于找到错误。
Done。

Copy link
Contributor

@typhoonzero typhoonzero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM++

@gongweibao gongweibao merged commit da3087a into PaddlePaddle:develop Jan 11, 2018
@gongweibao gongweibao deleted the asyncsendrecv branch January 11, 2018 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants