Skip to content
This repository was archived by the owner on Jul 1, 2025. It is now read-only.

Commit cfc989f

Browse files
Man Wangbeicy
authored andcommitted
[Partitioner] First Graph Partitioning
1 parent aa3effc commit cfc989f

File tree

6 files changed

+632
-0
lines changed

6 files changed

+632
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/**
2+
* Copyright (c) 2017-present, Facebook, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#ifndef GLOW_PARTITIONER_PARTITIONER_H
17+
#define GLOW_PARTITIONER_PARTITIONER_H
18+
19+
#include "glow/Graph/Graph.h"
20+
#include "glow/Runtime/RuntimeTypes.h"
21+
22+
#include "llvm/ADT/DenseMap.h"
23+
24+
#include <map>
25+
#include <set>
26+
#include <string>
27+
28+
namespace glow {
29+
30+
using namespace runtime;
31+
32+
using MemUsageMap = std::unordered_map<Node *, unsigned>;
33+
34+
/// Helper structure for building a partition. Records a mapping of nodes in the
35+
/// original function to destination partitions, along with a list of the
36+
/// newly-created functions.
37+
class NodeToFunctionMap {
38+
using Map = llvm::DenseMap<Node *, Function *>;
39+
40+
/// Newly-created partitions.
41+
FunctionList functions_;
42+
43+
/// Map of nodes in the original function to their target partition.
44+
Map nodeToFunction_;
45+
46+
public:
47+
/// Create a new partition \p F.
48+
void createPartition(Function *F) { functions_.emplace_back(F); }
49+
50+
/// Add a new Node->Function mapping.
51+
void add(Node *N, Function *F) { nodeToFunction_[N] = F; }
52+
53+
/// Get list of functions contained in this map.
54+
const FunctionList &getPartitions() const { return functions_; }
55+
56+
/// Map API.
57+
Map::iterator find(Node *N) { return nodeToFunction_.find(N); }
58+
Map::iterator begin() { return nodeToFunction_.begin(); }
59+
Map::iterator end() { return nodeToFunction_.end(); }
60+
Function *operator[](Node *n) { return nodeToFunction_[n]; }
61+
};
62+
63+
/// The struct contains all the created DAGNodes. This DAGNodeList owns all the
64+
/// DAGNodes, which cannot outlive the DAGNodeList. In addition, the DAGNodes
65+
/// can only refer to the DAGNodes from the same DAGNodeList, and they can use
66+
/// the raw pointers to refer to each other since they are in the same
67+
/// DAGNodeList.
68+
struct DAGNodeList {
69+
/// The root DAGNode pointer of each graph/function.
70+
std::vector<std::unique_ptr<DAGNode>> roots;
71+
/// The non-root DAGNode pointers.
72+
std::vector<std::unique_ptr<DAGNode>> nodes;
73+
};
74+
75+
/// Given a module, partitions each of the its functions into multiple ones
76+
/// based on memory constraints and minimizes the communication cost.
77+
class Partitioner {
78+
/// The module that needs to be decomposed.
79+
Module *module_;
80+
81+
/// The representative function used for partition. We choose the function who
82+
/// has the largest memory size.
83+
Function *F_;
84+
85+
/// The cost model related to device.
86+
const std::vector<DeviceInfo> &deviceInfo_;
87+
88+
/// The result of module partitioning.
89+
DAGNodeList partitions_;
90+
91+
/// Total memory (bytes) requested by one module.
92+
size_t memSize_;
93+
94+
/// The map of each operator and the corresponding memory size.
95+
MemUsageMap memUsage_;
96+
97+
/// Get the representative function (the one with the largest input) and
98+
/// update the memSize.
99+
static Function *selectRepFunc(Module *parent, size_t &memSize);
100+
101+
/// Get the minimal memory requirement for each op in the representive
102+
/// function.
103+
void initOpMemUsage();
104+
105+
/// Assign nodes to partitions and return the mapping.
106+
NodeToFunctionMap selectPartitions(Function *F, unsigned availableMemory);
107+
108+
/// Adjust a logicalDevice ID to each DAGNode. It is possible that two
109+
/// sub-functions need to be assigned into 1 device due to the memory
110+
/// constraits.
111+
void adjustLogicalDeviceID(DAGNode *DAG, int num);
112+
113+
/// Given the node-function mapping, do the actual partitioning.
114+
void doPartitioning(Function *F, NodeToFunctionMap &mapping);
115+
116+
public:
117+
/// \p parent is the module which contains the functions need to be divided.
118+
/// Here we assume that all the functions in one module belong to a same
119+
/// "Function Family", that is, without considerting the "dynamic stuff" (i.e.
120+
/// batch size, input/output shape of each op), all the functions are
121+
/// identical. The required memory and computation cost for each op can be
122+
/// found in Module. The \p devices provides the cost model related to
123+
/// devices.
124+
Partitioner(Module *parent, const std::vector<DeviceInfo> &devices);
125+
126+
/// Decompose each function in a module and return a list of DAGNodes.
127+
DAGNodeList &Partition();
128+
};
129+
} // namespace glow
130+
#endif // GLOW_PARTITIONER_PARTITIONER_H

lib/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ add_subdirectory(Optimizer)
1212
add_subdirectory(Quantization)
1313
add_subdirectory(Support)
1414
add_subdirectory(Onnxifi)
15+
add_subdirectory(Partitioner)
16+

lib/Partitioner/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_library(Partitioner
2+
Partitioner.cpp)
3+
4+
target_link_libraries(Partitioner
5+
PRIVATE
6+
Graph)

0 commit comments

Comments
 (0)