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

Dear Monks,
When we build Java applets, there are commonly available tools to strip out code that will not execute and so reduce the size of the bytecode.

Is there anything you know of that can do this for Perl? For a specific .pl file it would traverse the heirarchy of inherited PMs and produce a PL file with local subroutines copied in. The larger body of code not used in the .pm files would not be there.
I am aware that one can request only specific functions via inheritance. Our enquiry is about producing stand-alone PL files.
I know this proposed tool might prevent ///e, symbolic referencing, eval, XS, etc etc.
I actually suspect there might be something in B:: that might do what I am after. The deparser?!

Any advice you have would be gratefully grokked. Cheers,
bobajobRob

Replies are listed 'Best First'.
Re: Optimise Perl code pl file
by Roger (Parson) on Nov 28, 2003 at 03:38 UTC
    Not a simple task. You can have a look at the B family of modules ...

  • B::Concise (walk Perl syntax tree, printing concise info about ops)
  • B::Deparse (produce perl code)
  • B::Generate (generate your own op trees)

    Personally I think the idea is a bit 'crazy'. However I believe it is possible to produce some sort of dead-code elimination algorithm. The following is just my idea on how this might be done.

    +-------------------------+ | generate perl-byte code | | of the entire project | +------------+------------+ | +------------+------------+ | walk the op-tree and | | identify unused opcodes | +------------+------------+ | +---------------------+ | construct your own | | op-tree without the | | unused op-codes | +---------------------+
      That's pointless. When perl optimizes away an opnode, it just stops pointing to it. Null nodes have no runtime impact since they are never seen by the interpreter. They still consume a bit of memory and are still present but you only ever see them when you dump the optree.
Re: Optimise Perl code pl file
by simonm (Vicar) on Nov 28, 2003 at 07:25 UTC
    For a specific .pl file it would traverse the heirarchy of inherited PMs and produce a PL file with local subroutines copied in. The larger body of code not used in the .pm files would not be there.

    I don't know of anything off-hand that would strip out the unused functions for you.

    There are a couple of packages around that will merge all of your modules into a single file, including my Devel::PreProcessor. (You can also use it to strip out comment lines and POD sections.)

    You can use Devel::Cover to list which of your subroutines are called and which are not, although this depends on you having test scripts or manually running the program several times to exercise all of the possible code paths.

    It would be up to you to combine these two capabilities and strip out the unused functions.

      Is Devel::PreProcessor used when compiling Perl to bytecode? I was considering doing that in the future to enable people without Perl to install my scripts, and to obfuscate it, but the following was among the limitations listed for Devel::PreProcessor
      While some pragmas are known to work, including use vars, problems may pop up with others. In particular, use strict and no strict pragmas are removed from the resulting source, because their scoping changes in a single-file context, usually with fatal results.
      That sounds like a major limitation to me.
        Is Devel::PreProcessor used when compiling Perl to bytecode?

        Nope, it's just source-code manipulation; it produces a single file that contains the source of your script and the modules it uses.

        ...the following was among the limitations listed for Devel::PreProcessor: ... use strict and no strict pragmas are removed ...

        Assuming your code already compiles under use strict, there's not much of an impact if you then remove that pragma.

        However, in hindsight the solution to this wasn't very difficult to implement, so I've made this change and released a new version of Devel::PreProcessor to CPAN; it should show up on your local mirror within a day or so.

Re: Optimise Perl code pl file
by schweini (Friar) on Nov 28, 2003 at 12:27 UTC
    maybe i need more coffee, but isn't this roughly what AutoSplit and AutoLoad(?) do? they wont remove unused code, but will at least make perl not 'compile' it unless it is needed, IIRC...
      Thank you Monks, I wish I could contribute back some expertise, but perhaps from the nature of my post my solutions to problems might perhaps be pretty out there.

      Given our project, the scripts we want to create have pretty basic execution paths and so it is feasible to execute them to "touch" the nodes that we want to keep in the tree. I'll have a burl at the Monk suggestion to this effect above.

      I think the solution posted above this was a suggestion to use AUTOLOAD to boot only the code we want. My proposition is to produce a Perl text file which has been derived from a very large collection of shared libraries. Maybe I can use AUTOLOAD to read only the code we want, then use Deparse to "export" it. This would then give us only the code we want. Is this the implication?

      We are doing this because the OOP heirarchy we use is really vast and we want to spit out Perl files which should be very short and hopefully fairly boring and readable. At the moment they are pretty elaborate.

      As a side note, I have seen Deparse used to help de-obfuscate code. We also think this might be a good exercise as we can then audit the little scripts which are the end-point of our Perl script-writing package.

      Best,
      bobajobRob
        Deparse is not perfect and it tends to develop new bugs with new perl releases (because the structure of the optree gets changed without always remembering Deparse). It also has large areas such as closures where it just won't easily work. It also will strip all comments and pod (including copyright statements or licensing terms, which may be a legal issue).

        Update: if it is any comfort, when Deparse breaks it usually breaks badly enough to get noticed and fixed before a perl release. And it probably is your best bet for accomplishing the job (with the possible exception of figuring out some way to use AutoSplit.)

Re: Optimise Perl code pl file
by BUU (Prior) on Nov 28, 2003 at 02:57 UTC
    Uh.. why?
      "Auditability"...
      I have gone on to discover how to do some of this with B::Deparse, but have hit another wall. The -u flag to Deparse does not seem to want to deal with packages. Do I need to give full paths or similar? It seems to ignore all our -u flags and just manage the .pl file.
      Thanks again
      bobajobRob
        Having spent some time with B::Deparse, it gets nicer with each perl revision. I seem to recall thinking that the -u flag was much nicer (or was it not needed?) with some of the later B::Deparse's from 5.8.1 and later. You could of course just subclass B::Deparse and add on any functionality you wish.