Skip to content

Commit

Permalink
verbose mode for autotune.php and RAM detection
Browse files Browse the repository at this point in the history
  • Loading branch information
dzuelke committed Jan 30, 2024
1 parent 2d96005 commit 3866053
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 23 deletions.
9 changes: 7 additions & 2 deletions bin/heroku-php-apache2
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,10 @@ httpd_command=( httpd -D NO_DETACH -c "Include $httpd_config" )

mlib="/sys/fs/cgroup/memory/memory.limit_in_bytes"
if [[ -f "$mlib" ]]; then
[[ $verbose ]] && echo "Reading available RAM from '$mlib'" >&2
ram="$(cat "$mlib")"
else
[[ $verbose ]] && echo "No '$mlib' with RAM info found" >&2
ram="512M"
echo "Assuming RAM to be ${ram} Bytes" >&2
fi
Expand All @@ -401,6 +403,8 @@ if [[ -z ${WEB_CONCURRENCY:-} ]]; then
max_ram="6G"
fi

[[ $verbose ]] && echo "Calculating WEB_CONCURRENCY..." >&2

# dump the FPM config and parse out memory_limit declarations
# for that to work, we need the WEB_CONCURRENCY env var set, as the FPM config references it
export WEB_CONCURRENCY=1
Expand All @@ -419,8 +423,9 @@ if [[ -z ${WEB_CONCURRENCY:-} ]]; then
# determine number of FPM processes to run
# we feed it the PHP config we found much earlier (it must be the one FPM loads, not the CLI one!), docroot (for .user.ini), detected RAM, and RAM cap
# on STDIN, we also pass it any php_value or php_admin_value lines from the FPM config dump that may have a memory_limit (via a herestring, easier than echo)
WEB_CONCURRENCY=$(php ${php_config:+-c "$php_config"} "$bp_dir/bin/util/autotune.php" -t "$DOCUMENT_ROOT" "$ram" "$max_ram" <<<"$fpm_limits")
[[ $WEB_CONCURRENCY -lt 1 ]] && WEB_CONCURRENCY=1
WEB_CONCURRENCY=$(php ${php_config:+-c "$php_config"} -f "$bp_dir/bin/util/autotune.php" -- ${verbose:+-v} -t "$DOCUMENT_ROOT" "$ram" "$max_ram" <<<"$fpm_limits")
[[ $verbose ]] && echo "WEB_CONCURRENCY=${WEB_CONCURRENCY} (RAM / memory_limit)" >&2
[[ $WEB_CONCURRENCY -lt 1 ]] && { WEB_CONCURRENCY=1; [[ $verbose ]] && echo "WEB_CONCURRENCY=1 (was below mininum)" >&2; }
export WEB_CONCURRENCY
else
echo '$WEB_CONCURRENCY env var is set, skipping automatic calculation' >&2
Expand Down
9 changes: 7 additions & 2 deletions bin/heroku-php-nginx
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,10 @@ nginx_command=( nginx -c "$nginx_main" -g "pid $nginx_pidfile; include $nginx_co

mlib="/sys/fs/cgroup/memory/memory.limit_in_bytes"
if [[ -f "$mlib" ]]; then
[[ $verbose ]] && echo "Reading available RAM from '$mlib'" >&2
ram="$(cat "$mlib")"
else
[[ $verbose ]] && echo "No '$mlib' with RAM info found" >&2
ram="512M"
echo "Assuming RAM to be ${ram} Bytes" >&2
fi
Expand All @@ -401,6 +403,8 @@ if [[ -z ${WEB_CONCURRENCY:-} ]]; then
max_ram="6G"
fi

[[ $verbose ]] && echo "Calculating WEB_CONCURRENCY..." >&2

# dump the FPM config and parse out memory_limit declarations
# for that to work, we need the WEB_CONCURRENCY env var set, as the FPM config references it
export WEB_CONCURRENCY=1
Expand All @@ -419,8 +423,9 @@ if [[ -z ${WEB_CONCURRENCY:-} ]]; then
# determine number of FPM processes to run
# we feed it the PHP config we found much earlier (it must be the one FPM loads, not the CLI one!), docroot (for .user.ini), detected RAM, and RAM cap
# on STDIN, we also pass it any php_value or php_admin_value lines from the FPM config dump that may have a memory_limit (via a herestring, easier than echo)
WEB_CONCURRENCY=$(php ${php_config:+-c "$php_config"} "$bp_dir/bin/util/autotune.php" -t "$DOCUMENT_ROOT" "$ram" "$max_ram" <<<"$fpm_limits")
[[ $WEB_CONCURRENCY -lt 1 ]] && WEB_CONCURRENCY=1
WEB_CONCURRENCY=$(php ${php_config:+-c "$php_config"} -f "$bp_dir/bin/util/autotune.php" -- ${verbose:+-v} -t "$DOCUMENT_ROOT" "$ram" "$max_ram" <<<"$fpm_limits")
[[ $verbose ]] && echo "WEB_CONCURRENCY=${WEB_CONCURRENCY} (RAM / memory_limit)" >&2
[[ $WEB_CONCURRENCY -lt 1 ]] && { WEB_CONCURRENCY=1; [[ $verbose ]] && echo "WEB_CONCURRENCY=1 (was below mininum)" >&2; }
export WEB_CONCURRENCY
else
echo '$WEB_CONCURRENCY env var is set, skipping automatic calculation' >&2
Expand Down
52 changes: 33 additions & 19 deletions bin/util/autotune.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function bytestostring($amount) {
return sprintf("%d%s", $amount, $suffix);
}

$opts = getopt("t:", array(), $rest_index);
$opts = getopt("vt:", array(), $rest_index);
$argv = array_slice($argv, $rest_index);
$argc = count($argv);
if($argc < 1 || $argc > 2) {
Expand All @@ -40,13 +40,28 @@ function bytestostring($amount) {
);
fputs(STDERR,
"Options:\n".
" -v Verbose mode\n".
" -t <DOCUMENT_ROOT> Dir to read '.user.ini' with 'memory_limit' settings from\n\n".
"php_value or php_admin_value lines from a PHP-FPM config can be fed via STDIN.\n\n"
);
exit(2);
}

// first, parse potential php_value and php_admin_value data from STDIN
$ram = stringtobytes($argv[0]); // first arg is the available memory

fprintf(STDERR, "Available RAM is %s Bytes\n", bytestostring($ram));

if(isset($argv[1])) { // optional second arg is the maximum RAM we're allowed
$max_ram_string = $argv[1];
$max_ram = stringtobytes($max_ram_string);

if($ram > $max_ram) {
$ram = $max_ram;
fprintf(STDERR, "Limiting RAM usage to %s Bytes\n", bytestostring($ram));
}
}

// parse potential php_value and php_admin_value data from STDIN
// the expected format is lines like the following:
// php_value[memory_limit] = 128M
// php_admin_value[memory_limit] = 128M
Expand All @@ -56,42 +71,41 @@ function bytestostring($amount) {
exit(1);
}

if(isset($opts['v'])) {
if(isset($limits['php_value'])) {
fputs(STDERR, "memory_limit changed by php_value in PHP-FPM configuration\n");
}
}

if(
isset($opts['t']) &&
is_readable($opts['t'].'/.user.ini')
is_readable($userini_path = $opts['t'].'/.user.ini')
) {
// we only read the topmost .user.ini inside document root
$userini = parse_ini_file($opts['t'].'/.user.ini');
$userini = parse_ini_file($userini_path);
if($userini === false) {
fputs(STDERR, "ERROR: Malformed .user.ini in document root.\n");
fprintf(STDERR, "ERROR: Malformed %s.\n", $userini_path);
exit(1);
}
if(isset($userini['memory_limit'])) {
if(isset($opts['v'])) {
fprintf(STDERR, "memory_limit changed by %s\n", $userini_path);
}
// if .user.ini has a limit set, it will overwrite an FPM config php_value, but not a php_admin_value
$limits['php_value']['memory_limit'] = $userini['memory_limit'];
}
}

if(isset($limits['php_admin_value']['memory_limit'])) {
// these take precedence and cannot be overridden later
if(isset($opts['v'])) {
fputs(STDERR, "memory_limit overridden by php_admin_value in PHP-FPM configuration\n");
}
ini_set('memory_limit', $limits['php_admin_value']['memory_limit']);
} elseif(isset($limits['php_value']['memory_limit'])) {
ini_set('memory_limit', $limits['php_value']['memory_limit']);
}

$ram = stringtobytes($argv[0]); // first arg is the available memory

fprintf(STDERR, "Available RAM is %s Bytes\n", bytestostring($ram));

if(isset($argv[1])) { // optional second arg is the maximum RAM we're allowed
$max_ram_string = $argv[1];
$max_ram = stringtobytes($max_ram_string);

if($ram > $max_ram) {
$ram = $max_ram;
fprintf(STDERR, "Limiting RAM usage to %s Bytes\n", bytestostring($ram));
}
}

$limit = ini_get('memory_limit');
fprintf(STDERR, "PHP memory_limit is %s Bytes\n", $limit); // we output the original value here, since it's user supplied

Expand Down

0 comments on commit 3866053

Please sign in to comment.