Skip to content

Commit 98b170b

Browse files
seantaltsGoogle-ML-Automation
authored andcommitted
[XLA:CPU] Optimize StackFrames Proto index access and Dynamically Cap MultiModuleDriver parallel compilation concurrency
- Rewrote `StackFrames::IsPrefix` to traverse stack frames directly via `.parent_frame_id()` protobuf indexes rather than allocating full `HloStackFrame` structural copies on every hop, resolving extreme compile-time O(N) memory allocation hotspots during call graph metadata propagation. - Capped `MultiModuleDriver::Compile` parallel submodule compilation to dynamically match the dimensions of `CompileOptions::thread_pool` (or a safe fallback limit of 8 concurrent LLVM compilations) to prevent Out-Of-Memory (OOM) hard freezes and virtual memory thrashing when compiling massively split models (like `torax`) under `FAST_COMPILE`. PiperOrigin-RevId: 931295728
1 parent 50469bb commit 98b170b

3 files changed

Lines changed: 53 additions & 15 deletions

File tree

xla/hlo/ir/stack_frames.cc

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,25 @@ HloStackFrame StackFrames::GetStackFrame(StackFrameId id) const {
117117
}
118118

119119
StackFrameId StackFrames::AddStackFrame(const HloStackFrame& frame) {
120-
auto [file_it, file_inserted] = file_name_to_id_.try_emplace(
121-
std::string(frame.file_name), proto_.file_names_size() + 1);
122-
if (file_inserted) {
120+
FileNameId file_id;
121+
auto file_it = file_name_to_id_.find(frame.file_name);
122+
if (file_it != file_name_to_id_.end()) {
123+
file_id = file_it->second;
124+
} else {
125+
file_id = proto_.file_names_size() + 1;
126+
file_name_to_id_.emplace(std::string(frame.file_name), file_id);
123127
proto_.add_file_names(std::string(frame.file_name));
124128
}
125-
FileNameId file_id = file_it->second;
126129

127-
auto [func_it, func_inserted] = function_name_to_id_.try_emplace(
128-
std::string(frame.function_name), proto_.function_names_size() + 1);
129-
if (func_inserted) {
130+
FunctionNameId func_id;
131+
auto func_it = function_name_to_id_.find(frame.function_name);
132+
if (func_it != function_name_to_id_.end()) {
133+
func_id = func_it->second;
134+
} else {
135+
func_id = proto_.function_names_size() + 1;
136+
function_name_to_id_.emplace(std::string(frame.function_name), func_id);
130137
proto_.add_function_names(std::string(frame.function_name));
131138
}
132-
FunctionNameId func_id = func_it->second;
133139

134140
FileLocationKey loc_key = {file_id, func_id, frame.line,
135141
frame.column, frame.end_line, frame.end_column};
@@ -165,7 +171,10 @@ bool StackFrames::IsPrefix(StackFrameId prefix, StackFrameId full) const {
165171
if (full == prefix) {
166172
return true;
167173
}
168-
full = GetStackFrame(full).parent_frame_id;
174+
if (full.value > proto_.stack_frames_size()) {
175+
return false;
176+
}
177+
full = StackFrameId{proto_.stack_frames(full.value - 1).parent_frame_id()};
169178
}
170179
return false;
171180
}

xla/service/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,10 +1871,14 @@ cc_library(
18711871
"//xla/hlo/transforms:hlo_module_stitcher",
18721872
"//xla/stream_executor:stream_executor_h",
18731873
"//xla/tsl/concurrency:executor",
1874+
"//xla/tsl/platform:env",
18741875
"//xla/tsl/platform:status_macros",
1876+
"@com_google_absl//absl/base:core_headers",
18751877
"@com_google_absl//absl/container:flat_hash_map",
18761878
"@com_google_absl//absl/status:statusor",
1879+
"@com_google_absl//absl/synchronization",
18771880
"@tsl//tsl/platform:blocking_counter",
1881+
"@tsl//tsl/platform:platform_port",
18781882
],
18791883
)
18801884

xla/service/multi_module_driver.cc

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ limitations under the License.
2222
#include <utility>
2323
#include <vector>
2424

25+
#include "absl/base/thread_annotations.h"
2526
#include "absl/container/flat_hash_map.h"
2627
#include "absl/status/statusor.h"
28+
#include "absl/synchronization/mutex.h"
2729
#include "xla/tsl/platform/status_macros.h"
2830
#include "xla/hlo/ir/hlo_computation.h"
2931
#include "xla/hlo/ir/hlo_module.h"
@@ -33,7 +35,9 @@ limitations under the License.
3335
#include "xla/service/compiler.h"
3436
#include "xla/stream_executor/stream_executor.h"
3537
#include "xla/tsl/concurrency/executor.h"
38+
#include "xla/tsl/platform/threadpool.h"
3639
#include "tsl/platform/blocking_counter.h"
40+
#include "tsl/platform/cpu_info.h"
3741

3842
namespace xla {
3943

@@ -89,14 +93,35 @@ absl::StatusOr<std::unique_ptr<HloModule>> MultiModuleDriver::Compile(
8993
results[i] = compile_fn_(std::move(all_modules[i]), options);
9094
}
9195
} else {
92-
// Parallel compilation.
96+
// Parallel compilation with concurrency capping to avoid LLVM OOM or
97+
// thrashing.
98+
int max_concurrency = std::max<int>(
99+
1, options.thread_pool ? options.thread_pool->NumThreads()
100+
: std::min<int>(8, tsl::port::MaxParallelism()));
101+
102+
absl::Mutex mutex;
103+
int active_compilations = 0;
104+
93105
tsl::BlockingCounter counter(all_modules.size());
94106
for (size_t i = 0; i < all_modules.size(); ++i) {
95-
executor->Execute(
96-
[this, &all_modules, &options, &results, &counter, i]() {
97-
results[i] = compile_fn_(std::move(all_modules[i]), options);
98-
counter.DecrementCount();
99-
});
107+
{
108+
absl::MutexLock lock(&mutex);
109+
auto can_compile = [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex) {
110+
return active_compilations < max_concurrency;
111+
};
112+
mutex.Await(absl::Condition(&can_compile));
113+
active_compilations++;
114+
}
115+
116+
executor->Execute([this, &all_modules, &options, &results, &counter,
117+
&mutex, &active_compilations, i]() {
118+
results[i] = compile_fn_(std::move(all_modules[i]), options);
119+
{
120+
absl::MutexLock lock(&mutex);
121+
active_compilations--;
122+
}
123+
counter.DecrementCount();
124+
});
100125
}
101126
counter.Wait();
102127
}

0 commit comments

Comments
 (0)