Re: ASCII chart that displays jobs that are running and jobs that are queued for a day
by madbombX (Hermit) on Oct 26, 2006 at 11:55 UTC
|
Since you have a few goals that you are trying to accomplish here, you are going to need modules for each one of the goals. In order to create an ASCII table, I would look into using the Perl module Perl6::Form. As far as taking the epoch times and manipulating them and organizing them, you can check out some of the following modules: Date::Manip, Time::Format, Time::Period. Using these modules will allow you to compare times and create functions to compare the jobs and put them where they need to go.
What I would do is to write a function to determine what time the job is running and push it into a complex data structrue. Then iterate over that data structure to create the table you are looking for. You may want to check out planetscape's Re: How can I visualize my complex data structure?.
However, if you looking for more specific help...the best way to get it is to actually start the work. Attempt some code (ie a specific part of your program). If you are having trouble, show us what you have tried and the errors it gives you and we will do our best to help you along and explain why what happened happened. But just asking for general help with a problem may not quite yield the results you are looking for. | [reply] |
Re: ASCII chart that displays jobs that are running and jobs that are queued for a day
by husker (Chaplain) on Oct 26, 2006 at 14:31 UTC
|
OK, I'm assuming those values in each column are some time designator (seconds since epoch or something similar?)
Since you are going to be doing a lot of time comparisons to figure out "did this job queue up but not start before this given time" or "did this job start but not finish as of this given time", seems to me your data structure needs to be something that's going to be ordered by time to simplify scanning the structure for the jobs.
Take the simplest case: how would you do this for just one queue? I'd be tempted to create three ordered arrays: one containing all the queue times, one with all the start time, and one with all the end times. The algorithm for stepping through the arrays, looking for jobs that werre queued up but not started, or started but not finished, as of a given time is pretty simple. In fact, I'd probably collect all three arrays into a hash, so I'd have a hash of arrays. There would be three keys: q_time, s_time, e_time, with the array of those times hanging off each key.
Extending this to 4 queues (or 7 queues or 2 .. maybe you can't predict how many queues you'll have each time?), then you just add another key to the front of your hash, with this key being the queue name. So now you have a hash of a hash of arrays.
Iterating over that to generate the report should not be too awful hard.
If a hash of a hash of arrays gives you a headache, start simple: do your algorithm with three separate arrays. Then put those arrays into a hash and see how it works. Then put another key in front of that hash and look again. It's not that tricky, really.
Hope that helps.
Edit: Actually, be very careful how you order your arrays. If you sort each array independently, you'll hose yourself good. You have to keep the queue, start, and end times for each job *together*. I realized I didn't point that out.
| [reply] |
|
Thank's, thats really helpful. That makes sense.
I'm going to try all those suggestions at the weekend. Looks like I've got a busy weekend in front of me lol.
| [reply] |
Re: ASCII chart that displays jobs that are running and jobs that are queued for a day
by Anonymous Monk on Oct 26, 2006 at 12:10 UTC
|
Me and my Buddy YAWPS can help.
code to get time with time offset if needed.
my $date = get_date(0);
# --------------------------------------------------------------------
+-
# Get the current date and time in epoch seconds.
# --------------------------------------------------------------------
+-
sub get_date
{
my $cfg{time_offset} = shift;
return time + 3600 * $cfg{time_offset};
}
formats the date to many viewing styles
my $formated_date($date, 3);
# --------------------------------------------------------------------
+-
# Format date output.
# --------------------------------------------------------------------
+-
sub format_date
{
my $date = shift || &get_date;
my $type = shift || 1;
# Get user profile.
my $query = new CGI;
my %user_data = authenticate();
# Get selected date format.
my $sel_date_format =
(exists $user_data{date_format})
? $user_data{date_format}
: $cfg{date_format};
$sel_date_format = ($type || $type ne '') ? $type : $cfg{date_
+format};
$date = ($date || $date ne '') ? $date : get_date()
+;
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isds
+t) =
localtime($date + 3600 * $cfg{time_offset});
my ($formatted_date, $cmon, $cday, $syear);
$year += 1900;
$cmon = $mon + 1;
$syear = sprintf("%02d", $year % 100);
if ($hour < 10) { $hour = 0 . $hour; }
if ($min < 10) { $min = 0 . $min; }
if ($sec < 10) { $sec = 0 . $sec; }
if ($cmon < 10) { $cmon = 0 . $cmon; }
$cday = ($mday < 10) ? 0 . $mday : $mday;
# Format: 01/15/00, 15:15:30
if (!$sel_date_format || $sel_date_format == 0)
{
$formatted_date = "$cmon/$cday/$syear, $hour:$min:$sec
+";
}
# Format: 15.01.00, 15:15:30
if ($sel_date_format == 1)
{
$formatted_date = "$cday.$cmon.$syear, $hour:$min:$sec
+";
}
# Format: 15.01.2000, 15:15:30
if ($sel_date_format == 2)
{
$formatted_date = "$cday.$cmon.$year, $hour:$min:$sec"
+;
}
# Format: Jan 15th, 2000, 3:15pm
if ($sel_date_format == 3)
{
my $ampm = 'am';
if ($hour > 11) { $ampm = 'pm'; }
if ($hour > 12) { $hour = $hour - 12; }
if ($hour == 0) { $hour = 12; }
if ($mday > 10 && $mday < 20) { $cday = '<sup>th</sup>
+'; }
elsif ($mday % 10 == 1) { $cday = '<sup>st</sup>'; }
elsif ($mday % 10 == 2) { $cday = '<sup>nd</sup>'; }
elsif ($mday % 10 == 3) { $cday = '<sup>rd</sup>'; }
else { $cday = '<sup>th</sup>'; }
$formatted_date = "$months{$mon} $mday$cday, $year, $h
+our:$min$ampm";
}
# Format: 15. Jan 2000, 15:15
if ($sel_date_format == 4)
{
$formatted_date = "$wday. $months{$mon} $year, $hour:$
+min";
}
# Format: 01/15/00, 3:15pm
if ($sel_date_format == 5)
{
my $ampm = 'am';
if ($hour > 11) { $ampm = 'pm'; }
if ($hour > 12) { $hour = $hour - 12; }
if ($hour == 0) { $hour = 12; }
$formatted_date = "$cmon/$cday/$syear, $hour:$min$ampm
+";
}
# Format: Sunday, 15 January, 2000
if ($sel_date_format == 6)
{
$formatted_date = "$week_days{$wday}, $mday $months{$m
+on} $year";
}
my $new_date22 = '';
my $new_mon = '';
# Format: year,month,day 20000
if ($sel_date_format == 7)
{
if($mday <= 9) { $new_date22 = "0$mday"; } else { $new_date22
+= "$mday"; }
if($mon <= 9) { $new_mon = "0$mon"; } else { $new_mon = "$mon"
+; }
#$cmon = $cmon - 1;
$formatted_date = "$year$new_mon$new_date22";
}
# Format: year,month,day 20000
if ($sel_date_format == 8)
{
#if(length($wday) < 2) { $wday = "0$wday"; }
#$cmon = $cmon - 1;
if($mon <= 9) { $new_mon = "0$mon"; } else { $new_mon
+= "$mon"; }
$formatted_date = "$year$new_mon";
}
# Format: 15/01/2000 - 03:15:30 (internal stats logfile format
+).
if ($sel_date_format == -1)
{
$formatted_date = "$cday/$cmon/$year - $hour:$min:$sec
+";
}
return $formatted_date;
}
my $time_dif = calc_time_diff($in_date1, $in_date2, '');
This code will show the difference in hours or day
# --------------------------------------------------------------------
+-
# Calculate difference between two dates.
# --------------------------------------------------------------------
+-
sub calc_time_diff
{
my ($in_date1, $in_date2, $type) = @_;
my $result = $in_date1 - $in_date2;
# Calculate difference in hours.
if (!$type) { $result = int($result / 3600); }
# Calculate difference in days.
else { $result = int($result / (24 * 3600)); }
return $result;
}
Hope that helps! and you can Tank Yawps befor thanking me! | [reply] [d/l] [select] |
|
The size of your format_date subroutine is too big; you should cut that down into smaller more readable blocks. You should also avoid the use of numbers as switchs to determine the output. Use CONSTANTS or Readonly variables to improve the readability.
| [reply] |
|
use Lingua::EN::Numbers::Ordinate;
my @standard_formats = (
'dd/mm/yyyy - HH:mm:ss', # -1: 15/01/2000 - 03:15:30
'MM/dd/yy, HH:mm:ss', # 0: 01/15/00, 15:15:30
'dd.MM.yy, HH:mm:ss', # 1: 15.01.00, 15:15:30
'dd.MM.yyyy, HH:mm:ss', # 2: 15.01.2000, 15:15:30
'MMM D, yyyy, h:mm tt', # 3: Jan 15th, 2000, 3:15pm
'd. MMM yyyy, hh:mm', # 4: 15. Jan 2000, 15:15
'MM/dd/yy, h:mm tt', # 5: 01/15/00, 3:15pm
'ddd, d MMMM, yyyy', # 6: Sunday, 15 January, 2000
'yyyyMMdd', # 7
'yyyyMM', # 8
);
my @months = qw( January February March April May June
July August September October November December );
my @wdays = qw( Sunday Monday Tuesday Wednesday Thursday
Friday Saturday );
sub d2($) { sprintf '%02d', $_[0] }
sub format_date
{
my( $date, $date_format ) = @_; # either could be undef
defined $date or
$date = get_date();
defined $date_format or
$date_format = get_date_format(); # from user data, cfg file
$date_format++; # since they start at -1
defined $standard_formats[$date_format]
or $date_format = 0; # default
my( $sec, $min, $hour, $mday, $mon, $year, $wday ) = localtime $da
+te;
my $month = $months[$mon];
my $weekday = $wdays[$wday];
$mon++;
$year += 1900;
# set up the substitutions:
my %v;
$v{'d'} = $mday; $v{'dd'} = d2 $v{'d'};
$v{'dddd'} = $weekday; $v{'ddd'} = substr $v{'dddd'}, 0, 3;
$v{'D'} = ordinate($v{'d'});
$v{'M'} = $mon; $v{'MM'} = d2 $v{'M'};
$v{'MMMM'} = $month; $v{'MMM'} = substr $v{'MMMM'}, 0, 3;
$v{'y'} = $year % 100; $v{'yy'} = d2 $v{'y'};
$v{'yyyy'} = $year;
$v{'H'} = $hour; $v{'HH'} = d2 $v{'H'};
$v{'h'} = $hour % 12; $v{'hh'} = d2 $v{'h'};
$v{'m'} = $min; $v{'mm'} = d2 $v{'m'};
$v{'s'} = $sec; $v{'ss'} = d2 $v{'s'};
$v{'t'} = $hour>=12?'P':'A'; $v{'tt'} = $v{'t'}.'M';
my $tf = $standard_formats[$date_format];
# do the substitutions:
$tf =~ s/\b([dDMyHhmst]+)\b/ $v{$1} || $1 /ge;
# this seems to be sflex's preference:
$tf =~ s/ ([AP]M)/\L$1/;
$tf
}
We're building the house of the future together.
| [reply] [d/l] |
|
sub get_date
{
my $cfg{time_offset} = shift;
syntax error at - line 4, near "$cfg{time_offset"
Execution of - aborted due to compilation errors.
| [reply] [d/l] [select] |
|
Ahhh... I wasnt loged in when i posted the above. hehehe..
| [reply] |
Re: ASCII chart that displays jobs that are running and jobs that are queued for a day
by brian_d_foy (Abbot) on Oct 26, 2006 at 22:13 UTC
|
This doesn't solve your configurable time slice problem, but it doesn't limit it either. Just change time_bin for that. I got you started so you just have to take it the rest of the way. Good luck :)
The first part of your program needs to digest the data and store it in a way in which you can conveniently access it. Since you want dates, then hours, then queues, I'd use a multi-level hash with the keys in that order. The Perl Data Structures Cookbook perldsc has some good examples.
#!/usr/bin/perl
use strict;
my %hash;
while( <DATA> )
{
chomp;
my( $name, @times ) = split;
# convert each time to [ date, time bin ]
@times = map {
[ date($_), time_bin( $_ ) ]
} @times;
=pod
The multi-level hash looks like this:
$hash{ date }{ time bin }{ queue name }{'running'}
{'queued'}
Look at it with:
use Data::Dumper; print Dumper( \%hash );
=cut
# count the bin it was queued, even if it runs in that bin
$hash{ $times[0][0] }{ $times[0][1] }{ $name }{'queued'}++;
# count the bin it starts running
$hash{ $times[1][0] }{ $times[1][1] }{ $name }{'running'}++;
# count the bin it ended, unless it's the same bin it started
# might want to check that it starts and ends on the same date too
$hash{ $times[2][0] }{ $times[2][1] }{ $name }{'running'}++
if $times[1][1] ne $times[2][1];
}
Once you have the data structure, you go through it level by level and print things however you like at the last level:
{
DATE: foreach my $date ( sort keys %hash )
{
print_header( $date );
my $hour_hash = $hash{ $date };
HOUR: foreach my $hour ( sort { $a <=> $b } keys %$hour_hash )
{
my $queue_hash = $hour_hash->{$hour};
my $string = '';
QUEUE: foreach my $queue ( sort keys %$queue_hash )
{
$string .= sprintf
" %6s %4d %4d\n",
$queue,
$queue_hash->{$queue}{'queued'},
$queue_hash->{$queue}{'running'};
}
# add the hour last to avoid a special case
substr( $string, 0, 5 ) = $hour;
print $string, "-" x 54, "\n";
}
}
}
Finally, the utility subroutines which you can adjust to taste:
sub time_bin
{
# this just assumes an hour, such as 19.
# adjust for whatever time bin you'd like to use
sprintf "%02d:00", (localtime( $_[0] ) )[2];
}
sub date
{
my @times = localtime( $_[0] );
$times[5] += 1900;
$times[4] += 1;
# join on / and make two digits for easy sorting
return join "/", map { sprintf "%02d", $_ } @times[3,4,5];
}
sub print_header
{
print <<"HERE";
Date: $_[0]
Time Queue Queued Running
------------------------------------------------------
HERE
}
For your input data, my script gives this output. If you want to show all of the hours and all of the queues even if they have nothing running, you just have to adjust the looping through the values. Instead of looping through only what's defined (foreach my $queue ( sort keys %$queue_hash )), loop through all of the possible values (foreach my $queue ( @queue_names )). With a bit more trickery, pagination is easy to add, too.
Date: 23/10/2006
Time Queue Queued Running
------------------------------------------------------
08:00 queuea 1 0
------------------------------------------------------
09:00 queuea 0 1
queueb 1 0
------------------------------------------------------
11:00 queuec 1 1
queued 1 1
------------------------------------------------------
13:00 queuea 1 0
queueb 2 2
queued 1 0
------------------------------------------------------
14:00 queuea 1 1
queuec 1 1
------------------------------------------------------
15:00 queuea 1 1
queueb 5 5
queuec 1 1
------------------------------------------------------
16:00 queuea 1 0
queueb 2 2
queued 5 5
------------------------------------------------------
17:00 queued 3 3
------------------------------------------------------
18:00 queuea 0 1
------------------------------------------------------
19:00 queuea 0 1
queueb 0 2
queued 0 4
------------------------------------------------------
20:00 queueb 0 5
queuec 0 1
queued 0 5
------------------------------------------------------
21:00 queuea 0 2
queueb 0 3
queuec 0 1
------------------------------------------------------
23:00 queued 0 1
------------------------------------------------------
Date: 24/10/2006
Time Queue Queued Running
-----------------------------------------------------
01:00 queuea 0 1
queuec 0 1
------------------------------------------------------
02:00 queueb 0 1
------------------------------------------------------
10:00 queuea 0 1
------------------------------------------------------
| [reply] [d/l] [select] |
|
I reworked your code to allow for any time periods (15mins, 30mins, 60mins, ...)
Chris
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $interval = shift || 60;
my %hash;
while( <DATA> ) {
my( $name, @times ) = split;
# convert the 3 times into their time slot.
# (eg) if the interval is 60 minutes (1 hour)
# a queued time of 9:26 would be converted to 9:00.
$_ -= $_ % ($interval * 60) for @times;
for (my $slot = $times[0]; $slot < $times[1]; $slot += $interval *
+ 60) {
$hash{ date($slot) }{ time_bin($slot) }{ $name }{queued}++;
}
for (my $slot = $times[1]; $slot < $times[2]; $slot += $interval *
+ 60) {
$hash{ date($slot) }{ time_bin($slot) }{ $name }{running}++;
}
}
{
DATE: foreach my $date ( sort keys %hash )
{
print_header( $date );
my $hour_hash = $hash{ $date };
HOUR: foreach my $hour ( sort keys %$hour_hash )
{
my $queue_hash = $hour_hash->{$hour};
my $string = '';
QUEUE: foreach my $queue ( sort keys %$queue_hash )
{
$string .= sprintf
" %6s %4d %4d\n",
$queue,
$queue_hash->{$queue}{'queued'}||0,
$queue_hash->{$queue}{'running'}||0;
}
# add the hour last to avoid a special case
substr( $string, 0, 5 ) = $hour;
print $string, "-" x 54, "\n";
}
}
}
sub time_bin
{
sprintf "%02d:%02d", (localtime( $_[0] ) )[2,1];
}
sub date
{
my @times = localtime( $_[0] );
$times[5] += 1900;
$times[4] += 1;
# join on / and make two digits for easy sorting
return join "/", map { sprintf "%02d", $_ } @times[3,4,5];
}
sub print_header
{
print <<"HERE";
Date: $_[0]
Time Queue Queued Running
------------------------------------------------------
HERE
}
| [reply] [d/l] |
|
Thank you so much, that is just what I need.
| [reply] |
|
Hi monks, I've been trying to understand the program in the above post, but there is a part that I just cannot understand. I can see that the program works, I just don't know how.
I cannot figure out how it knows when the queue is running a job, or queueing a job. I thought I would need to put some 'if statements' in there somewhere, otherwise how does it know, without conditionals.
Please excuse my ignorance, i'm new to programming and perl and trying to understand, how this works.
Could somebody try and explain to me how the hashes are being built with the correct information because to me, it looks like the times are not being compared so how does it know. Thanks.
| [reply] |
|
|