22
22
#include " llvm/Support/Format.h"
23
23
#include " llvm/Support/raw_ostream.h"
24
24
25
- #include < fstream>
26
-
27
25
#include " llvm/Support/CommandLine.h"
28
26
#include " llvm/Support/raw_ostream.h"
29
27
28
+ #include < fstream>
30
29
namespace glow {
31
30
bool GlowEnableLoadBalancedPartitioning = false ;
32
31
static llvm::cl::opt<bool , /* ExternalStorage */ true >
@@ -62,6 +61,20 @@ bool sortMinMemory(const std::pair<Function *, uint64_t> &a,
62
61
return a.second < b.second ;
63
62
}
64
63
64
+ static void dumpPartitionInfo (const NodeToFunctionMap &partitions) {
65
+ int i = 0 ;
66
+ for (Function *subF : partitions.getPartitions ()) {
67
+ LOG (INFO) << " \t Partition " << i++ << " :\n "
68
+ << " \t\t Name :\t " << subF->getName ().str () << " \n "
69
+ << " \t\t BackendKind :\t "
70
+ << partitions.getPartitionBackendName (subF) << " \n "
71
+ << " \t\t Memory :\t "
72
+ << partitions.getGraphMemInfo (subF).getTotalMemSize () << " \n "
73
+ << " \t\t LogicalDeviceIDs :\t "
74
+ << partitions.getLogicalDeviceIDList (subF)[0 ] << " \n " ;
75
+ }
76
+ }
77
+
65
78
void Partitioner::dumpDAG (llvm::StringRef dotFilename) const {
66
79
if (partitions_.size () == 0 )
67
80
return ;
@@ -168,9 +181,10 @@ Partitioner::Partitioner(Module *parent, const std::vector<DeviceInfo> &devices,
168
181
}
169
182
170
183
Partitioner::Partitioner (Module *parent, const std::vector<DeviceInfo> &devices,
171
- bool saturateHost, bool optimized)
184
+ bool saturateHost, bool optimized,
185
+ PartitionConfig partitionConfig)
172
186
: module_(parent), deviceInfo_(devices), saturateHost_(saturateHost),
173
- optimized_(optimized) {
187
+ optimized_(optimized), partitionConfig_(partitionConfig) {
174
188
memSize_ = module_->getConstantsSize ();
175
189
logicalDeviceID_ = 0 ;
176
190
}
@@ -1211,7 +1225,6 @@ llvm::Error Partitioner::QuantizationProfilingPartition(
1211
1225
module_->eraseFunction (F_);
1212
1226
std::unique_ptr<Backend> backend (createBackend (profilingBackend));
1213
1227
for (Function *subF : module_->getFunctions ()) {
1214
- (void )subF;
1215
1228
assert (subF->verify () && " Conversion led to invalid function" );
1216
1229
if (!optimized_) {
1217
1230
RETURN_IF_ERR (::glow::optimizeFunction (subF, *backend, cctx));
@@ -1231,6 +1244,11 @@ llvm::Error Partitioner::Partition(CompilationContext &cctx) {
1231
1244
std::vector<std::unique_ptr<Backend>> backendHolder;
1232
1245
getBackendMap (backendMap_, backendHolder, backends);
1233
1246
1247
+ if (partitionConfig_.enabled ()) {
1248
+ // Jump into user-defined partition, and skip the following auto partition.
1249
+ return PartitionFromConfig ();
1250
+ }
1251
+
1234
1252
// Step 0: Find the representative function for running partitioning
1235
1253
// algorithm.
1236
1254
F_ = selectRepFunc (module_, memSize_);
@@ -1348,27 +1366,104 @@ llvm::Error Partitioner::Partition(CompilationContext &cctx) {
1348
1366
dumpDAG (" DAG.dot" );
1349
1367
}
1350
1368
1351
- int i = 0 ;
1352
1369
for (Function *subF : funcList) {
1353
- (void )subF;
1354
- if (logPartition) {
1355
- LOG (INFO) << " \t Partition " << i << " :\n "
1356
- << " \t\t Name :\t " << subF->getName ().str () << " \n "
1357
- << " \t\t BackendKind :\t "
1358
- << mapping.getPartitionBackendName (subF) << " \n "
1359
- << " \t\t Memory :\t "
1360
- << mapping.getGraphMemInfo (subF).getTotalMemSize () << " \n "
1361
- << " \t\t LogicalDeviceIDs :\t "
1362
- << mapping.getLogicalDeviceIDList (subF)[0 ] << " \n " ;
1363
- }
1364
1370
if (dumpPartition) {
1365
1371
subF->dumpDAG (" partitionLogicalID" +
1366
1372
std::to_string (mapping.getLogicalDeviceIDList (subF)[0 ]) +
1367
1373
" __" + subF->getFilename () + " __" +
1368
1374
mapping.getPartitionBackendName (subF) + " .dot" );
1369
1375
}
1370
- i++;
1371
1376
assert (subF->verify () && " Conversion led to invalid function" );
1372
1377
}
1378
+ if (logPartition) {
1379
+ dumpPartitionInfo (mapping);
1380
+ }
1381
+ return llvm::Error::success ();
1382
+ }
1383
+
1384
+ llvm::Error Partitioner::PartitionFromConfig () {
1385
+ Function *F = module_->getFunction (partitionConfig_.funcName );
1386
+ RETURN_ERR_IF_NOT (F, strFormat (" Can't find function %s in current module." ,
1387
+ F->getName ().str ().data ()));
1388
+
1389
+ DCHECK (partitionConfig_.numOfPartitions ==
1390
+ partitionConfig_.backendNames .size () &&
1391
+ partitionConfig_.numOfPartitions ==
1392
+ partitionConfig_.partitionNames .size ())
1393
+ << " Invalid user-defined partition config." ;
1394
+
1395
+ NodeToFunctionMap partitionMap;
1396
+ std::vector<Function *> funcList;
1397
+ std::unordered_set<size_t > unused;
1398
+ std::vector<NodesSet> nodesSets (partitionConfig_.numOfPartitions );
1399
+ // Create partitions based on the given number and names.
1400
+ for (size_t i = 0 ; i < partitionConfig_.numOfPartitions ; i++) {
1401
+ Function *newF =
1402
+ module_->createFunction (partitionConfig_.partitionNames [i]);
1403
+ funcList.push_back (newF);
1404
+ partitionMap.createPartition (newF, partitionConfig_.backendNames [i]);
1405
+ unused.insert (i);
1406
+ }
1407
+
1408
+ // Map the nodes the the partitions.
1409
+ std::vector<Node *> unMapped;
1410
+ for (auto &node : F->getNodes ()) {
1411
+ auto iter = partitionConfig_.nodeToPartition .find (node.getName ());
1412
+ if (iter == partitionConfig_.nodeToPartition .end ()) {
1413
+ // If a node in F is not in the node to partition mapping, put it into
1414
+ // unMaped list.
1415
+ unMapped.push_back (&node);
1416
+ } else {
1417
+ size_t partitionID = iter->second ;
1418
+ DCHECK (partitionID < partitionConfig_.numOfPartitions )
1419
+ << " Invalid partition id :" << partitionID;
1420
+ partitionMap.add (&node, funcList[partitionID]);
1421
+ unused.erase (partitionID);
1422
+ nodesSets[partitionID].insert (&node);
1423
+ }
1424
+ }
1425
+
1426
+ // If there is unused partition and unmapped nodes, map those nodes to the
1427
+ // unused partition.
1428
+ if (unMapped.size ()) {
1429
+ DCHECK (unused.size () == 1 ) << " There must be exactly 1 unused partition." ;
1430
+ auto partitionID = *(unused.begin ());
1431
+ for (auto &node : unMapped) {
1432
+ partitionMap.add (node, funcList[partitionID]);
1433
+ nodesSets[partitionID].insert (node);
1434
+ }
1435
+ }
1436
+
1437
+ // Validate memory usage.
1438
+ for (size_t i = 0 ; i < partitionConfig_.numOfPartitions ; i++) {
1439
+ GraphMemInfo cost = getGraphMemInfo (nodesSets[i]);
1440
+ partitionMap.setGraphMemInfo (funcList[i], cost);
1441
+ }
1442
+ RETURN_IF_ERR (memoryUsageValidation (partitionMap));
1443
+
1444
+ // Logical device ID validation.
1445
+ logicalDeviceID_ = assignLogicalDeviceID (partitionMap);
1446
+ RETURN_IF_ERR (logicalDevicesValidation (partitionMap));
1447
+
1448
+ // TODO : loop-free validation.
1449
+
1450
+ // Do partition.
1451
+ doPartitioning (F->getName (), {F}, partitionMap, true );
1452
+ module_->eraseFunction (F);
1453
+
1454
+ // Do optimization based on backendName.
1455
+ for (size_t i = 0 ; i < partitionConfig_.numOfPartitions ; i++) {
1456
+ auto func = funcList[i];
1457
+ assert (func->verify () && " Conversion led to invalid function" );
1458
+ std::unique_ptr<Backend> backend (
1459
+ createBackend (partitionConfig_.backendNames [i]));
1460
+ if (!optimized_) {
1461
+ CompilationContext cctx;
1462
+ RETURN_IF_ERR (::glow::optimizeFunction (func, *backend, cctx));
1463
+ }
1464
+ }
1465
+ if (logPartition) {
1466
+ dumpPartitionInfo (partitionMap);
1467
+ }
1373
1468
return llvm::Error::success ();
1374
1469
}
0 commit comments