feat(php): 添加属性偏移量支持和性能优化

- 引入 Node 类型导入并添加 isIdExpr 方法用于标识符检查
- 新增 PROPERTY_OFFSETS 常量和 getPropertyOffset 方法用于属性偏移量计算
- 重构命名空间相关方法,统一使用 getNativeName 替代 getNativeFunctionName
- 优化属性获取逻辑,在特定条件下使用属性偏移量提升性能
- 在模板中生成属性偏移量声明和初始化代码
- 添加性能测试脚本 prof.php 和性能分析配置调整
pull/1/head
韩天峰 7 months ago
parent 91a607185e
commit 0f3ccb98cd
  1. 8
      bin/prof.php
  2. 2
      examples/EightQueue.php
  3. 6
      src/Php/AstNodeType.php
  4. 30
      src/Php/CompilerBase.php
  5. 11
      src/Php/Translator.php
  6. 2
      src/cpp/main.cc
  7. 22
      src/template/extension.cc.php

@ -0,0 +1,8 @@
#!/usr/bin/env php
<?php
if (count($argv) < 2) {
echo "Usage: $argv[0] elf\n";
exit(1);
}
$elf = $argv[1];
shell_exec("pprof --pdf $elf profile.out > profile.pdf");

@ -114,10 +114,12 @@ function main()
}
// 测试不同规模
$begin = microtime(true);
echo "\n=== 不同规模的皇后问题 ===\n";
for ($n = 4; $n <= 10; $n++) {
$q = new EightQueensOptimized($n);
$count = $q->countSolutions();
echo "{$n} 皇后问题有 {$count} 个解\n";
}
echo "耗时: " . (microtime(true) - $begin) . " 秒\n";
}

