Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
515 views
in Technique[技术] by (71.8m points)

fork - php xdebug: How to profile forked process

I am running a PHP daemon to be profiled.

The started php process loads all required data, forks itself to distribute workload over all cores, waits for the forked children to finish, and collects the results generated by the children.

Since I am sharing CLI environment with other users, I need to start xdebug profiling by injecting php.ini values into the shell call.

 $ php -d xdebug.profiler_enable=1 -d xdebug.profiler_output_dir="/home/xxx" daemon.php

The generated cachegrind-file, how ever, profiles the parent and hence shows 90% sleep.

Is there a way to profile the workers without building a driver to load them directly?

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I ran into the same issue and solved without XDebug. Unfortunately I couldn't find a way with XDebug. It's like somehow it does not care about any forked process.

I solved by using Xhprof to profile and Xhgui to inspect the logs. Xhprof is a great tool internally developed by Facebook and then released afterwards open-source. The cool thing is that you can decide exactly when to start profiling and when to stop. This gives you the ability to work around our issue.

So first of all let's get it installed!

sudo pecl install xhprof-beta

If you're using a debian based distro make sure you got also graphviz installed.

sudo apt-get install graphviz

Now let's take a look at the code.

$children = [];

do {
    if (count($children) < $maxConsumers) {
        $pid = pcntl_fork();
        $children[] = $pid;

        if ($pid == -1) {
            throw new RuntimeException('Could not fork process');
        } else if ($pid === 0) {
            // we are the child

            if ($verbose) {
                $output->writeln(sprintf('Child here (PID = %s)', posix_getpid()));
            }

            if ($xhProf) {
                // here we enable xhprof thus the profiling starts
                xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
            }

            // DO YOUR MAGIC HERE!

            if ($xhProf) {
                // and here we call the xhgui header file that will
                // stop xhprof and write all the gathered data into
                // mongo or into a dedicated file
                require_once('/var/www/xhgui/external/header.php');
            }

            exit;
        } else {
            // we are the parent
            if ($verbose) {
                $output->writeln(sprintf('Parent here (PID = %s) spawned a new child (PID = %s)', posix_getpid(), $pid));
            }
        }
    } else {
        if ($verbose) {
            $output->writeln(sprintf("Parent - spawned enough children, let's wait them..."));
        }

        $deadPID = pcntl_wait($status);
        $children = array_diff($children, [$deadPID]);
} while (true);

// Waits for all remaining children
while (($pid = pcntl_waitpid(0, $status)) != -1) {
    if ($verbose) {
        $status = pcntl_wexitstatus($status);
        $output->writeln(sprintf("Child (PID %d) terminated. Status is %s.", $pid, $status));
    }
}

In order to inspect your logs you also need to configure Xhgui properly. You'll probably need a virtual host as well.

For all the needed configuration and for reference:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...