http://qs321.pair.com?node_id=11114068

cavac has asked for the wisdom of the Perl Monks concerning the following question:

I have an application that uses literally hundreds of modules (plus in turn their dependencies). And it's a forking application, specifically a webserver.

My problem is that sometimes a child will hang with 100% CPU usage during the DESTROY call. What would be the best way to debug this?

Print statements? Setting hundreds of debug points?

Is there any good way to overload DESTROY without loosing the original functions? EDIT: To clarify, automatically adding a print "starting DESTROY in $filename"/"Ending destroy in $filename" to every DESTROY function would help quite a lot.

perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'

Replies are listed 'Best First'.
Re: Debugging DESTROY calls in forking application
by LanX (Saint) on Mar 10, 2020 at 11:25 UTC
    Perl is so dynamic, there are a variety of options coming to mind, which depend on details only you know.

    If you are using the debugger you could trace function calls or add watch expressions.

    See perldebguts perldebug

    Or you use the INIT° phase of your main application to dive into every namespace to monkey patch the sub DESTROY with a wrapper.

    See perlmod

    Or ...

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    °) but I'd try the END phase first, if it's not too late. Like this the overhead is reduced.

      Through the power of a very aggressive code-edit script i managed to inject enough print statements i found a couple of spots in my application that would, under certain (not clearly known) circumstances, throw errors during DESTROY.

      Basically, perl would DESTROY a IO::Socket::* instance, then call DESTROY on the instance that was using that socket and would try to cleanly close the connection. This would fail and raise an exception (not eval'ed) during DESTROY which would utterly confuse Perl 5.30.1 and/or the still-alive parts of my application (don't know which yet) which would result in an infinite loop.

      I fixed that by enclosing those function calls in eval(). At least i hope that fixed it permanenty.

      Unfortunately, one of those was in my Net::Clacks client, so everyone gets to enjoy adding another item to upgrade on their already too long list...

      perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'
        Well that's solution for your underlying problem, but not the OP. ;)

        The interested reader might want to know that Perl has also tracers in the Devel namespace.

        perlrun

        • dt:MOD=[bar,baz]
          runs the program under the control of a debugging, profiling, or tracing module installed as Devel::MOD. E.g., -d:DProf executes the program using the Devel::DProf profiler. As with the -M flag, options may be passed to the Devel::MOD package where they will be received and interpreted by the Devel::MOD::import routine. Again, like -M, use --d:-MOD to call Devel::MOD::unimport instead of import. The comma- separated list of options must follow a = character. If t is specified, it indicates to the debugger that threads will be used in the code being debugged. See perldebug

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Re: Debugging DESTROY calls in forking application
by haukex (Archbishop) on Mar 10, 2020 at 15:28 UTC
Re: Debugging DESTROY calls in forking application
by bliako (Monsignor) on Mar 11, 2020 at 12:56 UTC

    If you are sharing data between threads perhaps there is a deadlock during DESTROY? that is, both a child and a parent try to destroy the same thing but each one thinks that the other is still using it? btw, if you use threads then those print statements will not be synchronised?

      It's a webserver backend. It doesn't call back to the main process. And it's forking, not threading.

      perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'

        Oh sorry, I missed the fork vs thread. So no shared data.

A reply falls below the community's threshold of quality. You may see it by logging in.