[Operator Versioning][Edge] Change OP to CALL when there is a valid upgrader (#67731)

Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/67731

1. Register upgrader function at loading stage
2. Change OP to CALL when there operator_version from model is smaller than current runtime version and there exists a valid upgrader

The interpreter log is :
```
RUNNING 0 STOREN 1 3
RUNNING 1 DROPR 1
RUNNING 2 LOAD 2
RUNNING 3 LOAD 3
RUNNING 4 CALL 0
RUNNING 0 STOREN 1 2
RUNNING 1 LOAD 1
RUNNING 2 OP 0, aten::is_floating_point
RUNNING 3 JF 3
RUNNING 4 LOADC 1
RUNNING 5 JMP 3
RUNNING 8 STORE 3
RUNNING 9 MOVE 3
RUNNING 10 JF 5
RUNNING 11 LOAD 1
RUNNING 12 LOAD 2
RUNNING 13 OP 1, aten::div.Tensor
RUNNING 14 JMP 5
RUNNING 19 STORE 4
RUNNING 20 DROPR 2
RUNNING 21 DROPR 1
RUNNING 22 MOVE 4
RUNNING 23 RET
RUNNING 5 LOAD 2
RUNNING 6 LOAD 3
RUNNING 7 CALL 0
RUNNING 0 STOREN 1 2
RUNNING 1 LOAD 1
RUNNING 2 OP 0, aten::is_floating_point
RUNNING 3 JF 3
RUNNING 4 LOADC 1
RUNNING 5 JMP 3
RUNNING 8 STORE 3
RUNNING 9 MOVE 3
RUNNING 10 JF 5
RUNNING 11 LOAD 1
RUNNING 12 LOAD 2
RUNNING 13 OP 1, aten::div.Tensor
RUNNING 14 JMP 5
RUNNING 19 STORE 4
RUNNING 20 DROPR 2
RUNNING 21 DROPR 1
RUNNING 22 MOVE 4
RUNNING 23 RET
RUNNING 8 MOVE 2
RUNNING 9 MOVE 3
RUNNING 10 CALL 0
RUNNING 0 STOREN 1 2
RUNNING 1 LOAD 1
RUNNING 2 OP 0, aten::is_floating_point
RUNNING 3 JF 3
RUNNING 4 LOADC 1
RUNNING 5 JMP 3
RUNNING 8 STORE 3
RUNNING 9 MOVE 3
RUNNING 10 JF 5
RUNNING 11 LOAD 1
RUNNING 12 LOAD 2
RUNNING 13 OP 1, aten::div.Tensor
RUNNING 14 JMP 5
RUNNING 19 STORE 4
RUNNING 20 DROPR 2
RUNNING 21 DROPR 1
RUNNING 22 MOVE 4
RUNNING 23 RET
RUNNING 11 TUPLE_CONSTRUCT 3
RUNNING 12 RET
```

The upgrader bytecode is:
```
(STOREN, 1, 2)
(LOAD, 1, 0)
(OP, 0, 0)
(JF, 3, 0)
(LOADC, 1, 0)
(JMP, 3, 0)
(LOAD, 2, 0)
(OP, 0, 0)
(STORE, 3, 0)
(MOVE, 3, 0)
(JF, 5, 0)
(LOAD, 1, 0)
(LOAD, 2, 0)
(OP, 1, 0)
(JMP, 5, 0)
(LOAD, 1, 0)
(LOAD, 2, 0)
(LOADC, 0, 0)
(OP, 2, 0)
(STORE, 4, 0)
(DROPR, 2, 0)
(DROPR, 1, 0)
(MOVE, 4, 0)
(RET, 0, 0)
```
ghstack-source-id: 145635622

Test Plan: describe in summary and CI

Reviewed By: iseeyuan

Differential Revision: D32092517

fbshipit-source-id: 0314b4bda5d2578cdd4e7cfbfd1e3c07fbccf8a3
This commit is contained in:
Chen Lai
2021-12-14 19:04:32 -08:00
committed by Facebook GitHub Bot
parent 9e4d60a552
commit 408283319a
5 changed files with 494 additions and 6 deletions

View File

@ -8,15 +8,16 @@
#include <c10/util/ScopeExit.h>
#include <c10/util/irange.h>
#include <caffe2/serialize/inline_container.h>
#include <caffe2/serialize/versions.h>
#include <torch/csrc/jit/api/compilation_unit.h>
#include <torch/csrc/jit/mobile/interpreter.h>
#include <torch/csrc/jit/mobile/observer.h>
#include <torch/csrc/jit/mobile/upgrader_mobile.h>
#include <torch/csrc/jit/runtime/instruction.h>
#include <torch/csrc/jit/serialization/import_export_constants.h>
#include <torch/csrc/jit/serialization/import_export_functions.h>
#include <torch/csrc/jit/serialization/import_read.h>
#include <torch/custom_class.h>
#include <exception>
#include <fstream>
#include <string>
@ -202,6 +203,7 @@ class BytecodeDeserializer final {
private:
TypePtr resolveTypeName(const c10::QualifiedName& qn);
void init_upgrader(mobile::Function* function);
void parseMethods(
c10::ivalue::TupleElements&& vals,
c10::optional<c10::ivalue::TupleElements>&& debug_handles,
@ -298,6 +300,26 @@ void BytecodeDeserializer::parseFunctionSchema(
}
}
void BytecodeDeserializer::init_upgrader(mobile::Function* function) {
for (auto& byteCodeFunctionWithOperator : getUpgraderBytecodeList()) {
// When kUpgraderByteCode is initialized in upgrader_mobile.h, the mobile
// function is initialized with everything (instruction, constants, types,
// registerer size and etc), except operator. The operator function is also
// static initialized and is available later. The oprator for the upgrader
// function will be initialized when the first module is loaded.
if (byteCodeFunctionWithOperator.function.get_code()->operators_.empty()) {
for (const auto& op : byteCodeFunctionWithOperator.operators) {
byteCodeFunctionWithOperator.function.append_operator(
op.name,
op.overload_name,
op.num_specified_args,
caffe2::serialize::kMaxSupportedFileFormatVersion);
}
}
function->append_function(byteCodeFunctionWithOperator.function);
}
}
void BytecodeDeserializer::parseMethods(
c10::ivalue::TupleElements&& vals,
c10::optional<c10::ivalue::TupleElements>&& debug_handles,
@ -375,7 +397,7 @@ void BytecodeDeserializer::parseMethods(
debug_handles_m_tuple =
std::move(*std::move((*debug_handles)[i]).toTuple()).elements();
}
init_upgrader(function.get());
// 1. First pass all operators from models
parseOperators(
std::move(ops_list),
@ -387,15 +409,19 @@ void BytecodeDeserializer::parseMethods(
bool use_upgrader =
(operator_version_ < caffe2::serialize::kProducedFileFormatVersion);
// 3. If upgrader is needed, change change the OP instrunction to CALL
// instruction (In next PR, use_upgrader will be parsed to parseInstruction
// function and do the actual change)
parseInstructions(
function_name,
std::move(ins_list),
debug_handles_m_tuple,
function.get());
// 3. If upgrader is needed, change change the OP instrunction to CALL
// instruction (In next PR, use_upgrader will be parsed to parseInstruction
// function and do the actual change)
if (use_upgrader) {
applyUpgrader(function.get(), operator_version_);
}
parseConstants(consts_list, function.get());
parseTypes(types_list, function.get());