in src/nccl_op.cc [454:528]
void ComputeAsync(OpKernelContext* ctx, DoneCallback done) override
{
if (op_event == NULL)
cuEventCreate(&op_event, CU_EVENT_DISABLE_TIMING ); // | CU_EVENT_BLOCKING_SYNC
const Tensor& input = ctx->input(0);
char debug_message[1000];
bool verbose = !debug_str.empty();
if (verbose)
{
sprintf(debug_message, " op_num: %03d size: %s debug_str: %s\n", op_num, input.shape().DebugString().c_str(), debug_str.c_str());
std::cout << "START";
std::cout << debug_message;
fflush(stdout);
}
// TODO: Turn on for all ranks
if (!logfile.empty())
if (FILE* log = fopen(logfile.c_str(), "a"))
{
fprintf(log, "%03d %10d %12s %d %d %d\n",
op_num,
(int)input.NumElements(),
input.shape().DebugString().c_str(),
(int)ctx->step_id(),
(int)ctx->frame_iter().frame_id,
(int)ctx->frame_iter().iter_id
);
fclose(log);
}
// Nccl ops work in place, so save some memory here.
// ctx->set_output(0, input);
Tensor* output;
OP_REQUIRES_OK(ctx, ctx->allocate_output(0, input.shape(), &output));
auto actual_done = [ctx, done, debug_message, verbose](Status s) {
if (verbose)
{
std::cout << "END ";
std::cout << debug_message;
fflush(stdout);
}
OP_REQUIRES_OK_ASYNC(ctx, s, done);
done();
};
auto stream = ctx->op_device_context()->stream();
auto executor = stream->parent();
//auto gpu_info = ctx->device()->tensorflow_gpu_device_info();
//auto event_mgr = gpu_info->event_mgr;
//int gpu_id = gpu_info->gpu_id;
CUstream cu_stream = reinterpret_cast<CUstream>(stream->implementation()->GpuStreamHack());
// Record an event to mark this ops insertion in the compute stream.
// The reduce op will be executed on the nccl stream but
// not before this event is reached on the compute stream.
cuEventRecord(op_event, cu_stream);
// this keeps the backward pass from gobbling up buffers for every reduce op.
// By syncing we let big ones finish first.
// It's ok to greedily execute small buffers.
if (sync_size && input.NumElements() > sync_size)
cuStreamSynchronize(cu_stream);
auto manager = NcclManager::instance(num_comms, prereduce, executor);
if (!mpi_ranks.empty())
{
manager->CreateCustomComm(op_num, mpi_ranks, comm_id, executor);
}
manager->AddEntry(op_num, comm_idx, &input, output, std::move(actual_done), op_event);
}