38061793340c8dba3e6ea44044c46d86c3462d7c
[p5sagit/Devel-Size.git] / static / MemView.pl
1 #!/usr/bin/env perl
2
3 use strict;
4 use warnings;
5
6 use JSON::XS;
7 use Mojolicious::Lite;
8 use Getopt::Long;
9 use Storable qw(dclone);
10
11 GetOptions(
12     'db=s' => \(my $opt_db = '../memnodes.db'),
13     'debug!' => \my $opt_debug,
14 ) or exit 1;
15
16 #warn "Reading from $opt_db\n";
17
18 use ORLite {
19     file => '../memnodes.db',
20     package => "MemView",
21     #user_version => 1,
22     readonly => 1,
23     #unicode => 1,
24 };
25
26 my $j = JSON::XS->new;
27
28 # Documentation browser under "/perldoc"
29 plugin 'PODRenderer';
30
31 get '/' => sub {
32     my $self = shift;
33     $self->render('index');
34 };
35
36 get '/jit_tree/:id/:depth' => sub {
37     my $self = shift;
38     my $logarea = $self->param('logarea');
39
40     my $id = $self->stash('id');
41     my $depth = $self->stash('depth');
42     warn "jit_tree $id $depth";
43     my $node_tree = _fetch_node_tree($id, $depth);
44     my $jit_tree = _transform_node_tree($node_tree, sub {
45         my ($node) = @_;
46         my $children = delete $node->{children}; # XXX edits the src tree
47         my $area = $node->{self_size}+$node->{kids_size};
48         $node->{'$area'} = ($logarea) ? log($area) : $area; # XXX move to jit js
49         my $jit_node = {
50             id   => $node->{id},
51             name => $node->{title} || $node->{name},
52             data => $node,
53         };
54         $jit_node->{children} = $children if $children;
55         return $jit_node;
56     });
57 if(1){
58     use Devel::Dwarn;
59     use Data::Dump qw(pp);
60     local $jit_tree->{children};
61     pp(dclone($jit_tree)); # dclone to avoid stringification
62 }
63     $self->render_json($jit_tree);
64 };
65
66 sub _fetch_node_tree {
67     my ($id, $depth) = @_;
68     my $node = MemView->selectrow_hashref("select * from node where id = ?", undef, $id)
69         or die "Node '$id' not found";
70     $node->{$_} += 0 for (qw(child_count kids_node_count kids_size self_size));
71     $node->{leaves} = $j->decode(delete $node->{leaves_json});
72     $node->{attr}   = $j->decode(delete $node->{attr_json});
73
74     if ($node->{child_ids}) {
75         my @child_ids = split /,/, $node->{child_ids};
76         my $children;
77         if (@child_ids == 1 && $node->{type} == 2) {
78             my $child = _fetch_node_tree($child_ids[0], $depth); # same depth
79             # merge node into child
80             # XXX id, depth, parent_id
81             warn "Merged $node->{name} #$node->{id} with only child $child->{name} #$child->{id}\n"
82                 if $opt_debug;
83             $child->{name} = "$node->{name} + $child->{name}";
84             $child->{$_} += $node->{$_} for (qw(self_size));
85             $child->{$_}  = $node->{$_} for (qw(parent_id));
86
87             $child->{title} = join " + ", grep { defined && length } $child->{title}, $node->{title};
88             #warn "Titled $child->{title}" if $child->{title};
89
90             for my $attr_type (keys %{ $node->{attr} }) {
91                 my $src = $node->{attr}{$attr_type};
92                 if (ref $src eq 'HASH') { # eg NPattr_NAME: {attr}{1}{$name} = $value
93                     my $dst = $child->{attr}{$attr_type} ||= {};
94                     for my $k (keys %$src) {
95                         warn "Node $child->{id} attr $attr_type:$k=$dst->{$k} overwritten by $src->{$k}\n"
96                             if defined $dst->{$k};
97                         $dst->{$k} = $src->{$k};
98                     }
99                 }
100                 else { # ARRAY eg NPattr_PADNAME: {attr}{2}[$val] = $name
101                     my $dst = $child->{attr}{$attr_type} ||= [];
102                     my $idx = @$src;
103                     while (--$idx >= 0) {
104                         warn "Node $child->{id} attr $attr_type:$idx=$dst->[$idx] overwritten by $src->[$idx]\n"
105                             if defined $dst->[$idx];
106                         $dst->[$idx] = $src->[$idx];
107                     }
108                 }
109             }
110
111             $child->{leaves}{$_} += $node->{leaves}{$_}
112                 for keys %{ $node->{leaves} };
113
114             $child->{_ids_merged} .= ",$node->{id}";
115             my @child_ids = split /,/, $node->{child_ids};
116             $child->{child_count} = @child_ids;
117
118             $node = $child;
119         }
120         elsif ($depth) {
121             $children = [ map { _fetch_node_tree($_, $depth-1) } @child_ids ];
122             $node->{children} = $children;
123             $node->{child_count} = @$children;
124         }
125     }
126     return $node;
127 }
128
129 sub _transform_node_tree {  # recurse depth first
130     my ($node, $transform) = @_;
131     if (my $children = $node->{children}) {
132         $_ = _transform_node_tree($_, $transform) for @$children;
133     }
134     return $transform->($node);
135 }
136
137
138 app->start;
139 __DATA__
140 @@ index.html.ep
141 % layout 'default';
142 % title 'Welcome';
143 Welcome to the Mojolicious real-time web framework!
144
145 @@ layouts/default.html.ep
146 <!DOCTYPE html>
147 <head>
148 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
149 <title>Perl Memory Treemap</title>
150
151 <!-- CSS Files -->
152 <link type="text/css" href="css/base.css" rel="stylesheet" />
153 <link type="text/css" href="css/Treemap.css" rel="stylesheet" />
154
155 <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
156
157 <!-- JIT Library File -->
158 <script language="javascript" type="text/javascript" src="jit.js"></script>
159 <script language="javascript" type="text/javascript" src="jquery-1.2.6-min.js"></script>
160
161 <!-- Example File -->
162 <script language="javascript" type="text/javascript" src="sprintf.js"></script>
163 <script language="javascript" type="text/javascript" src="tm.js"></script>
164 </head>
165
166 <body onload="init();">
167 <div id="container">
168
169 <div id="left-container">
170
171 <div class="text">
172 <h4>
173 Perl Memory TreeMap
174 </h4> 
175     Clicking on a node will show a new TreeMap with the contents of that node.<br /><br />            
176 </div>
177
178 <a id="back" href="#" class="theme button white">Go to Parent</a>
179
180 <br />
181 <form name=params>
182 <label for="logarea">&nbsp;Logarithmic scale
183 <input type=checkbox id="logarea" name="logarea">
184 </form>
185
186 </div>
187
188 <div id="center-container">
189     <div id="infovis"></div>    
190 </div>
191
192 <div id="right-container">
193
194 <div id="inner-details"></div>
195
196 </div>
197
198 <div id="log"></div>
199 </div>
200 </body>
201 </html>