Skip to content

Commit 3c07380

Browse files
authored
executer & planner changes to potentially improve placing (#8409) (#8442)
1 parent cfab258 commit 3c07380

File tree

4 files changed

+65
-9
lines changed

4 files changed

+65
-9
lines changed

ydb/core/kqp/executer_actor/kqp_planner.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ bool TKqpPlanner::UseMockEmptyPlanner = false;
6060
// Task can allocate extra memory during execution.
6161
// So, we estimate total memory amount required for task as apriori task size multiplied by this constant.
6262
constexpr ui32 MEMORY_ESTIMATION_OVERFLOW = 2;
63-
constexpr ui32 MAX_NON_PARALLEL_TASKS_EXECUTION_LIMIT = 8;
6463

6564
TKqpPlanner::TKqpPlanner(TKqpPlanner::TArgs&& args)
6665
: TxId(args.TxId)
@@ -256,9 +255,18 @@ std::unique_ptr<IEventHandle> TKqpPlanner::AssignTasksToNodes() {
256255

257256
auto localResources = ResourceManager_->GetLocalResources();
258257
Y_UNUSED(MEMORY_ESTIMATION_OVERFLOW);
258+
259+
auto placingOptions = ResourceManager_->GetPlacingOptions();
260+
261+
bool singleNodeExecutionMakeSence = (
262+
ResourceEstimations.size() <= placingOptions.MaxNonParallelTasksExecutionLimit ||
263+
// all readers are located on the one node.
264+
TasksPerNode.size() == 1
265+
);
266+
259267
if (LocalRunMemoryEst * MEMORY_ESTIMATION_OVERFLOW <= localResources.Memory[NRm::EKqpMemoryPool::ScanQuery] &&
260268
ResourceEstimations.size() <= localResources.ExecutionUnits &&
261-
ResourceEstimations.size() <= MAX_NON_PARALLEL_TASKS_EXECUTION_LIMIT)
269+
singleNodeExecutionMakeSence)
262270
{
263271
ui64 selfNodeId = ExecuterId.NodeId();
264272
for(ui64 taskId: ComputeTasks) {
@@ -293,6 +301,41 @@ std::unique_ptr<IEventHandle> TKqpPlanner::AssignTasksToNodes() {
293301
return std::make_unique<IEventHandle>(ExecuterId, ExecuterId, ev.Release());
294302
}
295303

304+
std::vector<ui64> deepestTasks;
305+
ui64 maxLevel = 0;
306+
for(auto& task: TasksGraph.GetTasks()) {
307+
// const auto& task = TasksGraph.GetTask(taskId);
308+
const auto& stageInfo = TasksGraph.GetStageInfo(task.StageId);
309+
const NKqpProto::TKqpPhyStage& stage = stageInfo.Meta.GetStage(stageInfo.Id);
310+
const ui64 stageLevel = stage.GetProgram().GetSettings().GetStageLevel();
311+
312+
if (stageLevel > maxLevel) {
313+
maxLevel = stageLevel;
314+
deepestTasks.clear();
315+
}
316+
317+
if (stageLevel == maxLevel) {
318+
deepestTasks.push_back(task.Id);
319+
}
320+
}
321+
322+
THashMap<ui64, ui64> alreadyAssigned;
323+
for(auto& [nodeId, tasks] : TasksPerNode) {
324+
for(ui64 taskId: tasks) {
325+
alreadyAssigned.emplace(taskId, nodeId);
326+
}
327+
}
328+
329+
if (deepestTasks.size() <= placingOptions.MaxNonParallelTopStageExecutionLimit) {
330+
// looks like the merge / union all connection
331+
for(ui64 taskId: deepestTasks) {
332+
auto [it, success] = alreadyAssigned.emplace(taskId, ExecuterId.NodeId());
333+
if (success) {
334+
TasksPerNode[ExecuterId.NodeId()].push_back(taskId);
335+
}
336+
}
337+
}
338+
296339
auto planner = (UseMockEmptyPlanner ? CreateKqpMockEmptyPlanner() : CreateKqpGreedyPlanner()); // KqpMockEmptyPlanner is a mock planner for tests
297340

298341
auto ctx = TlsActivationContext->AsActorContext();
@@ -309,13 +352,6 @@ std::unique_ptr<IEventHandle> TKqpPlanner::AssignTasksToNodes() {
309352

310353
auto plan = planner->Plan(ResourcesSnapshot, ResourceEstimations);
311354

312-
THashMap<ui64, ui64> alreadyAssigned;
313-
for(auto& [nodeId, tasks] : TasksPerNode) {
314-
for(ui64 taskId: tasks) {
315-
alreadyAssigned.emplace(taskId, nodeId);
316-
}
317-
}
318-
319355
if (!plan.empty()) {
320356
for (auto& group : plan) {
321357
for(ui64 taskId: group.TaskIds) {

ydb/core/kqp/rm_service/kqp_rm_service.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ class TKqpResourceManager : public IKqpResourceManager {
142142
return Counters;
143143
}
144144

145+
TPlannerPlacingOptions GetPlacingOptions() override {
146+
return TPlannerPlacingOptions{
147+
.MaxNonParallelTasksExecutionLimit = MaxNonParallelTasksExecutionLimit.load(),
148+
.MaxNonParallelTopStageExecutionLimit = MaxNonParallelTopStageExecutionLimit.load(),
149+
};
150+
}
151+
145152
void CreateResourceInfoExchanger(
146153
const NKikimrConfig::TTableServiceConfig::TResourceManager::TInfoExchangerSettings& settings) {
147154
PublishResourcesByExchanger = true;
@@ -414,6 +421,8 @@ class TKqpResourceManager : public IKqpResourceManager {
414421
MinChannelBufferSize.store(config.GetMinChannelBufferSize());
415422
MaxTotalChannelBuffersSize.store(config.GetMaxTotalChannelBuffersSize());
416423
QueryMemoryLimit.store(config.GetQueryMemoryLimit());
424+
MaxNonParallelTopStageExecutionLimit.store(config.GetMaxNonParallelTopStageExecutionLimit());
425+
MaxNonParallelTasksExecutionLimit.store(config.GetMaxNonParallelTasksExecutionLimit());
417426
}
418427

419428
ui32 GetNodeId() override {
@@ -460,6 +469,8 @@ class TKqpResourceManager : public IKqpResourceManager {
460469
std::atomic<i32> ExecutionUnitsLimit;
461470
TLimitedResource<ui64> ScanQueryMemoryResource;
462471
std::atomic<i64> ExternalDataQueryMemory = 0;
472+
std::atomic<ui64> MaxNonParallelTopStageExecutionLimit = 1;
473+
std::atomic<ui64> MaxNonParallelTasksExecutionLimit = 8;
463474

464475
// current state
465476
std::atomic<ui64> LastResourceBrokerTaskId = 0;

ydb/core/kqp/rm_service/kqp_rm_service.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ struct TKqpLocalNodeResources {
202202
std::array<ui64, EKqpMemoryPool::Count> Memory;
203203
};
204204

205+
struct TPlannerPlacingOptions {
206+
ui64 MaxNonParallelTasksExecutionLimit = 8;
207+
ui64 MaxNonParallelTopStageExecutionLimit = 1;
208+
};
209+
205210
/// per node singleton with instant API
206211
class IKqpResourceManager : private TNonCopyable {
207212
public:
@@ -211,6 +216,7 @@ class IKqpResourceManager : private TNonCopyable {
211216

212217
virtual TKqpRMAllocateResult AllocateResources(TIntrusivePtr<TTxState>& tx, TIntrusivePtr<TTaskState>& task, const TKqpResourcesRequest& resources) = 0;
213218

219+
virtual TPlannerPlacingOptions GetPlacingOptions() = 0;
214220
virtual TTaskResourceEstimation EstimateTaskResources(const NYql::NDqProto::TDqTask& task, const ui32 tasksCount) = 0;
215221
virtual void EstimateTaskResources(TTaskResourceEstimation& result, const ui32 tasksCount) = 0;
216222

ydb/core/protos/table_service_config.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ message TTableServiceConfig {
4646

4747
optional uint64 MinMemAllocSize = 23 [default = 8388608]; // 8 MiB
4848
optional uint64 MinMemFreeSize = 24 [default = 33554432]; // 32 MiB
49+
50+
optional uint64 MaxNonParallelTasksExecutionLimit = 25 [default = 8];
51+
optional uint64 MaxNonParallelTopStageExecutionLimit = 26 [default = 1];
4952
}
5053

5154
message TSpillingServiceConfig {

0 commit comments

Comments
 (0)