Skip to content

Commit

Permalink
Revert "[Mac] Implement App Nap behaviour for background renderers"
Browse files Browse the repository at this point in the history
This reverts commit ac1cbbb.

Reason for revert: Failing tests: referrer-policy-mismatch.html

external/wpt/speculation-rules/prerender/referrer-policy-mismatch.html

https://ci.chromium.org/ui/p/chromium/builders/ci/Mac13%20Tests/2874/blamelist

Original change's description:
> [Mac] Implement App Nap behaviour for background renderers
>
> With App Nap, sleeping processes are blocked from using too much of
> the system's resources. Under the hood, this is achieved by applying
> a suppression policy to the processes.
>
> With this change, background renderers will have that same suppression
> policy applied to them, which should have a significant effect on the
> performance of other processes.
>
> Another consequence of App Nap is that the OS gives that process a
> default task role of TASK_FOREGROUND_APPLICATION, and its QoS
> settings are set to tier 0.
>
> Thus this CL also updates the `SetCurrentTaskDefaultRole` function to
> apply the same default values to each child process. (The browser
> process already has those settings applied by the OS).
>
> This change only affect MacOS.
>
> Bug: 1466479
> Change-Id: I156606714f586774ec1a9615358a2627c87f6763
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4788107
> Reviewed-by: Mark Mentovai <mark@chromium.org>
> Commit-Queue: Patrick Monette <pmonette@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1185246}

Bug: 1466479
Change-Id: Iaff6cc39fa715714f370c188b57f7720db892b07
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4794455
Commit-Queue: Solomon Kinard <solomonkinard@google.com>
Owners-Override: Solomon Kinard <solomonkinard@google.com>
Auto-Submit: Solomon Kinard <solomonkinard@chromium.org>
Reviewed-by: Patrick Monette <pmonette@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#1185414}
  • Loading branch information
