File Coverage

lib/UR/Namespace/Command/Test/TrackObjectRelease.pm
Criterion Covered Total %
statement 12 51 23.5
branch 0 14 0.0
condition 0 3 0.0
subroutine 4 8 50.0
pod 0 3 0.0
total 16 79 20.2


line stmt bran cond sub pod time code
1             package UR::Namespace::Command::Test::TrackObjectRelease;
2              
3 1     1   23 use strict;
  1         1  
  1         27  
4 1     1   4 use warnings;
  1         1  
  1         24  
5              
6 1     1   4 use UR;
  1         2  
  1         6  
7             our $VERSION = "0.46"; # UR $VERSION;
8 1     1   4 use IO::File;
  1         2  
  1         574  
9              
10             class UR::Namespace::Command::Test::TrackObjectRelease {
11             is => 'UR::Namespace::Command::Base',
12             has => [
13             file => { is => 'Text', doc => 'pathname of the input file' },
14             ],
15             };
16              
17 0     0 0   sub help_brief { 'Parse the data produced by UR_DEBUG_OBJECT_RELEASE and report possible memory leaks' };
18              
19             sub help_synopsis {
20 0     0 0   "ur test track-object-release --file /path/to/text.file > /path/to/results"
21             }
22              
23             sub help_detail {
24 0     0 0   "When a UR-based program is run with the UR_DEBUG_OBJECT_RELEASE environment
25             variable set to 1, it will emit messages to STDERR describing the various
26             stages of releasing an object. This command parses those messages and
27             provides a report on objects which did not completely deallocate themselves,
28             usually because of a reference being held."
29             }
30              
31             sub execute {
32 0     0     my $self = shift;
33              
34             #$DB::single = 1;
35 0           my $file = $self->file;
36 0           my $fh = IO::File->new($file,'r');
37              
38 0 0         unless ($fh) {
39 0           $self->error_message("Can't open input file: $!");
40 0           return;
41             }
42              
43             # for a given state, it's legal predecessor
44 0           my %prev_states = ( 'PRUNE object' => '',
45             'DESTROY object' => 'PRUNE object',
46             'UNLOAD object' => 'DESTROY object',
47             'DELETE object' => 'UNLOAD object',
48             'BURY object' => 'DELETE object',
49             'DESTROY deletedref' => 'BURY object',
50             );
51 0           my %next_states = reverse %prev_states;
52             # After this we stop stracking it
53 0           my %terminal_states = ( 'DESTROY deletedref' => 1 );
54 0           my %objects;
55              
56              
57 0           while(<$fh>) {
58 0           chomp;
59              
60 0           my ($action,$refaddr);
61 0 0         if (m/MEM ((PRUNE|DESTROY|UNLOAD|DELETE|BURY) (object|deletedref)) (\S+)/) {
62 0           $action = $1;
63 0           my $refstr = $4;
64 0           ($refaddr) = ($refstr =~ m/=HASH\((.*)\)/);
65             } else {
66 0           next;
67             }
68 0           my($class,$id) = m/class (\S+) id (.*)/; # These don't appear in the deletedref line, and are optional
69              
70 0           my $expected_prev_state = $prev_states{$action};
71 0 0 0       if (defined $expected_prev_state && $expected_prev_state) {
    0          
72             # This state must have a predecessor
73 0 0         if ($objects{$expected_prev_state}->{$refaddr}) {
74 0 0         if ($terminal_states{$action}) {
75 0           delete $objects{$expected_prev_state}->{$refaddr};
76             } else {
77 0           $objects{$action}->{$refaddr} = delete $objects{$expected_prev_state}->{$refaddr};
78             }
79             } else {
80 0           print STDERR "$action for $refaddr without matching $expected_prev_state at line $.\n";
81             }
82              
83             } elsif (defined $expected_prev_state) {
84             # The initial state
85 0           $objects{$action}->{$refaddr} = $_;
86              
87             } else {
88 0           print STDERR "Unknown action $action at line $.\n";
89             }
90             }
91              
92 0           foreach my $action (keys %objects) {
93 0 0         if (keys %{$objects{$action}} ) {
  0            
94 0           print "\n$action but not $next_states{$action}\n";
95 0           foreach (keys %{$objects{$action}}) {
  0            
96 0           print "$_ : ",$objects{$action}->{$_},"\n";
97             }
98             }
99             }
100              
101 0           return 1;
102             }
103              
104             1;
105              
106