Skip to content

Commit

Permalink
Lower Bazel's QoS service class to Utility on macOS.
Browse files Browse the repository at this point in the history
Even though Bazel is an interactive tool, the operations it performs
are not time-critical and should not starve system services (started
by launchd, typically under the Utility class).  To mitigate this
problem, spawn the Bazel server under the Utility priority as well.

In internal tests at Google, we have seen that this vastly improves
build performance and overall system responsiveness when Bazel might
compete with system services such as openvpn or FUSE daemons.

Note that this is not a complete fix though.  We are still letting
the Bazel client run under the default class and the client still
uses execv in a couple of places.  First, in batch mode, and, second,
in "bazel run".  A possible fix for this would involve making the
Bazel client respawn itself under the right priority at the very
beginning but this has its own difficulties that should be looked
into separately.

Fixes bazelbuild#7446 for the most
part.

RELNOTES: None.
PiperOrigin-RevId: 235054167
  • Loading branch information
jmmv authored and copybara-github committed Feb 21, 2019
1 parent d4e13ea commit 0877340
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/main/cpp/blaze_util_darwin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include <sys/un.h>

#include <libproc.h>
#include <pthread/spawn.h>
#include <signal.h>
#include <spawn.h>
#include <stdlib.h>
#include <unistd.h>

Expand Down Expand Up @@ -193,6 +195,19 @@ string GetSystemJavabase() {
return javabase.substr(0, javabase.length()-1);
}

int ConfigureDaemonProcess(posix_spawnattr_t* attrp) {
// The Bazel server and all of its subprocesses consume a ton of resources.
//
// It is common for these processes to rely on system services started by
// launchd and launchd-initiated services typically run as the Utility QoS
// class. We should run Bazel at the same level or otherwise we risk starving
// these services that we require to function properly.
//
// Explicitly lowering Bazel to run at the Utility QoS class also improves
// general system responsiveness.
return posix_spawnattr_set_qos_class_np(attrp, QOS_CLASS_UTILITY);
}

void WriteSystemSpecificProcessIdentifier(
const string& server_dir, pid_t server_pid) {
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/cpp/blaze_util_freebsd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <limits.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
#include <string.h> // strerror
#include <sys/mount.h>
#include <sys/param.h>
Expand Down Expand Up @@ -154,6 +155,11 @@ string GetSystemJavabase() {
return "/usr/local/openjdk8";
}

int ConfigureDaemonProcess(posix_spawnattr_t* attrp) {
// No interesting platform-specific details to configure on this platform.
return 0;
}

void WriteSystemSpecificProcessIdentifier(
const string& server_dir, pid_t server_pid) {
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/cpp/blaze_util_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/magic.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strerror
Expand Down Expand Up @@ -212,6 +213,11 @@ static bool GetStartTime(const string& pid, string* start_time) {
return true;
}

int ConfigureDaemonProcess(posix_spawnattr_t* attrp) {
// No interesting platform-specific details to configure on this platform.
return 0;
}

void WriteSystemSpecificProcessIdentifier(
const string& server_dir, pid_t server_pid) {
string pid_string = ToString(server_pid);
Expand Down
24 changes: 23 additions & 1 deletion src/main/cpp/blaze_util_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@ void ExecuteProgram(const string& exe, const vector<string>& args_vector) {
BAZEL_LOG(INFO) << "Invoking binary " << exe << " in "
<< blaze_util::GetCwd();

// TODO(jmmv): This execution does not respect any settings we might apply
// to the server process with ConfigureDaemonProcess when executed in the
// background as a daemon. Because we use that function to lower the
// priority of Bazel on macOS from a QoS perspective, this could have
// adverse scheduling effects on any tools invoked via ExecuteProgram.
CharPP argv(args_vector);
execv(exe.c_str(), argv.get());
}
Expand Down Expand Up @@ -325,6 +330,12 @@ bool SocketBlazeServerStartup::IsStillAlive() {
}
}

// Sets platform-specific attributes for the creation of the daemon process.
//
// Returns zero on success or -1 on error, in which case errno is set to the
// corresponding error details.
int ConfigureDaemonProcess(posix_spawnattr_t* attrp);

void WriteSystemSpecificProcessIdentifier(
const string& server_dir, pid_t server_pid);

Expand Down Expand Up @@ -366,15 +377,26 @@ int ExecuteDaemon(const string& exe,
<< "Failed to modify posix_spawn_file_actions: "<< GetLastErrorString();
}

posix_spawnattr_t attrp;
if (posix_spawnattr_init(&attrp) == -1) {
BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR)
<< "Failed to create posix_spawnattr: "<< GetLastErrorString();
}
if (ConfigureDaemonProcess(&attrp) == -1) {
BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR)
<< "Failed to modify posix_spawnattr: "<< GetLastErrorString();
}

pid_t transient_pid;
if (posix_spawn(&transient_pid, daemonize.c_str(), &file_actions, NULL,
if (posix_spawn(&transient_pid, daemonize.c_str(), &file_actions, &attrp,
CharPP(daemonize_args).get(), CharPP(env).get()) == -1) {
BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR)
<< "Failed to execute JVM via " << daemonize
<< ": " << GetLastErrorString();
}
close(fds[1]);

posix_spawnattr_destroy(&attrp);
posix_spawn_file_actions_destroy(&file_actions);

// Wait for daemonize to exit. This guarantees that the pid file exists.
Expand Down

0 comments on commit 0877340

Please sign in to comment.