solomonkinardchromium authored and Chromium LUCI CQ committed Aug 18, 2023
1 parent 6dcf5f6 commit c2228fa
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 157 deletions.
4 changes: 3 additions & 1 deletion base/process/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ class BASE_EXPORT Process {
#endif // BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_APPLE)
// Sets the priority of the current process to its default value.
// Sets the `task_role_t` of the current task (the calling process) to
// TASK_DEFAULT_APPLICATION, if the MacSetDefaultTaskRole feature is
// enabled.
static void SetCurrentTaskDefaultRole();
#endif // BUILDFLAG(IS_MAC)

Expand Down
209 changes: 53 additions & 156 deletions base/process/process_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#include <iterator>
#include <memory>
#include <utility>

#include "base/apple/mach_logging.h"
#include "base/feature_list.h"
Expand All @@ -30,8 +29,17 @@ BASE_FEATURE(kMacSetDefaultTaskRole,
"MacSetDefaultTaskRole",
FEATURE_DISABLED_BY_DEFAULT);

// Returns the `task_role_t` of the process whose task port is `task_port`.
absl::optional<task_role_t> GetTaskCategoryPolicyRole(mach_port_t task_port) {
// Returns the `task_role_t` of the process whose process ID is `pid`.
absl::optional<task_role_t> GetTaskCategoryPolicyRole(
PortProvider* port_provider,
ProcessId pid) {
DCHECK(port_provider);

mach_port_t task_port = port_provider->TaskForPid(pid);
if (task_port == TASK_NULL) {
return absl::nullopt;
}

task_category_policy_data_t category_policy;
mach_msg_type_number_t task_info_count = TASK_CATEGORY_POLICY_COUNT;
boolean_t get_default = FALSE;
Expand All @@ -44,103 +52,10 @@ absl::optional<task_role_t> GetTaskCategoryPolicyRole(mach_port_t task_port) {
MACH_LOG(ERROR, result) << "task_policy_get TASK_CATEGORY_POLICY";
return absl::nullopt;
}
CHECK(!get_default);
DCHECK(!get_default);
return category_policy.role;
}

// Sets the task role for `task_port`.
bool SetTaskCategoryPolicy(mach_port_t task_port, task_role_t task_role) {
task_category_policy task_category_policy{.role = task_role};
kern_return_t result =
task_policy_set(task_port, TASK_CATEGORY_POLICY,
reinterpret_cast<task_policy_t>(&task_category_policy),
TASK_CATEGORY_POLICY_COUNT);
if (result != KERN_SUCCESS) {
MACH_LOG(ERROR, result) << "task_policy_set TASK_SUPPRESSION_POLICY";
return false;
}
return true;
}

// Taken from task_policy_private.h.
struct task_suppression_policy {
integer_t active;
integer_t lowpri_cpu;
integer_t timer_throttle;
integer_t disk_throttle;
integer_t cpu_limit;
integer_t suspend;
integer_t throughput_qos;
integer_t suppressed_cpu;
integer_t background_sockets;
integer_t reserved[7];
};

// Taken from task_policy_private.h.
#define TASK_SUPPRESSION_POLICY_COUNT \
((mach_msg_type_number_t)(sizeof(struct task_suppression_policy) / \
sizeof(integer_t)))

// Activates or deactivates the suppression policy to match the effect of App
// Nap.
bool SetTaskSuppressionPolicy(mach_port_t task_port, bool activate) {
task_suppression_policy suppression_policy = {
.active = activate,
.lowpri_cpu = activate,
.timer_throttle =
activate ? LATENCY_QOS_TIER_5 : LATENCY_QOS_TIER_UNSPECIFIED,
.disk_throttle = activate,
.cpu_limit = 0, /* unused */
.suspend = false, /* unused */
.throughput_qos = THROUGHPUT_QOS_TIER_UNSPECIFIED, /* unused */
.suppressed_cpu = activate,
.background_sockets = activate,
};
kern_return_t result =
task_policy_set(task_port, TASK_SUPPRESSION_POLICY,
reinterpret_cast<task_policy_t>(&suppression_policy),
TASK_SUPPRESSION_POLICY_COUNT);
if (result != KERN_SUCCESS) {
MACH_LOG(ERROR, result) << "task_policy_set TASK_SUPPRESSION_POLICY";
return false;
}
return true;
}

// Returns true if the task suppression policy is active for `task_port`.
bool IsTaskSuppressionPolicyActive(mach_port_t task_port) {
task_suppression_policy suppression_policy = {
.active = false,
};

mach_msg_type_number_t task_info_count = TASK_SUPPRESSION_POLICY_COUNT;
boolean_t get_default = FALSE;

kern_return_t result =
task_policy_get(task_port, TASK_SUPPRESSION_POLICY,
reinterpret_cast<task_policy_t>(&suppression_policy),
&task_info_count, &get_default);
if (result != KERN_SUCCESS) {
MACH_LOG(ERROR, result) << "task_policy_get TASK_SUPPRESSION_POLICY";
return false;
}
CHECK(!get_default);

// Only check the `active` property as it is sufficient to discern the state,
// even though other properties could be used.
return suppression_policy.active;
}

// Sets the task role and the suppression policy for `task_port`.
bool SetPriorityImpl(mach_port_t task_port,
task_role_t task_role,
bool activate_suppression_policy) {
// Do both operations, even if the first one fails.
bool succeeded = SetTaskCategoryPolicy(task_port, task_role);
succeeded &= SetTaskSuppressionPolicy(task_port, activate_suppression_policy);
return succeeded;
}

} // namespace

Time Process::CreationTime() const {
Expand All @@ -161,70 +76,58 @@ bool Process::CanSetPriority() {
}

Process::Priority Process::GetPriority(PortProvider* port_provider) const {
CHECK(IsValid());
CHECK(port_provider);

mach_port_t task_port = port_provider->TaskForPid(Pid());
if (task_port == TASK_NULL) {
// Upon failure, return the default value.
return Priority::kUserBlocking;
}

absl::optional<task_role_t> task_role = GetTaskCategoryPolicyRole(task_port);
if (!task_role) {
// Upon failure, return the default value.
return Priority::kUserBlocking;
}
bool is_suppression_policy_active = IsTaskSuppressionPolicyActive(task_port);
if (*task_role == TASK_BACKGROUND_APPLICATION &&
is_suppression_policy_active) {
DCHECK(IsValid());
DCHECK(port_provider);

// A process is backgrounded if the role is explicitly
// TASK_BACKGROUND_APPLICATION (as opposed to not being
// TASK_FOREGROUND_APPLICATION).
absl::optional<task_role_t> task_role =
GetTaskCategoryPolicyRole(port_provider, Pid());
if (task_role && *task_role == TASK_BACKGROUND_APPLICATION) {
return Priority::kBestEffort;
} else if (*task_role == TASK_BACKGROUND_APPLICATION &&
!is_suppression_policy_active) {
return Priority::kUserVisible;
} else if (*task_role == TASK_FOREGROUND_APPLICATION &&
!is_suppression_policy_active) {
return Priority::kUserBlocking;
}

// It is possible to get a different state very early in the process lifetime,
// before SetCurrentTaskDefaultRole() has been invoked. Assume highest
// priority then.
return Priority::kUserBlocking;
}

bool Process::SetPriority(PortProvider* port_provider, Priority priority) {
CHECK(IsValid());
CHECK(port_provider);
DCHECK(IsValid());
DCHECK(port_provider);

if (!CanSetPriority()) {
return false;
}

mach_port_t task_port = port_provider->TaskForPid(Pid());
if (task_port == TASK_NULL) {
if (task_port == TASK_NULL)
return false;

absl::optional<task_role_t> current_role =
GetTaskCategoryPolicyRole(port_provider, Pid());
if (!current_role) {
return false;
}

switch (priority) {
case Priority::kBestEffort:
// Activate the suppression policy.
// Note:
// App Nap keeps the task role to TASK_FOREGROUND_APPLICATION when it
// activates the suppression policy. Here TASK_BACKGROUND_APPLICATION is
// used instead to keep the kBestEffort role consistent with the value for
// kUserVisible (so that its is not greater than kUserVisible). This
// difference is unlikely to matter.
return SetPriorityImpl(task_port, TASK_BACKGROUND_APPLICATION, true);
case Priority::kUserVisible:
// Set a task role with a lower priority than kUserBlocking, but do not
// activate the suppression policy.
return SetPriorityImpl(task_port, TASK_BACKGROUND_APPLICATION, false);
case Priority::kUserBlocking:
default:
// Set the highest priority with the suppression policy inactive.
return SetPriorityImpl(task_port, TASK_FOREGROUND_APPLICATION, false);
const bool background = priority == base::Process::Priority::kBestEffort;
if ((background && *current_role == TASK_BACKGROUND_APPLICATION) ||
(!background && *current_role == TASK_FOREGROUND_APPLICATION)) {
return true;
}

task_category_policy category_policy;
category_policy.role =
background ? TASK_BACKGROUND_APPLICATION : TASK_FOREGROUND_APPLICATION;
kern_return_t result =
task_policy_set(task_port, TASK_CATEGORY_POLICY,
reinterpret_cast<task_policy_t>(&category_policy),
TASK_CATEGORY_POLICY_COUNT);

if (result != KERN_SUCCESS) {
MACH_LOG(ERROR, result) << "task_policy_set TASK_CATEGORY_POLICY";
return false;
}

return true;
}

// static
Expand All @@ -233,17 +136,11 @@ void Process::SetCurrentTaskDefaultRole() {
return;
}

SetTaskCategoryPolicy(mach_task_self(), TASK_FOREGROUND_APPLICATION);

// Set the QoS settings to tier 0, to match the default value given to App Nap
// enabled applications.
task_qos_policy task_qos_policy = {
.task_latency_qos_tier = LATENCY_QOS_TIER_0,
.task_throughput_qos_tier = THROUGHPUT_QOS_TIER_0,
};
task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY,
reinterpret_cast<task_policy_t>(&task_qos_policy),
TASK_QOS_POLICY_COUNT);
task_category_policy category_policy;
category_policy.role = TASK_DEFAULT_APPLICATION;
task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY,
reinterpret_cast<task_policy_t>(&category_policy),
TASK_CATEGORY_POLICY_COUNT);
}

} // namespace base

0 comments on commit c2228fa

Please sign in to comment.