Skip to content

Commit 4b0c51d

Browse files
vj-menonmeta-codesync[bot]
authored andcommitted
Fix multi-component dynamic-dimension names
Summary: Explorer incorrectly names multi-component dynamic dimensions. Standalone tables are registered as `name_0`, `name_1`, and so on, but each value column remains `name`; every component also receives the same `src.name` and `dst.name` object-table columns. This makes the standalone schemas inconsistent and prevents the object table from exposing each component under a unique name. This diff fixes the bug with a file-local [[https://www.internalfb.com/code/fbsource/[bb5ba9591dd9]/fbcode/rebalancer/explorer/cpp_server/lib/LoadModel.cpp?lines=43-54 | `makeScalarDimensionName()`]] helper used by `getDynamicDimensionNames()`, standalone-table registration and construction, and object-column scheduling. Single-component names are unchanged; multi-component tables, value columns, and `src.` and `dst.` columns consistently use `name_index`. Reviewed By: sud03r Differential Revision: D116511110 fbshipit-source-id: c3e4b7bdafe4e3b46a1a50c7699bfcfc626c4031
1 parent a87d074 commit 4b0c51d

3 files changed

Lines changed: 114 additions & 25 deletions

File tree

algopt/rebalancer/explorer/cpp_server/lib/LoadModel.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ namespace facebook::rebalancer::explorer {
3636
using namespace facebook::rebalancer::entities;
3737
using namespace facebook::rebalancer::interface;
3838

39+
namespace {
40+
41+
std::string makeScalarDimensionName(
42+
const std::string& dimensionName,
43+
const int scalarCount,
44+
const int scalarIndex) {
45+
return scalarCount > 1 ? fmt::format("{}_{}", dimensionName, scalarIndex)
46+
: dimensionName;
47+
}
48+
49+
} // namespace
50+
3951
static EquivalenceSetsData buildEquivalenceSetData(
4052
const interface::EquivalenceSetInfo& equivSetInfo,
4153
const Universe& universe) {
@@ -281,9 +293,8 @@ buildStaticObjectDimensionCols(const entities::Universe& universe) {
281293
if (scalarDimension.isRoutingConfigBased()) {
282294
continue;
283295
}
284-
auto colName = (objectDimension.size() > 1)
285-
? fmt::format("{}_{}", dimName, i)
286-
: dimName;
296+
auto colName =
297+
makeScalarDimensionName(dimName, objectDimension.size(), i);
287298

288299
if (!scalarDimension.isDynamic()) {
289300
DataCell defaultDimension(0.0);
@@ -815,9 +826,8 @@ std::vector<std::string> LoadModel::getDynamicDimensionNames(
815826
for (int i = 0; i < dimension.size(); i++) {
816827
const ObjectScalarDimension& scalarDimension = dimension.at(i);
817828
if (scalarDimension.isDynamic()) {
818-
auto dimensionName =
819-
(dimension.size() > 1) ? fmt::format("{}_{}", dimName, i) : dimName;
820-
dynamicDimensionNames.emplace_back(dimensionName);
829+
dynamicDimensionNames.emplace_back(
830+
makeScalarDimensionName(dimName, dimension.size(), i));
821831
}
822832
}
823833
}
@@ -829,15 +839,15 @@ folly::coro::Task<void> buildDynamicTableAsync(
829839
const Universe& universe,
830840
DimensionId dimId,
831841
int index,
832-
std::string dimName,
842+
std::string scalarDimName,
833843
std::shared_ptr<folly::SharedPromise<Table>> promise) {
834844
try {
835845
const ObjectDimension& dimension =
836846
universe.getObjects().getDimension(dimId);
837847
const ObjectScalarDimension& scalarDimension = dimension.at(index);
838848
promise->setValue(
839849
LoadModel::buildDynamicDimensionTable(
840-
universe, scalarDimension, dimName));
850+
universe, scalarDimension, scalarDimName));
841851
} catch (...) {
842852
promise->setException(folly::exception_wrapper(std::current_exception()));
843853
}
@@ -861,15 +871,16 @@ void LoadModel::initDynamicDimensionTables(
861871
for (int i = 0; i < dimension.size(); i++) {
862872
const ObjectScalarDimension& scalarDimension = dimension.at(i);
863873
if (scalarDimension.isDynamic()) {
864-
auto dimensionName =
865-
(dimension.size() > 1) ? fmt::format("{}_{}", dimName, i) : dimName;
874+
auto scalarDimName =
875+
makeScalarDimensionName(dimName, dimension.size(), i);
866876
auto promise = std::make_shared<folly::SharedPromise<Table>>();
867-
tablePromises[dimensionName] = promise;
877+
tablePromises[scalarDimName] = promise;
868878
// Launch the coroutine on the thread pool
869879
asyncScope.add(
870880
folly::coro::co_withExecutor(
871881
executor,
872-
buildDynamicTableAsync(universe, dimId, i, dimName, promise)));
882+
buildDynamicTableAsync(
883+
universe, dimId, i, std::move(scalarDimName), promise)));
873884
}
874885
}
875886
}
@@ -882,11 +893,11 @@ buildDynamicObjectDimensionColAsync(
882893
const Universe& universe,
883894
DimensionId dimId,
884895
int index,
885-
std::string dimName,
896+
std::string scalarDimName,
886897
const Map<entities::ContainerId, std::vector<entities::ObjectId>>&
887898
finalAssignment) {
888899
algopt::treeprof::EventRecorder event("Build dynamic object dimension cols");
889-
XLOG(INFO) << "Building object dimension cols for " << dimName;
900+
XLOG(INFO) << "Building object dimension cols for " << scalarDimName;
890901
const algopt::Timer timer(true);
891902

892903
const ObjectDimension& dimension = universe.getObjects().getDimension(dimId);
@@ -900,13 +911,13 @@ buildDynamicObjectDimensionColAsync(
900911
auto srcColumn = std::make_shared<Column>(
901912
getObjectDimensionValues(initialAssignment, scalarDimension, universe),
902913
defaultCell,
903-
fmt::format("src.{}", dimName),
914+
fmt::format("src.{}", scalarDimName),
904915
ColumnType::DIMENSION);
905916

906917
auto dstColumn = std::make_shared<Column>(
907918
getObjectDimensionValues(finalAssignment, scalarDimension, universe),
908919
defaultCell,
909-
fmt::format("dst.{}", dimName),
920+
fmt::format("dst.{}", scalarDimName),
910921
ColumnType::DIMENSION);
911922

912923
// Insert columns into the objects table
@@ -915,7 +926,7 @@ buildDynamicObjectDimensionColAsync(
915926
result.emplace_back(std::move(srcColumn));
916927
result.emplace_back(std::move(dstColumn));
917928

918-
XLOG(INFO) << "Built object dimension cols for " << dimName << " in "
929+
XLOG(INFO) << "Built object dimension cols for " << scalarDimName << " in "
919930
<< timer.getSeconds() << " seconds";
920931
event.stop();
921932
co_return result;
@@ -942,12 +953,18 @@ buildDynamicObjectDimensionColsAsync(
942953
for (int i = 0; i < dimension.size(); i++) {
943954
const ObjectScalarDimension& scalarDimension = dimension.at(i);
944955
if (scalarDimension.isDynamic()) {
956+
auto scalarDimName =
957+
makeScalarDimensionName(dimName, dimension.size(), i);
945958
// Launch the coroutine on the thread pool
946959
tasks.push_back(
947960
folly::coro::co_withExecutor(
948961
executor,
949962
buildDynamicObjectDimensionColAsync(
950-
universe, dimId, i, dimName, finalAssignment)));
963+
universe,
964+
dimId,
965+
i,
966+
std::move(scalarDimName),
967+
finalAssignment)));
951968
}
952969
}
953970
}

algopt/rebalancer/explorer/cpp_server/lib/LoadModel.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ class LoadModel {
6363
tablePromises,
6464
folly::coro::AsyncScope& asyncScope,
6565
folly::Executor* executor);
66-
6766
static std::vector<std::string> getDynamicDimensionNames(
6867
const entities::Universe& universe);
6968
};

algopt/rebalancer/explorer/cpp_server/tests/LoadModelTest.cpp

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,15 @@ TEST(LoadModelTest, Basic) {
171171
// assert normal object dimension
172172
EXPECT_DOUBLE_EQ(
173173
128000, column->getDouble(toEntityId(universe.getObjectId("host2"))));
174-
} else if (column->getColumnName() == "network") {
175-
// asset network dimension for host3 are added
174+
} else if (column->getColumnName() == "network_0") {
175+
EXPECT_DOUBLE_EQ(
176+
3.0, column->getDouble(toEntityId(universe.getObjectId("host3"))));
177+
} else if (column->getColumnName() == "network_1") {
178+
EXPECT_DOUBLE_EQ(
179+
4.5, column->getDouble(toEntityId(universe.getObjectId("host3"))));
180+
} else if (column->getColumnName() == "network_2") {
176181
EXPECT_DOUBLE_EQ(
177-
8.0, column->getDouble(toEntityId(universe.getObjectId("host3"))));
182+
1.0, column->getDouble(toEntityId(universe.getObjectId("host3"))));
178183
} else if (column->getColumnName() == "scheme") {
179184
// assert partition data for object
180185
EXPECT_EQ(
@@ -373,6 +378,69 @@ TEST(LoadModelTest, DynamicDimensionTableUsesGroupRowsForCompactStorage) {
373378
EXPECT_DOUBLE_EQ(7.0, dimensionValues->getDouble(groupRow));
374379
}
375380

381+
TEST(LoadModelTest, MultiComponentDynamicDimensionsHaveUniqueNames) {
382+
auto bundle = TestUtils::buildBundle();
383+
auto& dimensions = *bundle.problem()->universe()->objects()->dimensions();
384+
entities::thrift::ObjectDimension* dynamicDimension = nullptr;
385+
for (auto& entry : dimensions) {
386+
auto& dimension = entry.second;
387+
if (*dimension.isDynamic()) {
388+
dynamicDimension = &dimension;
389+
break;
390+
}
391+
}
392+
if (!dynamicDimension) {
393+
FAIL() << "Expected the test universe to contain a dynamic dimension";
394+
}
395+
auto& scalarDimensions = *dynamicDimension->scalarDimensions();
396+
ASSERT_EQ(1, scalarDimensions.size());
397+
scalarDimensions.push_back(scalarDimensions.front());
398+
399+
auto explorerModel = LoadModel::buildData(std::move(bundle));
400+
addObjectTable(explorerModel);
401+
const auto& universe = *explorerModel.universe;
402+
auto dynamicDimensionName = explorerModel.dynamicDimensionNames.begin();
403+
std::set<std::string> detailColumnNames;
404+
for (const auto dimensionId : universe.getObjects().getDimensionIds()) {
405+
const auto& dimension = universe.getObjects().getDimension(dimensionId);
406+
for (int scalarIndex = 0; scalarIndex < dimension.size(); ++scalarIndex) {
407+
if (!dimension.at(scalarIndex).isDynamic()) {
408+
continue;
409+
}
410+
ASSERT_NE(
411+
dynamicDimensionName, explorerModel.dynamicDimensionNames.end());
412+
const auto table = LoadModel::buildDynamicDimensionTable(
413+
universe, dimension.at(scalarIndex), *dynamicDimensionName++);
414+
for (const auto& column : table.getColumnData()) {
415+
if (column->getColumnType() == ColumnType::DIMENSION) {
416+
detailColumnNames.insert(column->getColumnName());
417+
}
418+
}
419+
}
420+
}
421+
EXPECT_EQ(dynamicDimensionName, explorerModel.dynamicDimensionNames.end());
422+
423+
const auto expectedDetailColumnNames =
424+
makeSet<std::string>({"dynamicLoad_0", "dynamicLoad_1"});
425+
EXPECT_EQ(expectedDetailColumnNames, detailColumnNames);
426+
427+
std::set<std::string> objectColumnNames;
428+
for (const auto& columnName :
429+
explorerModel.tableData.at(universe.getObjectTypeName())
430+
.getColumnNames()) {
431+
if (columnName.starts_with("src.dynamicLoad") ||
432+
columnName.starts_with("dst.dynamicLoad")) {
433+
objectColumnNames.insert(columnName);
434+
}
435+
}
436+
const auto expectedObjectColumnNames = makeSet<std::string>(
437+
{"src.dynamicLoad_0",
438+
"dst.dynamicLoad_0",
439+
"src.dynamicLoad_1",
440+
"dst.dynamicLoad_1"});
441+
EXPECT_EQ(expectedObjectColumnNames, objectColumnNames);
442+
}
443+
376444
TEST(ModelTest, MoveGroupTogether) {
377445
// Build the problem.
378446
UniverseProblemBuilder builder(
@@ -622,10 +690,15 @@ TEST(LoadModelTest, BasicWithNoSolutionObject) {
622690
} else if (column->getColumnName() == "dst.dynamicLoad") {
623691
EXPECT_DOUBLE_EQ(
624692
1.0, column->getDouble(toEntityId(universe.getObjectId("host0"))));
625-
} else if (column->getColumnName() == "network") {
626-
// assert network dimension for host3 are added
693+
} else if (column->getColumnName() == "network_0") {
694+
EXPECT_DOUBLE_EQ(
695+
3.0, column->getDouble(toEntityId(universe.getObjectId("host3"))));
696+
} else if (column->getColumnName() == "network_1") {
697+
EXPECT_DOUBLE_EQ(
698+
4.5, column->getDouble(toEntityId(universe.getObjectId("host3"))));
699+
} else if (column->getColumnName() == "network_2") {
627700
EXPECT_DOUBLE_EQ(
628-
8.0, column->getDouble(toEntityId(universe.getObjectId("host3"))));
701+
1.0, column->getDouble(toEntityId(universe.getObjectId("host3"))));
629702
} else if (column->getColumnName() == kEquivSetPartition.data()) {
630703
const auto allObjectIds = universe.getObjects().getObjectIds();
631704
std::set<std::string> equivSetNames;

0 commit comments

Comments
 (0)