Skip to content

Commit

Permalink
Add initial implementation of the memory profiler
Browse files Browse the repository at this point in the history
NO TESTS, BUT WORKS ON MY END!!!!
  • Loading branch information
sj-i committed Nov 12, 2023
1 parent 543934e commit f480d95
Show file tree
Hide file tree
Showing 165 changed files with 10,091 additions and 64 deletions.
150 changes: 150 additions & 0 deletions src/Command/Inspector/MemoryCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Command\Inspector;

use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettingsFromConsoleInput;
use Reli\Inspector\Settings\TargetProcessSettings\TargetProcessSettingsFromConsoleInput;
use Reli\Inspector\TargetProcess\TargetProcessResolver;
use Reli\Lib\PhpProcessReader\PhpGlobalsFinder;
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ContextAnalyzer\ContextAnalyzer;
use Reli\Lib\PhpProcessReader\PhpMemoryReader\LocationTypeAnalyzer\LocationTypeAnalyzer;
use Reli\Lib\PhpProcessReader\PhpMemoryReader\MemoryLocationsCollector;
use Reli\Lib\PhpProcessReader\PhpMemoryReader\ObjectClassAnalyzer\ObjectClassAnalyzer;
use Reli\Lib\PhpProcessReader\PhpMemoryReader\RegionAnalyzer\RegionAnalyzer;
use Reli\Lib\PhpProcessReader\PhpVersionDetector;
use Reli\Lib\Process\ProcessStopper\ProcessStopper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

use function Reli\Lib\Defer\defer;

final class MemoryCommand extends Command
{
public function __construct(
private PhpGlobalsFinder $php_globals_finder,
private TargetPhpSettingsFromConsoleInput $target_php_settings_from_console_input,
private TargetProcessSettingsFromConsoleInput $target_process_settings_from_console_input,
private TargetProcessResolver $target_process_resolver,
private PhpVersionDetector $php_version_detector,
private MemoryLocationsCollector $memory_locations_collector,
private ProcessStopper $process_stopper,
) {
parent::__construct();
}

public function configure(): void
{
$this->setName('inspector:memory')
->setDescription('[experimental] get memory usage from an outer process')
;
$this->addOption(
'stop-process',
null,
InputOption::VALUE_OPTIONAL,
'stop the process while inspecting',
true,
);
$this->target_process_settings_from_console_input->setOptions($this);
$this->target_php_settings_from_console_input->setOptions($this);
}

public function execute(InputInterface $input, OutputInterface $output): int
{
$target_php_settings = $this->target_php_settings_from_console_input->createSettings($input);
$target_process_settings = $this->target_process_settings_from_console_input->createSettings($input);

$process_specifier = $this->target_process_resolver->resolve($target_process_settings);

$target_php_settings_version_decided = $this->php_version_detector->decidePhpVersion(
$process_specifier,
$target_php_settings
);

if ($input->getOption('stop-process')) {
$this->process_stopper->stop($process_specifier->pid);
defer($scope_guard, fn () => $this->process_stopper->resume($process_specifier->pid));
}

$eg_address = $this->php_globals_finder->findExecutorGlobals($process_specifier, $target_php_settings);
$cg_address = $this->php_globals_finder->findCompilerGlobals($process_specifier, $target_php_settings);

$collected_memories = $this->memory_locations_collector->collectAll(
$process_specifier,
$target_php_settings_version_decided,
$eg_address,
$cg_address
);

$region_analyzer = new RegionAnalyzer(
$collected_memories->chunk_memory_locations,
$collected_memories->huge_memory_locations,
$collected_memories->vm_stack_memory_locations,
$collected_memories->compiler_arena_memory_locations,
);

$analyzed_regions = $region_analyzer->analyze(
$collected_memories->memory_locations,
);
$location_type_analyzer = new LocationTypeAnalyzer();
$heap_location_type_summary = $location_type_analyzer->analyze(
$analyzed_regions->regional_memory_locations->locations_in_zend_mm_heap,
);

$object_class_analyzer = new ObjectClassAnalyzer();
$object_class_summary = $object_class_analyzer->analyze(
$analyzed_regions->regional_memory_locations->locations_in_zend_mm_heap,
);

$summary = [
$analyzed_regions->summary->toArray()
+ [
'memory_get_usage' => $collected_memories->memory_get_usage_size,
'memory_get_real_usage' => $collected_memories->memory_get_usage_real_size,
'cached_chunks_size' => $collected_memories->cached_chunks_size,
]
+ [
'heap_memory_analyzed_percentage' =>
$analyzed_regions->summary->zend_mm_heap_usage
/
$collected_memories->memory_get_usage_size * 100
,
]
+ [
'php_version' => $target_php_settings->php_version,
]
];

$context_analyzer = new ContextAnalyzer();
$analyzed_context = $context_analyzer->analyze(
$collected_memories->top_reference_context,
);

echo json_encode(
[
'summary' => $summary,
"per_type_analysis" => $heap_location_type_summary->per_type_usage,
'per_class_analysis' => $object_class_summary->per_class_usage,
'context' => $analyzed_context,
],
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE,
2147483647
);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException(json_last_error_msg());
}
return 0;
}
}
7 changes: 5 additions & 2 deletions src/Lib/FFI/Cast.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@