@ -4,6 +4,7 @@ namespace PhpAot\Php;
use PhpParser\Node\Expr;
use PhpParser\NodeAbstract;
use PhpParser\Node;
trait AstNodeType
{
@ -12,6 +13,11 @@ trait AstNodeType
return $expr instanceof Expr\Variable;
}
protected function isIdExpr(NodeAbstract $expr): bool
{
return $expr instanceof Node\Identifier;
}
protected function isPropertyFetch(NodeAbstract $expr): bool
{
return $expr instanceof Expr\PropertyFetch;

@ -39,6 +39,7 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string VALUE_NAN = 'std::numeric_limits<double>::quiet_NaN()';
public const string VALUE_INF = 'std::numeric_limits<double>::infinity()';
public const string LITERAL_STRINGS = '_literal_strings';
public const string PROPERTY_OFFSETS = '_property_offsets';
public const string EXPR_VARIABLE = 'Expr_Variable';
public const string EXPR_NEW = 'Expr_New';
public const string EXPR_ARRAY_DIM_FETCH = 'Expr_ArrayDimFetch';
@ -235,12 +236,17 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function getFunctionName(FunctionLike $v): string
{
return $this->getNativeFunctionName($this->parseIdentifier($v->name), $this->namespace, $this->class);
return $this->getNativeName($this->parseIdentifier($v->name), $this->namespace, $this->class);
}
protected function getNativeFunctionName(string $fn, string $ns = '', string $class = ''): string
protected function getPropertyOffset(string $property, string $class, string $namespace = ''): string
{
$names[] = $this->escapeFunction($fn);
return $this->getNativeName('property_offset_' . $property, $namespace, $class);
}
protected function getNativeName(string $fn, string $ns = '', string $class = ''): string
{
$names[] = $this->escapeName($fn);
if ($ns) {
$names[] = $this->escapeNamespace($ns);
}
@ -1371,7 +1377,7 @@ class CompilerBase extends \PhpAot\Core\Translator
*/
protected function findNativeFunction(string $fname): string|false
{
$possibleFunctionNames = [$this->escapeFunction($fname),];
$possibleFunctionNames = [$this->escapeName($fname),];
if ($this->namespace) {
$possibleFunctionNames[] = $this->escapeNamespace($this->namespace) . self::NAMESPACE_SEPARATOR . $fname;
}
@ -1918,9 +1924,9 @@ class CompilerBase extends \PhpAot\Core\Translator
return str_replace('\\', self::NAMESPACE_SEPARATOR, strtolower($ns));
}
protected function escapeFunction(string $fname): string
protected function escapeName(string $name): string
{
return strtolower($fname);
return strtolower($name);
}
protected function escapeClass(string $class): string
@ -2015,7 +2021,15 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parsePropertyFetch(Node\Expr\PropertyFetch $expr): string
{
return $this->convertToObject($expr->var) . '.getPropertyIndirect("' . $this->parseIdentifier($expr->name) . '")';
$object = $expr->var;
$property = $expr->name;
$id = $this->identifierToStr($property);
if ($this->isVarExpr($object) and $this->isIdExpr($property)) {
if ($this->parseIdentifier($object) === 'this_') {
$id = self::PREFIX . $this->getPropertyOffset($property, $this->class, $this->namespace);
}
}
return $this->convertToObject($object) . '.getPropertyIndirect(' . $id . ')';
}
protected function parseAssignOpShiftRight(Node $node): string
@ -2371,7 +2385,7 @@ class CompilerBase extends \PhpAot\Core\Translator
{
$object = $this->convertToObject($expr->var);
$method = $this->parseIdentifier($expr->name);
$nativeFunc = $this->getNativeFunctionName($method, $this->namespace, $this->class);
$nativeFunc = $this->getNativeName($method, $this->namespace, $this->class);
if ($this->isNativeMethod($object, $nativeFunc)) {
return $this->parseNativeMethodCall($object, $nativeFunc, $expr->args);
}

@ -283,6 +283,13 @@ class Translator extends Preprocessor
$lines[] = 'extern ' . self::TYPE_VAR . ' ' . $name . ';';
}
// property offset
foreach ($this->classes as $classDef) {
foreach ($classDef->properties as $propertyDef) {
$lines[] = 'extern uint32_t ' . self::PREFIX . $this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace) . ';';
}
}
$literalStringsCount = count($this->literalStrings);
$lines[] = 'extern php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
$code = implode(PHP_EOL, $lines) . PHP_EOL . PHP_EOL;
@ -446,7 +453,7 @@ class Translator extends Preprocessor
protected function getNativeMethodName(ClassDef $classDef, MethodDef $methodDef): string
{
return $this->getNativeFunctionName($methodDef->name, $classDef->namespace, $classDef->name);
return $this->getNativeName($methodDef->name, $classDef->namespace, $classDef->name);
}
protected function parseNamespace(Node\Stmt\Namespace_ $node): string
@ -576,6 +583,8 @@ class Translator extends Preprocessor
foreach ($classDef->methods as $method) {
$code .= $methodCodes[$method->name] . PHP_EOL;
}
$code .= PHP_EOL;
return $code;
}

@ -29,7 +29,7 @@ int main(int cpp_argc, char **cpp_argv) {
int rc = 0;
#if PPROF_ON
ProfilerStart("myapp.prof");
ProfilerStart("profile.out");
#endif
zend_first_try {
php_app_init();

@ -43,6 +43,17 @@ foreach ($this->nativeConstants as $name => $constant):
<?=$constant->type?> <?=$name?>;
<?php endforeach; ?>
// property offset
<?php
foreach ($this->classes as $classDef):
foreach ($classDef->properties as $propertyDef):
?>
uint32_t <?=Translator::PREFIX . $this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace)?>;
<?php
endforeach;
endforeach;
?>
static ZEND_FUNCTION(main) {
php_main();
}
@ -82,6 +93,17 @@ foreach ($this->globalVars as $name => $type):
?>
<?= $name ?> = php::global("<?=$name?>");
<?php endforeach; ?>
// property offset
<?php
foreach ($this->classes as $classDef):
foreach ($classDef->properties as $propertyDef):
?>
<?=Translator::PREFIX . $this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace)?> = php::getPropertyOffset("<?=$classDef->getNamespacedName()?>", "<?=$propertyDef->name?>");
<?php
endforeach;
endforeach;
?>
}
void php_app_clean() {

Loading…
Cancel
Save