Caffe2 Code Review - PaddlePaddle/Paddle GitHub Wiki
*** This is a draft! ***
Page 9 shows SimpleNet::Run and SimpleNet::RunAsync.:q
Both calls ops in the topologically sorted order; whereas SimpleNet::Run calls OperatorBase::Run(stream_id=0), and SimpleNet::RunAsync calls OperatorBased::RunAsync(stream_id=0).
OperatorBase::Run/RunAsync are both virtual methods and are overloaded by Operator, which derives from OperatorBase.  Also, Operator::Run/RunAsync calls Operator::RunOnDevice, which is what users are supposed to overload when they define their own operators.  The difference  is that Operator::Run calls
- Context::SwitchToDeivce
- Operator::Run
- Context::FinishDevice
whereas Operator::RunAsync calls only the first two:
- Context::SwitchToDeivce
- Operator::Run
So SimpleNet::Run actually calls
workspace.CreateNet calls C.create_net:
def CreateNet(net, overwrite=False, input_blobs=None):
    if input_blobs is None:
        input_blobs = []
    for input_blob in input_blobs:
        C.create_blob(input_blob)
    return CallWithExceptionIntercept(
        C.create_net, C.last_failed_op_uuid, StringifyProto(net), overwrite)C.create_net calls gWorkspace->CreateNet:
  m.def(
      "create_net",
      [](py::bytes net_def, bool overwrite) {
        caffe2::NetDef proto;
        CAFFE_ENFORCE(
            ParseProtobufFromLargeString(net_def, &proto),
            "Can't parse net proto: ",
            std::string(net_def));
        CAFFE_ENFORCE(
            gWorkspace->CreateNet(proto, overwrite),
            "Error creating net with proto: ",
            std::string(net_def));
        return true;
      },
      py::arg("net_def"),
      py::arg("overwrite") = kPyBindFalse);where gWorkspace is of type WorkSpace.
Workspace::CreateNet calls caffe2::CreateNet:
  net_map_[net_def.name()] =
      unique_ptr<NetBase>(caffe2::CreateNet(net_def, this));caffe2::CreateNet calls SimpleNet's constructor via make_unique:
unique_ptr<NetBase> CreateNet(const NetDef& net_def, Workspace* ws) {
  // In default, we will return a simple network that just runs all operators
  // sequentially.
  if (!net_def.has_type()) {
    return make_unique<SimpleNet>(net_def, ws);
  }
  return NetRegistry()->Create(net_def.type(), net_def, ws);
}SimpleNet::SimpleNet call SimpleNet::CreateOperator:
SimpleNet::SimpleNet(const NetDef& net_def, Workspace* ws)
    : NetBase(net_def, ws) {
  VLOG(1) << "Constructing SimpleNet " << net_def.name();
  bool net_def_has_device_option = net_def.has_device_option();
  // Initialize the operators
  for (const OperatorDef& operator_def : net_def.op()) {
    VLOG(1) << "Creating operator " << operator_def.name()
            << ":" << operator_def.type();
    if (!operator_def.has_device_option() && net_def_has_device_option) {
      // In the case that the operator def does not specify a device option but
      // the net def has a default option, we copy the device option over to the
      // operator def.
      OperatorDef temp_def(operator_def);
      temp_def.mutable_device_option()->CopyFrom(net_def.device_option());
      operators_.emplace_back(CreateOperator(temp_def, ws));
    } else {
      operators_.emplace_back(CreateOperator(operator_def, ws));
    }
  }
}where CreateOperator is a global function
unique_ptr<OperatorBase> CreateOperator(
    const OperatorDef& operator_def, Workspace* ws);whose implementation class OpertorBase's constructor, which creates blobs according to OperatorDef:
OperatorBase::OperatorBase(const OperatorDef& operator_def, Workspace* ws)
    : operator_ws_(ws),
      operator_def_(operator_def),
      arg_helper_(operator_def_) {
  ...
  for (const string& output_str : operator_def_.output()) {
    outputs_.push_back(CHECK_NOTNULL(ws->CreateBlob(output_str)));
  }
}Please note that all input/output blobs are created by calling Workspace::CreateBlob, so the workspace would know all blobs.
Please be aware that the blob creation doesn't allocate tensor memory.  It is Operator::Input/Output who interpret blob's