diff --git a/Makefile b/Makefile index d6f1e8ad..ab556dd2 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,7 @@ CGIDIR = ${LIBEXECDIR}/mxq/cgi ######################################################################## MXQ_MYSQL_DEFAULT_FILE = ${SYSCONFDIR}/mxq/mysql.cnf +MXQ_MYSQL_RO_DEFAULT_FILE = ${SYSCONFDIR}/mxq/mysql_ro.cnf MXQ_MYSQL_DEFAULT_GROUP_CLIENT = mxqclient MXQ_MYSQL_DEFAULT_GROUP_SERVER = mxqd MXQ_MYSQL_DEFAULT_GROUP_DEVELOPMENT = mxqdevel @@ -158,6 +159,7 @@ sed-rules = -e 's,@PREFIX@,${PREFIX},g' \ -e 's,@DATADIR@,${DATADIR},g' \ -e 's,@MXQ_VERSION@,${MXQ_VERSION},g' \ -e 's,@MXQ_MYSQL_DEFAULT_FILE@,${MXQ_MYSQL_DEFAULT_FILE},g' \ + -e 's,@MXQ_MYSQL_RO_DEFAULT_FILE@,${MXQ_MYSQL_RO_DEFAULT_FILE},g' \ -e 's,@CGIDIR@,${CGIDIR},g' \ -e 's,@HTTP_USER@,${HTTP_USER},g' \ -e 's,@HTTP_GROUP@,${HTTP_GROUP},g' \ diff --git a/web/pages/mxq/mxq.in b/web/pages/mxq/mxq.in index d35021f8..f188b33f 100755 --- a/web/pages/mxq/mxq.in +++ b/web/pages/mxq/mxq.in @@ -10,8 +10,11 @@ our %GROUP_STATUS_NAME; # ( 0=>'OK',...) our %JOB_STATUS_NAME; our %DAEMON_STATUS_NAME; our $dbh; +our $hostconfig; our $q; +our $LIMIT=100000; # max rows + sub STYLE { return <<'EOF'; EOF } sub HEAD { - return <<'EOF'.STYLE().<<'EOF'; - - - - - - - -EOF - -EOF + return "\n\n".STYLE()."\n"; } sub my_url { @@ -73,10 +48,22 @@ sub my_url { return $uri; } +sub hostconfig_init { + open my $in,'<','/etc/hostconfig' or die "/etc/hostconfig: $!\n"; + while (<$in>) { + s/#.*//; + chomp; + my ($host,$attr,$value)=split ' ',$_,3; + $host or next; + $attr or next; + $attr eq 'mxqd' and $hostconfig->{$host}=1; + } +} + sub db_init { - open my $test,"<@MXQ_MYSQL_DEFAULT_FILE@" or die "@MXQ_MYSQL_DEFAULT_FILE@: $!\n"; - $dbh= DBI->connect('DBI:mysql:mysql_read_default_file=@MXQ_MYSQL_DEFAULT_FILE@',undef,undef, { RaiseError => 1, AutoCommit => 1 }); + open my $test,"<@MXQ_MYSQL_RO_DEFAULT_FILE@" or die "@MXQ_MYSQL_RO_DEFAULT_FILE@: $!\n"; + $dbh= DBI->connect('DBI:mysql:mysql_read_default_file=@MXQ_MYSQL_RO_DEFAULT_FILE@',undef,undef, { RaiseError => 1, AutoCommit => 1 }); # mxq_group.h register_group_status( OK => 0, @@ -137,10 +124,73 @@ sub daemon_status { return get_status(\%DAEMON_STATUS_NAME,@_) } sub humanSeconds { my ($seconds)=@_; - $seconds<60 and return sprintf ('%2d s',$seconds); - $seconds<3600 and return sprintf ('%2d m %2d s',$seconds/60,$seconds%60); - $seconds<86400 and return sprintf ('%2d h %2d m',$seconds/3600,$seconds%3600/60); - return sprintf('%2d d %2d h',$seconds/86400,$seconds%86400/3600); + $seconds<60 and return sprintf ('%2ds',$seconds); + $seconds<3600 and return sprintf ('%2dm %2ds',$seconds/60,$seconds%60); + $seconds<86400 and return sprintf ('%2dh %2dm',$seconds/3600,$seconds%3600/60); + return sprintf('%2dd %2dh',$seconds/86400,$seconds%86400/3600); +} + +sub size { + my $s = shift; + my $n = shift; + defined($n) or $n=1; + $s == 0 and return '0 B'; + + my @T=(); + for (my $f = 4; $f >= 0; $f--) { + my $t = int($s/(1000**$f)); + push @T, ($t > 0) ? $t : 0; # TB/GB/MB/Kb/B + $s -= $t*(1000**$f); + } + my @L; + for my $x ('TB','GB','MB','kB','B') { + my $y = shift @T; + if ($y != 0) { + if (defined($n)) { + $n--; + last if ($n < 0); + } + push @L,"$y $x"; + } + } + return join(' ',@L); +} + +sub days { + my $s = shift; + my $n = shift; + + if ($s == 0) { + return '0 secs'; + } + my @T=(); + my $t = int($s/(60*60*24)); + push @T, ($t > 0) ? $t : 0; # days + $s -= $t*(60*60*24); + + $t = int($s/(60*60)); + push @T, ($t > 0) ? $t : 0; # hrs + $s -= $t*(60*60); + + $t = int($s/(60)); + push @T, ($t > 0) ? $t : 0; # min + $s -= $t*60; + + $t = int($s); + push @T, ($t > 0) ? $t : 0; # sec + + my @L; + for my $x ('days','hrs','min','secs') { + my $y = shift @T; + if ($y != 0) { + if (defined($n)) { + $n--; + last if ($n < 0); + } + push @L,"$y $x"; + } + } + return join(' ',@L); } sub split_cmd { @@ -149,6 +199,21 @@ sub split_cmd { return $in; } +sub colorize { + my ($color,$html) = @_; + return $html if ($html eq "0"); # zeros remain black + return "$html"; +} + +sub colorize_status { + my ($status)=@_; + return colorize("green", $status) if $status =~ m/FINISHED/; + return colorize("orange",$status) if $status =~ m/RUNNING/; + return colorize("blue", $status) if $status =~ m/INQ/; + return colorize("red", $status) if $status =~ m/KILL|FAIL/; + return $status; +} + sub DataDumper { use Data::Dumper; $Data::Dumper::Indent=0; @@ -170,6 +235,7 @@ sub job_table_pending { $out.=$q->Tr($q->th(\@cols)); + my $cnt=0; while (my $row=$sth->fetchrow_arrayref()) { my ($job_id,$user_name,$date_submit,$job_threads)=@$row; @@ -179,8 +245,12 @@ sub job_table_pending { $q->td($date_submit), $q->td({class=>'number'},$job_threads), ); + ++$cnt == $LIMIT and last; } $out.=''; + if ($cnt==$LIMIT) { + $out.=$q->p($q->em("(truncated after $LIMIT rows)")); + } } sub job_table_running { @@ -215,35 +285,165 @@ sub job_table_running { sub job_table_of_group { - my ($group_id)=@_; + my ($group_id,$job_status_filter)=@_; my $out; - my @cols=qw(job_id job_status date_submit date_start host_hostname host_pid); - - my $sth=$dbh->prepare('SELECT '.join(',',@cols).' FROM mxq_job,mxq_group WHERE mxq_job.group_id=mxq_group.group_id AND mxq_job.group_id=? ORDER BY job_id DESC'); + my @scols=qw(job_id job_status qtime rtime host_hostname host_pid); + + my $jobfilter = defined($job_status_filter) ? "AND mxq_job.job_status=$job_status_filter" : ''; + + my $sth=$dbh->prepare(<<"__EOF__"); + SELECT + job_id, + job_status, + date_submit, + date_start, + date_end, + host_hostname, + host_pid, + timestampdiff(SECOND,date_submit,date_start), + timestampdiff(SECOND,date_submit,now()), + timestampdiff(SECOND,date_start,date_end), + timestampdiff(SECOND,date_start,now()), + UNIX_TIMESTAMP(date_submit) as ds + FROM mxq_job,mxq_group + WHERE mxq_job.group_id=mxq_group.group_id AND mxq_job.group_id=? + $jobfilter + ORDER BY job_id DESC +__EOF__ $sth->execute($group_id); $out.=''; - $out.=$q->Tr($q->th(\@cols)); + $out.=$q->Tr($q->th(\@scols)); + my $lds; + my $col=1; + my $cnt=0; while (my $row=$sth->fetchrow_arrayref()) { - my ($job_id,$job_status,$date_submit,$date_start,$host_hostname,$host_pid)=@$row; + my ($job_id,$job_status,$date_submit,$date_start,$date_end,$host_hostname,$host_pid, + $qtime,$qtime_now,$rtime,$rtime_now,$ds)=@$row; + + if (defined($qtime)) { + $qtime = humanSeconds($qtime); + } else { + $qtime = colorize("gray",humanSeconds($qtime_now)); + } + + if (defined($rtime)) { + $rtime = humanSeconds($rtime); + } else { + $rtime = colorize("gray",humanSeconds($rtime_now)); + } + my $date_info = "submit: $date_submit\nstart: $date_start\nend: $date_end"; + + if (defined $lds && abs($lds-$ds)>10) { + $col = 1-$col; + $out.=$q->Tr($q->td(' ')); + } + $lds=$ds; $out.=$q->Tr( + {class=>'bg'.$col}, $q->td({class=>'number'},$q->a({href=>selfurl("/job/$job_id")},$job_id)), - $q->td(job_status($job_status)), - $q->td($date_submit), - $q->td($date_start), + $q->td(colorize_status(job_status($job_status))), + $q->td("$qtime"), + $q->td("$rtime"), $q->td($host_hostname), $q->td({class=>'number'},$host_pid), ); + ++$cnt == $LIMIT and last; } $out.='
'; + if ($cnt==$LIMIT) { + $out.=$q->p($q->em("(truncated after $LIMIT rows)")); + } +} + +sub job_status_filter_buttons { + my $group_id = shift; + my @r=(); + push @r,$q->a({href=>selfurl("/group/$group_id")},'ALL'); + for my $js ( 0, 200, 1000, 750, 400 ) { + push @r,$q->a({href=>selfurl("/group/$group_id/$js")},job_status($js)); + } + return '