class Cast
{
/** @param CPointer $cdata */
public static function castPointerToInt(CData &$cdata): int
/** @param CPointer|null $cdata */
public static function castPointerToInt(?CData &$cdata): int
{
if ($cdata === null) {
return 0;
}
/** @var CInteger $casted */
$casted = \FFI::cast('long', $cdata);
return $casted->cdata;
Expand Down
2 changes: 1 addition & 1 deletion src/Lib/PhpInternals/CastedCData.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

use FFI\CData;

/** @template T of CData */
/** @template-covariant T of CData */
final class CastedCData
{
/**
Expand Down
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV70.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV70 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = 0x40000000;
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV71.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV71 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = 0x40000000;
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV72.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV72 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = 0x40000000;
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV73.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV73 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = (1 << 30);
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV74.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV74 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = (1 << 13);
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV80.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV80 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = (1 << 13);
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV81.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV81 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = (1 << 13);
}
19 changes: 19 additions & 0 deletions src/Lib/PhpInternals/Constants/PhpInternalsConstantsV82.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

final class PhpInternalsConstantsV82 extends VersionAwareConstants
{
public const ZEND_ACC_HAS_RETURN_TYPE = (1 << 13);
}
37 changes: 37 additions & 0 deletions src/Lib/PhpInternals/Constants/VersionAwareConstants.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* This file is part of the reliforp/reli-prof package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Reli\Lib\PhpInternals\Constants;

use Reli\Lib\PhpInternals\ZendTypeReader;

abstract class VersionAwareConstants
{
/** @var int */
public const ZEND_ACC_HAS_RETURN_TYPE = (1 << 13);

/** @param value-of<ZendTypeReader::ALL_SUPPORTED_VERSIONS> $php_version */
public static function getConstantsOfVersion(string $php_version): self
{
return new (match ($php_version) {
ZendTypeReader::V70 => PhpInternalsConstantsV70::class,
ZendTypeReader::V71 => PhpInternalsConstantsV71::class,
ZendTypeReader::V72 => PhpInternalsConstantsV72::class,
ZendTypeReader::V73 => PhpInternalsConstantsV73::class,
ZendTypeReader::V74 => PhpInternalsConstantsV74::class,
ZendTypeReader::V80 => PhpInternalsConstantsV80::class,
ZendTypeReader::V81 => PhpInternalsConstantsV81::class,
ZendTypeReader::V82 => PhpInternalsConstantsV82::class,
});
}
}
Loading

0 comments on commit f480d95

Please sign in to comment.