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. 4
      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");

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

@ -4,6 +4,7 @@ namespace PhpAot\Php;
use PhpParser\Node\Expr; use PhpParser\Node\Expr;
use PhpParser\NodeAbstract; use PhpParser\NodeAbstract;
use PhpParser\Node;
trait AstNodeType trait AstNodeType
{ {
@ -12,6 +13,11 @@ trait AstNodeType
return $expr instanceof Expr\Variable; return $expr instanceof Expr\Variable;
} }
protected function isIdExpr(NodeAbstract $expr): bool
{
return $expr instanceof Node\Identifier;
}
protected function isPropertyFetch(NodeAbstract $expr): bool protected function isPropertyFetch(NodeAbstract $expr): bool
{ {
return $expr instanceof Expr\PropertyFetch; 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_NAN = 'std::numeric_limits<double>::quiet_NaN()';
public const string VALUE_INF = 'std::numeric_limits<double>::infinity()'; public const string VALUE_INF = 'std::numeric_limits<double>::infinity()';
public const string LITERAL_STRINGS = '_literal_strings'; 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_VARIABLE = 'Expr_Variable';
public const string EXPR_NEW = 'Expr_New'; public const string EXPR_NEW = 'Expr_New';
public const string EXPR_ARRAY_DIM_FETCH = 'Expr_ArrayDimFetch'; 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 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) { if ($ns) {
$names[] = $this->escapeNamespace($ns); $names[] = $this->escapeNamespace($ns);
} }
@ -1371,7 +1377,7 @@ class CompilerBase extends \PhpAot\Core\Translator
*/ */
protected function findNativeFunction(string $fname): string|false protected function findNativeFunction(string $fname): string|false
{ {
$possibleFunctionNames = [$this->escapeFunction($fname),]; $possibleFunctionNames = [$this->escapeName($fname),];
if ($this->namespace) { if ($this->namespace) {
$possibleFunctionNames[] = $this->escapeNamespace($this->namespace) . self::NAMESPACE_SEPARATOR . $fname; $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)); 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 protected function escapeClass(string $class): string
@ -2015,7 +2021,15 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parsePropertyFetch(Node\Expr\PropertyFetch $expr): string 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 protected function parseAssignOpShiftRight(Node $node): string
@ -2371,7 +2385,7 @@ class CompilerBase extends \PhpAot\Core\Translator
{ {
$object = $this->convertToObject($expr->var); $object = $this->convertToObject($expr->var);
$method = $this->parseIdentifier($expr->name); $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)) { if ($this->isNativeMethod($object, $nativeFunc)) {
return $this->parseNativeMethodCall($object, $nativeFunc, $expr->args); return $this->parseNativeMethodCall($object, $nativeFunc, $expr->args);
} }

@ -283,6 +283,13 @@ class Translator extends Preprocessor
$lines[] = 'extern ' . self::TYPE_VAR . ' ' . $name . ';'; $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); $literalStringsCount = count($this->literalStrings);
$lines[] = 'extern php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; $lines[] = 'extern php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
$code = implode(PHP_EOL, $lines) . PHP_EOL . 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 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 protected function parseNamespace(Node\Stmt\Namespace_ $node): string
@ -576,6 +583,8 @@ class Translator extends Preprocessor
foreach ($classDef->methods as $method) { foreach ($classDef->methods as $method) {
$code .= $methodCodes[$method->name] . PHP_EOL; $code .= $methodCodes[$method->name] . PHP_EOL;
} }
$code .= PHP_EOL;
return $code; return $code;
} }

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

@ -43,6 +43,17 @@ foreach ($this->nativeConstants as $name => $constant):
<?=$constant->type?> <?=$name?>; <?=$constant->type?> <?=$name?>;
<?php endforeach; ?> <?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) { static ZEND_FUNCTION(main) {
php_main(); php_main();
} }
@ -82,6 +93,17 @@ foreach ($this->globalVars as $name => $type):
?> ?>
<?= $name ?> = php::global("<?=$name?>"); <?= $name ?> = php::global("<?=$name?>");
<?php endforeach; ?> <?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() { void php_app_clean() {

Loading…
Cancel
Save