'.join(' | ',@r).'

'; +} + +sub group_details_raw { + my ($o)=@_; + + my $group_name=escapeHTML($o->{'group_name'}); + my $job_command=escapeHTML($o->{'job_command'}); + my $group_status_text=group_status($o->{'group_status'}); + + return <<"__EOF__" +
+group_name     : $group_name
+group_status   : $group_status_text
+group_flags    : $o->{group_flags}
+group_priority : $o->{group_priority}
+
+user_uid       : $o->{user_uid}
+user_name      : $o->{user_name}
+user_gid       : $o->{user_gid}
+user_group     : $o->{user_group}
+
+job_command    : $job_command
+job_threads    : $o->{job_threads}
+job_memory     : $o->{job_memory} MiB
+job_time       : $o->{job_time} minutes
+
+job_max_per_node      : $o->{job_max_per_node}
+
+group_jobs            : $o->{group_jobs}
+group_jobs_inq        : $o->{group_jobs_inq}
+group_jobs_running    : $o->{group_jobs_running}
+group_jobs_finished   : $o->{group_jobs_finished}
+group_jobs_failed     : $o->{group_jobs_failed}
+group_jobs_cancelled  : $o->{group_jobs_cancelled}
+group_jobs_unknown    : $o->{group_jobs_unknown}
+group_jobs_restarted  : $o->{group_jobs_restarted}
+
+group_slots_running:  : $o->{group_slots_running}
+
+group_mtime           : $o->{group_mtime}
+
+group_date_end        : $o->{group_date_end}
+
+stats_max_sumrss                 : $o->{stats_max_sumrss} kiB
+stats_max_maxrss                 : $o->{stats_max_maxrss}
+stats_max_utime_sec              : $o->{stats_max_utime_sec}
+stats_max_stime_sec              : $o->{stats_max_stime_sec}
+stats_max_real_sec               : $o->{stats_max_real_sec}
+
+stats_total_utime_sec            : $o->{stats_total_utime_sec}
+stats_total_stime_sec            : $o->{stats_total_stime_sec}
+stats_total_real_sec             : $o->{stats_total_real_sec}
+stats_total_wait_sec             : $o->{stats_total_wait_sec}
+
+stats_wait_sec                   : $o->{stats_wait_sec}
+stats_run_sec                    : $o->{stats_run_sec}
+stats_idle_sec                   : $o->{stats_idle_sec}
+
+stats_total_utime_sec_finished   : $o->{stats_total_utime_sec_finished}
+stats_total_stime_sec_finished   : $o->{stats_total_stime_sec_finished}
+stats_total_real_sec_finished    : $o->{stats_total_real_sec_finished}
+stats_total_wait_sec_finished    : $o->{stats_total_wait_sec_finished}
+
+__EOF__ +} + +sub group_details_raw_by_group_id { + my ($group_id)=@_; + my $sth=$dbh->prepare('SELECT * FROM mxq_group WHERE group_id=? LIMIT 1',undef); + $sth->execute($group_id); + my $o=$sth->fetchrow_hashref('NAME_lc'); + return group_details_raw($o); } -sub group_detail { +sub group_details { my ($group_id)=@_; $dbh or db_init(); @@ -253,79 +453,45 @@ sub group_detail { $sth->execute($group_id); my %o=%{$sth->fetchrow_hashref('NAME_lc')}; - $out.=h2("Group Detail group_id $o{group_id}"); - my $group_status_text=group_status($o{'group_status'}); my $group_name=escapeHTML($o{group_name}); my $job_command=escapeHTML($o{job_command}); - $out.=<<"EOF"; + $out.=<<"__EOF__"; +

Summary

-group_name     : $group_name
-group_status   : $group_status_text
-group_flags    : $o{group_flags}
-group_priority : $o{group_priority}
+$o{user_name} submitted
 
-user_uid       : $o{user_uid}
-user_name      : $o{user_name}
-user_gid       : $o{user_gid}
-user_group     : $o{user_group}
+        $job_command
+
+in group "$group_name", the group status is $group_status_text.
 
-job_command    : $job_command
-job_threads    : $o{job_threads}
-job_memory     : $o{job_memory} MiB
-job_time       : $o{job_time} minutes
-
-job_max_per_node      : $o{job_max_per_node}
-
-group_jobs            : $o{group_jobs}
-group_jobs_inq        : $o{group_jobs_inq}
-group_jobs_running    : $o{group_jobs_running}
-group_jobs_finished   : $o{group_jobs_finished}
-group_jobs_failed     : $o{group_jobs_failed}
-group_jobs_cancelled  : $o{group_jobs_cancelled}
-group_jobs_unknown    : $o{group_jobs_unknown}
-group_jobs_restarted  : $o{group_jobs_restarted}
-
-group_slots_running:  : $o{group_slots_running}
-
-group_mtime           : $o{group_mtime}
-
-group_date_end        : $o{group_date_end}
-
-stats_max_sumrss                 : $o{stats_max_sumrss} kiB
-stats_max_maxrss                 : $o{stats_max_maxrss}
-stats_max_utime_sec              : $o{stats_max_utime_sec}
-stats_max_stime_sec              : $o{stats_max_stime_sec}
-stats_max_real_sec               : $o{stats_max_real_sec}
-
-stats_total_utime_sec            : $o{stats_total_utime_sec}
-stats_total_stime_sec            : $o{stats_total_stime_sec}
-stats_total_real_sec             : $o{stats_total_real_sec}
-stats_total_wait_sec             : $o{stats_total_wait_sec}
-
-stats_wait_sec                   : $o{stats_wait_sec}
-stats_run_sec                    : $o{stats_run_sec}
-stats_idle_sec                   : $o{stats_idle_sec}
-
-stats_total_utime_sec_finished   : $o{stats_total_utime_sec_finished}
-stats_total_stime_sec_finished   : $o{stats_total_stime_sec_finished}
-stats_total_real_sec_finished    : $o{stats_total_real_sec_finished}
-stats_total_wait_sec_finished    : $o{stats_total_wait_sec_finished}
 
-EOF + +

[show group details ...]

+
+ + +__EOF__ - return $out; + return $out; } sub group { - my ($group_id)=@_; + my ($group_id,$job_status_filter)=@_; my $out=h1('MXQ Group '.$group_id); - $out.=group_detail($group_id); - $out.=h2('Jobs of this group').job_table_of_group($group_id); + $out.=group_details($group_id); + my $what = defined($job_status_filter) ? job_status($job_status_filter) . ' jobs' : 'Jobs'; + $out.=h2($what . ' of this group ').job_status_filter_buttons($group_id).job_table_of_group($group_id,$job_status_filter); return $out; } @@ -341,8 +507,6 @@ sub job { $sth->execute($job_id); my %o=%{$sth->fetchrow_hashref('NAME_lc')}; - $out.=group_detail($o{group_id}); - my $job_status_text=job_status($o{'job_status'}); my $job_umask_text=sprintf('%03O',$o{job_umask}); my $link_group_id=a({href=>selfurl("/group/$o{group_id}")},$o{group_id}); @@ -356,8 +520,6 @@ sub job { defined $_ or $_='<null>' for values %o; - $out.=h2("Job Details $o{job_id}"); - $out.=<<"EOF";
 job_status       : $job_status_text
@@ -411,12 +573,15 @@ stats_nvcsw      : $o{stats_nvcsw}
 stats_nivcsw     : $o{stats_nivcsw}
 
EOF + + $out .= "

group details

"; + $out.=group_details_raw_by_group_id($o{group_id}); return $out; } sub group_table { - my ($sql_clause,$sql_binds)=@_; + my ($sql_clause,$sql_binds,$days)=@_; $sql_clause||='true'; @@ -426,8 +591,10 @@ sub group_table { $out .= '

Active Groups

'; @cols=qw( - group_id group_name job_threads user_name - group_mtime + group_id group_name job_threads + job_memory + job_time + user_name group_status group_jobs group_jobs_inq group_jobs_running @@ -435,12 +602,20 @@ sub group_table { ); @head=qw( - group_id group_name threads user_name - group_mtime - group_status + group
id + group
name + req.
threads + req.
memory + req.
runtime + user
name + group
status jobs - inq running - finished failed cancelled unknown + inq + running + finished + failed + cancelled + unknown ); my $sth=$dbh->prepare('SELECT '.join(',',@cols).' FROM mxq_group WHERE '.$sql_clause.' AND (group_jobs_running>0 OR group_jobs_inq>0) ORDER BY group_id DESC'); @@ -449,7 +624,9 @@ sub group_table { $out.=''; $out.=$q->Tr($q->th(\@head)); while (my $row=$sth->fetchrow_arrayref()) { - my ($group_id,$group_name,$job_threads,$user_name,$group_mtime,$group_status, + my ($group_id,$group_name,$job_threads, + $job_memory,$job_time, + $user_name,$group_status, $group_jobs,$group_jobs_inq,$group_jobs_running,$group_jobs_finished,$group_jobs_failed,$group_jobs_cancelled,$group_jobs_unknown )=@$row; @@ -457,45 +634,66 @@ sub group_table { $q->td({class=>'number'},$q->a({href=>selfurl("/group/$group_id")},$group_id)), $q->td($group_name), $q->td({class=>'number'},$job_threads), + $q->td({class=>'number'},size($job_memory*1000**2)), + $q->td({class=>'number'},days($job_time*60)), $q->td($q->a({href=>my_url('groups',{user_name=>$user_name})},$user_name)), - $q->td($group_mtime), $q->td(group_status($group_status)), $q->td({class=>'number'},$group_jobs), - $q->td({class=>'number'},$group_jobs_inq), - $q->td({class=>'number'},$group_jobs_running), - $q->td({class=>'number'},$group_jobs_finished), - $q->td({class=>'number'},$group_jobs_failed), - $q->td({class=>'number'},$group_jobs_cancelled), - $q->td({class=>'number'},$group_jobs_unknown) + $q->td({class=>'number'},colorize("blue",$group_jobs_inq)), + $q->td({class=>'number'},colorize("orange",$group_jobs_running)), + $q->td({class=>'number'},colorize("green",$group_jobs_finished)), + $q->td({class=>'number'},colorize("red",$group_jobs_failed)), + $q->td({class=>'number'},colorize("red",$group_jobs_cancelled)), + $q->td({class=>'number'},colorize("red",$group_jobs_unknown)) ); } $out.='
'; - $out .= '

Finished Groups (last 7 days)

'; + $out .= "

Finished Groups (last $days days)

"; @cols=qw( - group_id group_name job_threads user_name - group_date_end + group_id group_name job_threads + job_memory + stats_max_sumrss + job_time + stats_run_sec + stats_idle_sec + user_name group_status group_jobs group_jobs_finished group_jobs_failed group_jobs_cancelled group_jobs_unknown ); @head=qw( - group_id group_name threads user_name - date_end - group_status + group
id + group
name + req.
threads + req.
memory + used
memory + req.
runtime + used
runtime + user
name + group
status jobs - finished failed cancelled unknown + fin + fail + canc + unkn ); - $sth=$dbh->prepare('SELECT '.join(',',@cols).' FROM mxq_group WHERE '.$sql_clause.' AND (group_jobs_running=0 AND group_jobs_inq=0) AND group_mtime >= DATE_SUB(NOW(),INTERVAL 7 DAY) ORDER BY group_id DESC'); - $sth->execute(@$sql_binds); + $sth=$dbh->prepare('SELECT '.join(',',@cols).' FROM mxq_group WHERE '.$sql_clause.' AND (group_jobs_running=0 AND group_jobs_inq=0) AND group_mtime >= DATE_SUB(NOW(),INTERVAL ? DAY) ORDER BY group_id DESC'); + $sth->execute(@$sql_binds,$days); $out.=''; $out.=$q->Tr($q->th(\@head)); while (my $row=$sth->fetchrow_arrayref()) { - my ($group_id,$group_name,$job_threads,$user_name,$group_date_end,$group_status, + my ($group_id,$group_name,$job_threads, + $job_memory, + $stats_max_sumrss, + $job_time, + $stats_run_sec, + $stats_idle_sec, + $user_name,$group_status, $group_jobs,$group_jobs_finished,$group_jobs_failed,$group_jobs_cancelled,$group_jobs_unknown )=@$row; @@ -503,14 +701,17 @@ sub group_table { $q->td({class=>'number'},$q->a({href=>selfurl("/group/$group_id")},$group_id)), $q->td($group_name), $q->td({class=>'number'},$job_threads), + $q->td({class=>'number'},size($job_memory*1000**2)), + $q->td({class=>'number'},size($stats_max_sumrss*1000)), + $q->td({class=>'number'},humanSeconds($job_time*60)), + $q->td({class=>'number'},humanSeconds($stats_run_sec+$stats_idle_sec,2)), $q->td($q->a({href=>my_url('groups',{user_name=>$user_name})},$user_name)), - $q->td($group_date_end), $q->td(group_status($group_status)), $q->td({class=>'number'},$group_jobs), - $q->td({class=>'number'},$group_jobs_finished), - $q->td({class=>'number'},$group_jobs_failed), - $q->td({class=>'number'},$group_jobs_cancelled), - $q->td({class=>'number'},$group_jobs_unknown) + $q->td({class=>'number'},colorize("green",$group_jobs_finished)), + $q->td({class=>'number'},colorize("red",$group_jobs_failed)), + $q->td({class=>'number'},colorize("red",$group_jobs_cancelled)), + $q->td({class=>'number'},colorize("red",$group_jobs_unknown)) ); } $out.='
'; @@ -522,16 +723,24 @@ sub groups { my @sql_clauses; my @sql_binds; + my $user_name_info=''; if ($q->param('user_name')) { push @sql_clauses,'user_name = ?'; push @sql_binds,$q->param('user_name'); + $user_name_info=' submitted by '. $q->param('user_name'); + } + my $days = 7; + if ($q->param('days')) { + if ( $q->param('days') =~ /^\d+$/ ) { + $days = $q->param('days'); + } } - my $out=h1('MXQ Groups'); + my $out=h1("MXQ Groups$user_name_info"); $dbh or db_init(); - $out.=group_table(join('AND',@sql_clauses),\@sql_binds); + $out.=group_table(join('AND',@sql_clauses),\@sql_binds,$days); return $out; } @@ -543,6 +752,8 @@ sub active_jobs() { sub server() { $dbh or db_init(); + $hostconfig or hostconfig_init(); + my $dead_hosts = $hostconfig; my $out=h1('MXQ Servers'); my @cols=qw( @@ -569,9 +780,9 @@ sub server() { # 'boot_id', # 'pid_starttime', 'pid', - 'slots
available', - 'memory
available', - 'max runtime
(minutes)', + 'slots', + 'memory', + 'time
min', # 'time', 'slotmem_soft
available', # 'slotmem_hard', @@ -584,7 +795,7 @@ sub server() { # 'stop', ])); - + my %S; while (my $row=$sth->fetchrow_arrayref()) { my ( $daemon_id,$daemon_name,$status,$hostname,$mxq_version,$boot_id,$pid_starttime, @@ -596,6 +807,14 @@ sub server() { ) = @$row; $hostname =~s/\.molgen\.mpg\.de$//; + $S{daemon_slots} += $daemon_slots; + $S{daemon_slots_dist}->{$daemon_slots}++; + $S{daemon_slots_running} += $daemon_slots_running; + $S{daemon_memory_sum} += $daemon_memory; + $S{daemon_memory_used_sum} += $daemon_memory_used; + $S{servers}++; + + delete($dead_hosts->{$hostname}); $out.=$q->Tr( $q->td({class=>'number'},$daemon_id), @@ -605,21 +824,32 @@ sub server() { $q->td($mxq_version), # $q->td($boot_id), # $q->td($pid_starttime), - $q->td($daemon_pid), + $q->td({class=>'number'},$daemon_pid), $q->td({class=>'number'},$daemon_slots), - $q->td({class=>'number'},$daemon_memory), - $q->td({class=>'number'},$daemon_maxtime), - $q->td({class=>'number'},$daemon_memory_limit_slot_soft), + $q->td({class=>'number'},size($daemon_memory*1000000)), + $q->td({class=>'number'},$daemon_maxtime ? $daemon_maxtime : ''), + $q->td({class=>'number'},size($daemon_memory_limit_slot_soft*1000000)), # $q->td({class=>'number'},$daemon_memory_limit_slot_hard), $q->td({class=>'number'},$daemon_jobs_running), $q->td({class=>'number'},$daemon_slots_running), $q->td({class=>'number'},$daemon_threads_running), - $q->td({class=>'number'},$daemon_memory_used), + $q->td({class=>'number'},size($daemon_memory_used*1000000)), # $q->td($mtime), # $q->td($daemon_start), # $q->td($daemon_stop), ); } + map { + $out.=$q->Tr( $q->td(0),$q->td('-'),$q->td('no mxqd'),$q->td($_),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),$q->td(' '),); + } keys %{$dead_hosts}; + + $out.=$q->Tr($q->td({colspan=>14},' ')); + my $dist = join(', ',map {"$S{daemon_slots_dist}->{$_}x$_"} sort {$b <=> $a} keys %{$S{daemon_slots_dist}}); + $out.=$q->Tr( + $q->td({class=>'center', colspan=>3},$S{servers}.' servers'),$q->td($dist), + $q->td({class=>'center', colspan=>3},$S{daemon_slots}.' cores'),$q->td({class=>'number'},size($S{daemon_memory_sum}*1000**2)),$q->td(' '),$q->td(' '),$q->td(' '), + $q->td({class=>'number'},$S{daemon_slots_running}),$q->td(' '),$q->td({class=>'number'},size($S{daemon_memory_used_sum}*1000**2)),); + $out.=''; return $out; } @@ -629,12 +859,12 @@ sub selfurl { return $q->url().$path_info; } -sub top { - return $q->ul( - $q->li(a({href=>selfurl('/groups')},'groups')), - $q->li(a({href=>selfurl('/active_jobs')},'active_jobs')), - $q->li(a({href=>selfurl('/server')},'server')), - ); +sub top_menu { + return '' . $q->Tr( + $q->td(a({href=>selfurl('/groups')},'groups')),$q->td(' '), + $q->td(a({href=>selfurl('/active_jobs')},'active_jobs')),$q->td(' '), + $q->td(a({href=>selfurl('/server')},'server')) + ).''; } $q=new CGI; @@ -649,17 +879,19 @@ my $path_info=$q->path_info()||''; $path_info=~s/\/$//; if ($path_info eq '') { - print header().HEAD().top(); + print header().HEAD().top_menu().groups(); } elsif ($path_info eq '/server') { - print header().HEAD().server(); + print header().HEAD().top_menu().server(); } elsif ($path_info eq '/groups') { - print header().HEAD().groups(); + print header().HEAD().top_menu().groups(); } elsif ($path_info eq '/active_jobs') { - print header().HEAD().active_jobs(); + print header().HEAD().top_menu().active_jobs(); } elsif ($path_info =~ /\/group\/(\d+)$/) { - print header().HEAD().group($1); + print header().HEAD().top_menu().group($1); +} elsif ($path_info =~ /\/group\/(\d+)\/(\d+)$/) { + print header().HEAD().top_menu().group($1,$2); } elsif ($path_info =~ /\/job\/(\d+)$/) { - print header().HEAD().job($1); + print header().HEAD().top_menu().job($1); } else { - print header(-status => 404).HEAD().'

not found

'; + print header(-status => 404).HEAD().top_menu().'

not found

'; }