File Coverage

blib/lib/HPC/Runner/Command/stats.pm
Criterion Covered Total %
statement 12 105 11.4
branch 0 22 0.0
condition 0 8 0.0
subroutine 4 15 26.6
pod 0 11 0.0
total 16 161 9.9


line stmt bran cond sub pod time code
1             package HPC::Runner::Command::stats;
2              
3 1     1   1254 use MooseX::App::Command;
  1         1  
  1         11  
4 1     1   8085 use Log::Log4perl qw(:easy);
  1         3  
  1         11  
5 1     1   503 use JSON;
  1         1  
  1         36  
6 1     1   171 use Text::ASCIITable;
  1         2  
  1         1016  
7              
8             with 'HPC::Runner::Command::Plugin::Logger::Sqlite';
9              
10             command_short_description 'Get an overview of your submission.';
11             command_long_description 'Query the sqlite database for a submission overview.';
12              
13             #TODO project and jobname are already defined as options in execute_array
14              
15             option 'project' => (
16             is => 'rw',
17             isa => 'Str',
18             documentation => 'Query by project',
19             required => 0,
20             predicate => 'has_project',
21             );
22              
23             option 'jobname' => (
24             is => 'rw',
25             isa => 'Str',
26             documentation => 'Query by jobname',
27             required => 0,
28             predicate => 'has_jobname',
29             );
30              
31             option 'summary' => (
32             is => 'rw',
33             isa => 'Bool',
34             documentation =>
35             'Summary view of your jobs - Number of running, completed, failed, successful.',
36             required => 0,
37             default => 1,
38             );
39              
40             option 'long' => (
41             is => 'rw',
42             isa => 'Bool',
43             documentation =>
44             'Long view. More detailed report - Task tags, exit codes, duration, etc.',
45             required => 0,
46             default => 0,
47             trigger => sub {
48             my $self = shift;
49             $self->summary(0) if $self->long;
50             },
51             cmd_aliases => ['l'],
52             );
53              
54             has 'task_data' => (
55             is => 'rw',
56             isa => 'HashRef',
57             default => sub { {} },
58             clearer => 'clear_task_data',
59             );
60              
61             sub execute {
62 0     0 0   my $self = shift;
63              
64 0 0         if ( $self->summary ) {
65 0           $self->summary_view;
66             }
67             else {
68 0           $self->long_view;
69             }
70             }
71              
72             sub long_view {
73 0     0 0   my $self = shift;
74              
75 0           my $results_pass = $self->build_query;
76              
77 0           while ( my $res = $results_pass->next ) {
78              
79 0           my $table = $self->build_table($res);
80 0           $table->setCols(
81             [
82             'JobName',
83             'Task Tags',
84             'Start Time',
85             'End Time',
86             'Duration',
87             'Exit Code'
88             ]
89             );
90              
91 0           map { $self->iter_jobs_long($_) } @{ $res->{jobs} };
  0            
  0            
92 0           while ( my ( $k, $v ) = each %{ $self->task_data } ) {
  0            
93 0           foreach my $h ( @{$v} ) {
  0            
94             $table->addRow(
95             [
96             $k, $h->{task_tags}, $h->{start_time},
97             $h->{end_time}, $h->{duration}, $h->{exit_code}
98 0           ]
99             );
100             }
101 0           $table->addRowLine;
102             }
103 0           $self->task_data( {} );
104 0           print $table;
105 0           print "\n";
106             }
107             }
108              
109             sub iter_jobs_long {
110 0     0 0   my $self = shift;
111 0           my $job = shift;
112              
113 0 0         if ( !exists $self->task_data->{ $job->{job_name} } ) {
114 0           $self->task_data->{ $job->{job_name} } = [];
115             }
116              
117 0           map { $self->iter_tasks_long( $job->{job_name}, $_ ) } @{ $job->{tasks} };
  0            
  0            
118             }
119              
120             sub iter_tasks_long {
121 0     0 0   my $self = shift;
122 0           my $jobname = shift;
123 0           my $task = shift;
124              
125 0           my $exit_code = $task->{exit_code};
126 0 0         $exit_code = "" if !defined $exit_code;
127              
128             push(
129 0           @{ $self->task_data->{$jobname} },
130             {
131             'start_time' => $task->{start_time} || "",
132             'end_time' => $task->{exit_time} || "",
133             'task_tags' => $task->{task_tags} || "",
134 0   0       'duration' => $task->{duration} || "",
      0        
      0        
      0        
135             'exit_code' => $exit_code,
136             }
137             );
138             }
139              
140             sub summary_view {
141 0     0 0   my $self = shift;
142              
143 0           my $results_pass = $self->build_query;
144              
145 0           while ( my $res = $results_pass->next ) {
146              
147 0           my $table = $self->build_table($res);
148 0           $table->setCols(
149             [ 'JobName', 'Complete', 'Running', 'Success', 'Fail', 'Total' ] );
150              
151 0           map { $self->iter_jobs_summary($_) } @{ $res->{jobs} };
  0            
  0            
152              
153 0           while ( my ( $k, $v ) = each %{ $self->task_data } ) {
  0            
154             $table->addRow(
155             [
156             $k,
157             $self->task_data->{$k}->{complete},
158             $self->task_data->{$k}->{running},
159             $self->task_data->{$k}->{success},
160             $self->task_data->{$k}->{fail},
161             $self->task_data->{$k}->{total},
162 0           ]
163             );
164             }
165              
166 0           $self->task_data( {} );
167 0           print $table;
168 0           print "\n";
169             }
170             }
171              
172             sub build_table {
173 0     0 0   my $self = shift;
174 0           my $res = shift;
175              
176 0           my $header = "Time: " . $res->{submission_time};
177 0           $header .= " SubmissionID: " . $res->{submission_pi};
178 0 0         $header .= " Project: " . $res->{project} if defined $res->{project};
179 0           my $table = Text::ASCIITable->new( { headingText => $header } );
180              
181 0           return $table;
182             }
183              
184             sub build_query {
185 0     0 0   my $self = shift;
186              
187             # $self->schema->storage->debug(1);
188 0           my $where = {};
189 0 0         if ( $self->has_project ) {
190 0           $where->{project} = $self->project;
191             }
192 0 0         if ( $self->has_jobname ) {
193 0           $where->{'jobs.job_name'} = $self->jobname;
194             }
195              
196 0           my $results_pass = $self->schema->resultset('Submission')->search(
197             $where,
198             {
199             join => { jobs => 'tasks' },
200             prefetch => { jobs => 'tasks' },
201             group_by => [ 'project', ],
202             order_by => { '-desc' => 'submission_pi', },
203             }
204             );
205              
206 0           $results_pass->result_class('DBIx::Class::ResultClass::HashRefInflator');
207 0           return $results_pass;
208             }
209              
210             sub iter_jobs_summary {
211 0     0 0   my $self = shift;
212 0           my $job = shift;
213              
214 0 0         if ( !exists $self->task_data->{ $job->{job_name} } ) {
215 0           my $job_meta = decode_json( $job->{jobs_meta} );
216 0           my $total_tasks = $job_meta->{job_tasks};
217             $self->task_data->{ $job->{job_name} } = {
218 0           complete => 0,
219             success => 0,
220             fail => 0,
221             total => $total_tasks,
222             running => 0
223             };
224             }
225              
226 0           map { $self->iter_tasks_summary( $job->{job_name}, $_ ) }
227 0           @{ $job->{tasks} };
  0            
228              
229             }
230              
231             sub iter_tasks_summary {
232 0     0 0   my $self = shift;
233 0           my $job_name = shift;
234 0           my $task = shift;
235              
236 0 0         if ( $self->task_is_running($task) ) {
237 0           $self->task_data->{$job_name}->{running} += 1;
238             }
239             else {
240 0           $self->task_data->{$job_name}->{complete} += 1;
241 0 0         if ( $self->task_is_success($task) ) {
242 0           $self->task_data->{$job_name}->{success} += 1;
243             }
244             else {
245 0           $self->task_data->{$job_name}->{fail} += 1;
246             }
247             }
248             }
249              
250             sub task_is_running {
251 0     0 0   my $self = shift;
252 0           my $task = shift;
253              
254 0 0         if ( !defined $task->{exit_code} ) {
255 0           return 1;
256             }
257             else {
258 0           return 0;
259             }
260             }
261              
262             sub task_is_success {
263 0     0 0   my $self = shift;
264 0           my $task = shift;
265              
266 0 0         if ( $task->{exit_code} == 0 ) {
267 0           return 1;
268             }
269             else {
270 0           return 0;
271             }
272             }
273              
274             1;