mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-12 11:25:35 +08:00
move pgo from new to static creation method
This commit is contained in:
@@ -23,6 +23,8 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
/** @var bool Micro patch phar flag */
|
/** @var bool Micro patch phar flag */
|
||||||
private bool $phar_patched = false;
|
private bool $phar_patched = false;
|
||||||
|
|
||||||
|
private ?PgoManager $pgo = null;
|
||||||
|
|
||||||
public function __construct(array $options = [])
|
public function __construct(array $options = [])
|
||||||
{
|
{
|
||||||
$this->options = $options;
|
$this->options = $options;
|
||||||
@@ -49,6 +51,8 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
*/
|
*/
|
||||||
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
|
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
|
||||||
{
|
{
|
||||||
|
$this->pgo = PgoManager::fromBuilder($this, $build_target);
|
||||||
|
|
||||||
$cflags = $this->arch_c_flags;
|
$cflags = $this->arch_c_flags;
|
||||||
f_putenv('CFLAGS=' . $cflags);
|
f_putenv('CFLAGS=' . $cflags);
|
||||||
|
|
||||||
@@ -134,7 +138,7 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
|
|
||||||
$this->cleanMake();
|
$this->cleanMake();
|
||||||
|
|
||||||
$pgo = PgoManager::active();
|
$pgo = $this->pgo;
|
||||||
$needsClean = false;
|
$needsClean = false;
|
||||||
$sapiBuilds = [
|
$sapiBuilds = [
|
||||||
['cli', $enableCli, true, fn () => $this->buildCli()],
|
['cli', $enableCli, true, fn () => $this->buildCli()],
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use SPC\store\SourcePatcher;
|
|||||||
use SPC\util\DependencyUtil;
|
use SPC\util\DependencyUtil;
|
||||||
use SPC\util\GlobalEnvManager;
|
use SPC\util\GlobalEnvManager;
|
||||||
use SPC\util\LicenseDumper;
|
use SPC\util\LicenseDumper;
|
||||||
use SPC\util\PgoManager;
|
|
||||||
use SPC\util\SPCTarget;
|
use SPC\util\SPCTarget;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
@@ -215,20 +214,6 @@ class BuildPHPCommand extends BuildCommand
|
|||||||
// clean old modules that may conflict with the new php build
|
// clean old modules that may conflict with the new php build
|
||||||
FileSystem::removeDir(BUILD_MODULES_PATH);
|
FileSystem::removeDir(BUILD_MODULES_PATH);
|
||||||
|
|
||||||
$pgi = (bool) $this->getOption('pgi');
|
|
||||||
$csPgi = (bool) $this->getOption('cs-pgi');
|
|
||||||
$pgo = (bool) $this->getOption('pgo');
|
|
||||||
if (((int) $pgi + (int) $csPgi + (int) $pgo) > 1) {
|
|
||||||
$this->output->writeln('<error>--pgi, --cs-pgi, and --pgo are mutually exclusive</error>');
|
|
||||||
return static::FAILURE;
|
|
||||||
}
|
|
||||||
if ($pgi) {
|
|
||||||
(new PgoManager())->setupInstrument($rule);
|
|
||||||
} elseif ($csPgi) {
|
|
||||||
(new PgoManager())->setupCsInstrument($rule);
|
|
||||||
} elseif ($pgo) {
|
|
||||||
(new PgoManager())->setupUse($rule);
|
|
||||||
}
|
|
||||||
$builder->buildPHP($rule);
|
$builder->buildPHP($rule);
|
||||||
$builder->testPHP($rule);
|
$builder->testPHP($rule);
|
||||||
|
|
||||||
|
|||||||
@@ -43,64 +43,29 @@ class PgoManager
|
|||||||
|
|
||||||
private string $mode;
|
private string $mode;
|
||||||
|
|
||||||
private static ?self $active = null;
|
private function __construct()
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
{
|
||||||
$this->profileRoot = BUILD_ROOT_PATH . '/pgo-data';
|
$this->profileRoot = BUILD_ROOT_PATH . '/pgo-data';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function active(): ?self
|
/** Build a PgoManager for the active --pgi/--cs-pgi/--pgo option, or null if none set. */
|
||||||
|
public static function fromBuilder(BuilderBase $builder, int $rule): ?self
|
||||||
{
|
{
|
||||||
return self::$active;
|
$modes = array_filter(['pgi', 'cs-pgi', 'pgo'], fn ($m) => (bool) $builder->getOption($m));
|
||||||
}
|
if (count($modes) > 1) {
|
||||||
|
throw new WrongUsageException('--pgi, --cs-pgi, and --pgo are mutually exclusive');
|
||||||
/** Setup --pgi: build with -fprofile-generate=<sapi-dir>. */
|
|
||||||
public function setupInstrument(int $rule): void
|
|
||||||
{
|
|
||||||
$this->validateRule($rule);
|
|
||||||
FileSystem::removeDir($this->profileRoot);
|
|
||||||
f_mkdir($this->profileRoot, recursive: true);
|
|
||||||
foreach ($this->trainableIn($rule) as $sapi) {
|
|
||||||
f_mkdir($this->rawDir($sapi), recursive: true);
|
|
||||||
}
|
}
|
||||||
$this->mode = self::MODE_INSTRUMENT;
|
$mode = array_values($modes)[0] ?? null;
|
||||||
self::$active = $this;
|
if ($mode === null) {
|
||||||
$this->applyShutdownPatches();
|
return null;
|
||||||
$this->applyForSapi($this->trainableIn($rule)[0]);
|
|
||||||
logger()->info('pgo --pgi: instrumented build, profraw will land under ' . $this->profileRoot . '/<sapi>/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Setup --cs-pgi: build with -fprofile-use=<sapi.profdata> -fcs-profile-generate=<cs-dir>. Requires existing .profdata. */
|
|
||||||
public function setupCsInstrument(int $rule): void
|
|
||||||
{
|
|
||||||
$this->validateRule($rule);
|
|
||||||
foreach ($this->trainableIn($rule) as $sapi) {
|
|
||||||
if (!is_file($this->profDataFile($sapi))) {
|
|
||||||
throw new WrongUsageException("--cs-pgi: missing {$sapi}.profdata; run --pgi + --pgo first");
|
|
||||||
}
|
|
||||||
f_mkdir($this->csRawDir($sapi), recursive: true);
|
|
||||||
}
|
}
|
||||||
$this->mode = self::MODE_CS_INSTRUMENT;
|
$instance = new self();
|
||||||
self::$active = $this;
|
match ($mode) {
|
||||||
$this->applyShutdownPatches();
|
'pgi' => $instance->setupInstrument($rule),
|
||||||
$this->applyForSapi($this->trainableIn($rule)[0]);
|
'cs-pgi' => $instance->setupCsInstrument($rule),
|
||||||
logger()->info('pgo --cs-pgi: cs-instrumented build, cs-profraw under ' . $this->profileRoot . '/cs-<sapi>/');
|
'pgo' => $instance->setupUse($rule),
|
||||||
}
|
};
|
||||||
|
return $instance;
|
||||||
/** Setup --pgo: merge collected .profraw, then build with -fprofile-use=<sapi.profdata>. */
|
|
||||||
public function setupUse(int $rule): void
|
|
||||||
{
|
|
||||||
$this->validateRule($rule);
|
|
||||||
if (trim((string) shell_exec('command -v llvm-profdata 2>/dev/null')) === '') {
|
|
||||||
throw new WrongUsageException('--pgo: llvm-profdata not on PATH');
|
|
||||||
}
|
|
||||||
foreach ($this->trainableIn($rule) as $sapi) {
|
|
||||||
$this->mergeSapi($sapi);
|
|
||||||
}
|
|
||||||
$this->mode = self::MODE_USE;
|
|
||||||
self::$active = $this;
|
|
||||||
$this->applyForSapi($this->trainableIn($rule)[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Patches php-src/libtool to passthrough -fcs-profile-* flags (otherwise dropped during shared lib link). */
|
/** Patches php-src/libtool to passthrough -fcs-profile-* flags (otherwise dropped during shared lib link). */
|
||||||
@@ -155,6 +120,51 @@ class PgoManager
|
|||||||
logger()->info("pgo {$this->mode} ({$sapi})");
|
logger()->info("pgo {$this->mode} ({$sapi})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Setup --pgi: build with -fprofile-generate=<sapi-dir>. */
|
||||||
|
private function setupInstrument(int $rule): void
|
||||||
|
{
|
||||||
|
$this->validateRule($rule);
|
||||||
|
FileSystem::removeDir($this->profileRoot);
|
||||||
|
f_mkdir($this->profileRoot, recursive: true);
|
||||||
|
foreach ($this->trainableIn($rule) as $sapi) {
|
||||||
|
f_mkdir($this->rawDir($sapi), recursive: true);
|
||||||
|
}
|
||||||
|
$this->mode = self::MODE_INSTRUMENT;
|
||||||
|
$this->applyShutdownPatches();
|
||||||
|
$this->applyForSapi($this->trainableIn($rule)[0]);
|
||||||
|
logger()->info('pgo --pgi: instrumented build, profraw will land under ' . $this->profileRoot . '/<sapi>/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Setup --cs-pgi: build with -fprofile-use=<sapi.profdata> -fcs-profile-generate=<cs-dir>. Requires existing .profdata. */
|
||||||
|
private function setupCsInstrument(int $rule): void
|
||||||
|
{
|
||||||
|
$this->validateRule($rule);
|
||||||
|
foreach ($this->trainableIn($rule) as $sapi) {
|
||||||
|
if (!is_file($this->profDataFile($sapi))) {
|
||||||
|
throw new WrongUsageException("--cs-pgi: missing {$sapi}.profdata; run --pgi + --pgo first");
|
||||||
|
}
|
||||||
|
f_mkdir($this->csRawDir($sapi), recursive: true);
|
||||||
|
}
|
||||||
|
$this->mode = self::MODE_CS_INSTRUMENT;
|
||||||
|
$this->applyShutdownPatches();
|
||||||
|
$this->applyForSapi($this->trainableIn($rule)[0]);
|
||||||
|
logger()->info('pgo --cs-pgi: cs-instrumented build, cs-profraw under ' . $this->profileRoot . '/cs-<sapi>/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Setup --pgo: merge collected .profraw, then build with -fprofile-use=<sapi.profdata>. */
|
||||||
|
private function setupUse(int $rule): void
|
||||||
|
{
|
||||||
|
$this->validateRule($rule);
|
||||||
|
if (trim((string) shell_exec('command -v llvm-profdata 2>/dev/null')) === '') {
|
||||||
|
throw new WrongUsageException('--pgo: llvm-profdata not on PATH');
|
||||||
|
}
|
||||||
|
foreach ($this->trainableIn($rule) as $sapi) {
|
||||||
|
$this->mergeSapi($sapi);
|
||||||
|
}
|
||||||
|
$this->mode = self::MODE_USE;
|
||||||
|
$this->applyForSapi($this->trainableIn($rule)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static-embed mode links libphp.a into frankenphp; both end up in one
|
* Static-embed mode links libphp.a into frankenphp; both end up in one
|
||||||
* binary so must share one profdata. Shared-embed mode keeps libphp.so
|
* binary so must share one profdata. Shared-embed mode keeps libphp.so
|
||||||
|
|||||||
Reference in New Issue
Block a user