-
Notifications
You must be signed in to change notification settings - Fork 699
[Partitioner] Partitioner refactoring 3 #3384
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
Conversation
cbe8afa
to
f59a8a8
Compare
using namespace runtime; | ||
/// Given a module, partitions each of the its functions into multiple ones | ||
/// based on memory constraints and minimizes the communication cost. | ||
class PartitionerBase { |
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.
let's clean up this interface a bit as discussed offline.
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.
Done.
|
||
/// Decompose each function in a module. \p cctx is used in function | ||
/// optimization. \returns whether there was an error encountered. | ||
virtual llvm::Error Partition(CompilationContext &cctx) { |
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.
Nit: should be lowercase p
to match our coding conventions.
/// among different type of devices. \p cctx is used during optimization of | ||
/// the Function. \returns whether there was an error encountered. | ||
llvm::Error Partition(CompilationContext &cctx); | ||
llvm::Error PartitionFromConfig(PartitionConfig &partitionConfig); |
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.
Same initial-caps nit, here and a few places below.
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.
@beicy has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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.
BTW while you're refactoring, how do you feel about dropping the Ty
suffix from the partitioner/runtime types? I think @bertmaher has mentioned this before. E.g. DAGListTy
, DeviceIDTy
, etc.
/// The representative function used for partition. We choose the function who | ||
/// has the largest memory size. | ||
Function *F_; | ||
|
||
/// The partition result. | ||
DAGListTy partitions_; |
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.
Would it make sense for this to be moved to PartitionerBase
? PartitionerBase::partition()
will always return a reference to this DAGListTy
, right?
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.
"PartitionerBase::partition() will always return a reference to this DAGListTy, right?"
-- Yes.
"Would it make sense for this to be moved to PartitionerBase? "
-- After the offline discussion with @rdzhabarov, we would like to make the PartitionerBase "stateless".
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.
Question: do we really need to keep DAGListTy partitions_;
in partitioner.
Role of the partitioner is to generate DAGList
and return it back to the caller (once generated it's never accessed in partitioner).
What do we gain by keeping partitions_ here?
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.
Removed DAGListTy partitions_;
in partitioner.
virtual ~PartitionerBase() = default; | ||
|
||
/// Decompose each function in a module. \p cctx is used in function | ||
/// optimization. \returns whether there was an error encountered. |
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.
nit: Think this was copy+paste -- but I don't think it's correct anymore to say it returns whether there was an error encountered. In normal circumstances it actually returns the DAGList
.
For "Ty", if we decide to move that, I think it is better to get a separate PR, since other parts of Runtime (e.g. Provisioner) use those date type as well. |
/// need to be created, we use \p backendsHolder to hold them for memory | ||
/// purpose. | ||
void getBackendMap(std::map<std::string, BackendInfo> &backendMap, | ||
/// Greate the map between the backend name and the concrete backend info |
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.
typo: Greate -> Create
0c52c95
to
8c56fbc
Compare
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.
@beicy has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
64b05ce
to
c69a38b
Compare
|
||
FunctionToBackendNameMap | ||
backendBasedPartition(Function *F, std::vector<Backend *> &backends, | ||
/// Do the partition based on backend types. |
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.
could you add some description to the doxygen, e.g., what F is and what's stored in functobackend map etc.
/// the Function. \returns whether there was an error encountered. | ||
llvm::Error Partition(CompilationContext &cctx); | ||
llvm::Expected<DAGListTy> | ||
partitionFromConfig(PartitionConfig &partitionConfig); |
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.
why config is not a const here?
Function *F, | ||
std::vector<Backend *> backends); | ||
llvm::Expected<DAGListTy> | ||
quantizationProfilingPartition(CompilationContext &cctx); |
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.
why all these special methods are part of the public interface of partitioner?
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.
Discussed with @artemrakhov before. It allows users to call those method directly. For example, user-defined partitioner can be called directly without setting params, e.g "optimized_" and "saturateHost_". @artemrakhov could you please also help to double check the interface? Thanks!
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.
Yes, this is the right direction! It is very useful to be able to call just one method.
But Roman wanted to bring a different question to your attention. Can we create more Partitioner-based (inherited) classes? I.e. we could further introduce UserDefinedPartitioner
, SaturatingPartitioner
, and so on. Whatever makes sense. That way, Partitioner
class itself won't implement any "special" partitions. It will be a very general class.
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.
Yes, this is the right direction! It is very useful to be able to call just one method.
But Roman wanted to bring a different question to your attention. Can we create more Partitioner-based (inherited) classes? I.e. we could further introduce
UserDefinedPartitioner
,SaturatingPartitioner
, and so on. Whatever makes sense. That way,Partitioner
class itself won't implement any "special" partitions. It will be a very general class.
We now have "class PartitionerBase" and new partitioner class can be derived from that. The reason we have current partition flows in Partitioner because they shares lots of common data types, internal members. We would like to keep "class PartitionerBase" stateless.
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.
We can do further inheritance. For example: PartitionerBase -> Partitioner -> UserDefinedPartitioner
lib/Partitioner/Partitioner.cpp
Outdated
@@ -723,30 +542,20 @@ llvm::Error Partitioner::QuantizationProfilingPartition( | |||
<< "Profiling a model to be partitioned cross different backends. Each " | |||
"sub-network will be optimized and run on cpu backend.\n"; | |||
} | |||
return llvm::Error::success(); | |||
return partitions; |
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.
while refactoring can you replace asserts with DCHECK and add more detail to error message where applicable.
ecebbe7
to
3f969aa
Compare
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.
@beicy has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
49de964
to
b0842f1
Compare
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.
@beicy has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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.
LGTM! Just a series of doxygen/comment stuff.
@@ -83,10 +83,13 @@ class Partitioner { | |||
llvm::StringRef backendName); | |||
|
|||
/// Duplicates all networks in the module order to saturate the Host. |
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.
nit: Update doxygen to mention the method parameters.
/// Partition a function \p F based on backends \p backends. \returns the | ||
/// final result and a map between partitions and backend names. | ||
llvm::Expected<DAGListTy> | ||
backendBasedPartition(FunctionToBackendNameMap &FuncToBackend, Function *F, |
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.
nit: uncapitalize FuncToBackend
(matches the cpp definition)
FunctionToBackendNameMap | ||
backendBasedPartition(Function *F, std::vector<Backend *> &backends, | ||
/// Partition a function \p F based on backends \p backends. \returns the | ||
/// final result and a map between partitions and backend names. |
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.
nit: Update doxygen with all method params
/// partition result. | ||
void doPartitioning(llvm::StringRef funcName, std::vector<Function *>, | ||
NodeToFunctionMap &mapping, bool saveDAG); | ||
|
||
/// If there is no need to do any partition, just generate the DAGNode based | ||
/// on current functions in this module for backend \p backendName found in \p | ||
/// backendMap. \p cctx is used during optimization of the Function. \returns | ||
/// whether there was an error encountered. |
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.
nit: This doesn't return if an error was encountered, it returns the DAG list or else an error.
/// the Function. \returns whether there was an error encountered. | ||
llvm::Error Partition(CompilationContext &cctx); | ||
llvm::Expected<DAGListTy> | ||
partitionFromConfig(const PartitionConfig &partitionConfig); | ||
|
||
/// This partition approach is used in Glow Quantization Profiling flow. The | ||
/// backendBasedPartition is applied first in case there are heterogeneous | ||
/// backends. Then each sub-function will be compiled and run in CPU backend | ||
/// for profiling. |
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.
nit: \returns ...
and mention cctx.
void dumpDAG(llvm::StringRef dotFilename, const DAGListTy &partitions) const; | ||
|
||
protected: | ||
/// Given the node-function mapping, do the actual partitioning. If \p saveDAG |
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.
nit: \p mapping
etc. and \returns
instead of partitions_
.
lib/Partitioner/Partitioner.cpp
Outdated
@@ -237,13 +178,14 @@ NodeToFunctionMap Partitioner::selectPartitions(Function *F, | |||
/// Duplicate the network to saturate the number of devices. For example: If a |
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.
Looks like this doxygen can be moved to the header?
lib/Partitioner/Partitioner.cpp
Outdated
@@ -825,7 +641,7 @@ llvm::Error Partitioner::Partition(CompilationContext &cctx) { | |||
} | |||
|
|||
// Step 5 : do the real partitioning for the function list. | |||
doPartitioning(origName, funcs, mapping, true); | |||
partitions = doPartitioning(origName, funcs, module_, mapping, true); |
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.
nit: /* saveDAG */ true
lib/Partitioner/Partitioner.cpp
Outdated
@@ -931,15 +751,15 @@ llvm::Error Partitioner::PartitionFromConfig() { | |||
// TODO : loop-free validation. | |||
|
|||
// Do partition. | |||
doPartitioning(F->getName(), {F}, partitionMap, true); | |||
partitions = doPartitioning(F->getName(), {F}, module_, partitionMap, true); |
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.
nit: /* saveDAG */ true
lib/Partitioner/PartitionerBase.cpp
Outdated
using namespace glow; | ||
using llvm::isa; | ||
|
||
/// Current only partition the representative function. |
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.
nit: Don't need doxygen in cpp files.
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.
@beicy has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Summary:
In this PR:
class ParititionerBase
which contains interfaces and common functions used for partitioner. and theclass Partitioner
is now derived fromclass ParititionerBase
.class Partitioner
, we have 3 partition approaches:The above 3 method can be called directly by users, or chosen by
llvm::Error Partition(CompilationContext &cctx)
Note:
loadBalancedPartitioning
is still included inHeterogeneousPartition
since it uses the result of current partitioner approach. Will take it fromHeterogeneousPartition
in next PR and make it as the 4th partition approach.Documentation:
[Optional Fixes #issue]
#2298
Test Plan:
Ninja test, ./tests/image/run.sh
Please see a detailed explanation of how to fill out the fields in the relevant sections in PULL_REQUEST.md.