The CGI script edademo.cgi
This is the most complex piece of the demo. It is also the least necessary, given that we have already covered all pieces necessary to efficietly completing a FlowTracer based design using the CLI and the GUI.
Let's start from the main part of the code, which looks quite similar to the CGI scripts that we have already seen in the CGI tutorial. In bold, you can notice the parsing of QUERY_STRING, which is needed to determine which page to display, based on the values of the "user" and "action" variables.
#!/bin/csh -f
# The rest is -*- Tcl -*- \
exec vovsh -t $0 $*
## Definition of all procedures
################################# MAIN CODE
VOVHTML_START
set listOfUnits {}
set listOfSteps { synth place route sta drc lvs }
set listOfUsers {}
set results() "Initialization of results array"
set opt(reload) 0
set opt(user) ""
set opt(mode) ""
set opt(action) "summary"
foreach option [split $env(QUERY_STRING) &] {
if [regexp {(.*)=(.*)} $option all var value] {
set var [string tolower $var]
set opt($var) [url_decode $value]
}
}
switch $opt(action) {
"job" {
showJobReport $opt(id)
}
"user" {
getResultsJobs $opt(user)
getResultsArea $opt(user)
getResultsTiming $opt(user)
showUserReport $opt(user) $opt(mode) $opt(reload)
}
default {
showProjectSummary $opt(reload)
}
}
VOVHTML_FINISH
getResultsArea
In the procedure getResultsArea we search the trace database for files that contain area information, which in our case are files with a suffix area.rpt. We create a temporary set of all such files (with vtk_set_create), and then we get all elements in the set (with vtk_set_get_elements). We look inside each of the files (with source $namex) and store the area information in the results array, taking care of flagging whether the data up-to-date or not, by looking at the status (@STATUS@) of the report file. Finally, we cleanup by forgetting the temporary set.
proc getResultsArea { userToReport } {
global results
set setName "@@@:tmp:grarp[pid]"
set setRule "isfile name~/$userToReport/.*area.rpt$"
set setId [vtk_set_create $setName $setRule]
foreach fileInfo [vtk_set_get_elements $setId "@STATUS@ @NAME@"] {
set status [shift fileInfo]
set name [shift fileInfo]
set namex [vtk_path_expand $name]
if [file exists $namex] {
set unit [file root [file root [file tail $namex]]]
catch {source $namex}
set results($unit,area,status) $status
}
}
vtk_set_forget $setId
}
getResultsJobs
In the procedure getResultsJobs we query the trace database for information about the status, duration, etc. about each of the CDT jobs in the flow. We store the information in the results array.
First we get a list of all the sets in the trace (with vtk_trace_list_sets). We are interested only in the sets with name beginning with "CDT:". We get the elements of each set (with vtk_set_find and vtk_set_get_elements).
proc getResultsJobs { userToReport } {
global results
global listOfUnits
global listOfUsers
foreach setName [vtk_trace_list_sets] {
# puts '$setName'
if [regexp {^CDT:(.*):unit:([^:]+)$} $setName all user unit] {
lappend_no_dup listOfUnits $unit
lappend_no_dup listOfUsers $user
if { $user != $userToReport } continue
set setId [vtk_set_find $setName]
set results($unit,setId) $setId
foreach jobInfo [vtk_set_get_elements $setId "@ID@ @STATUS@ @COMMAND@"] {
set id [shift jobInfo]
set st [shift jobInfo]
set tool [lindex $jobInfo 1]
if { $tool == "cdt" } {
set step [lindex $jobInfo 2]
set results($unit,$step,id) $id
set results($unit,$step,st) $st
}
}
}
if [regexp {^CDT:(.*):step:([^:]+)$} $setName all user step] {
if { $user != $userToReport } continue
set setId [vtk_set_find $setName]
set results(step,$step,setId) $setId
}
}
set listOfUnits [lsort $listOfUnits]
set listOfUsers [lsort $listOfUsers]
}
Page Layout
- title, which is the title of the page
- reloadMs, the value in milliseconds of the auto-reload period
- menu_script, a script to customize the menu on the left hand side of the page
- body_script, a script with the actual content of the page
The scripts are evaluated using the Tcl command uplevel.
proc EDADEMOPAGE { title reloadMs menu_script body_script } {
global env
HTML {
HEAD { omitted }
BODY {
TABLE CELLSPACING=0 CELLPADDING=6 BORDER=0 WIDTH="100%" {
TR BGCOLOR="white" {
omitted title code
}
TR {
TD BGCOLOR="$bgColor" VALIGN=TOP {
HREF "/cgi/edademo.cgi" "Summary"; BR
if { $menu_script != {} } {
uplevel $menu_script
}
}
TD VALIGN=TOP COLSPAN=2 BGCOLOR="#BBCCBB" {
uplevel $body_script
}
}
}
}
}
}
Following is a collection of procedure used to render the data in HTML. Note the use of vtk_time_pp to print durations in a human readable form and of the global array vov_color() to colorize the cells in the tables according to the status of the node they represent.
proc showStepInfo { unit step displayMode } {
global results
global vov_color
set st [getResult $unit,$step,st EMPTY]
if { $st == "EMPTY" } {
TD {}
TD {}
TD {}
return
}
set du [getResult $unit,$step,du n/a]
set id [getResult $unit,$step,id 0 ]
set ag [getResult $unit,$step,ag 0 ]
set url "/cgi/edademo.cgi?action=job&id=$id"
if { $du >= 0 } {
set tim [vtk_time_pp $du]
} else {
set tim [vtk_time_pp $ag]
}
if { $displayMode == "simple" } {
TD ALIGN="right" COLSPAN="2" { SMALL { HREF $url $tim } }
TD BGCOLOR=$vov_color($st) { OUT " " }
} else {
TD ALIGN="right" { SMALL { HREF $url $tim } }
TD ALIGN="center" { SMALL { HREF $url [string tolower $st] } }
TD BGCOLOR=$vov_color($st) { OUT " " }
}
}
proc showResults { user { displayMode "simple"} } {
global results
global vov_color
global listOfUnits
global listOfSteps
TABLE BORDER="0" CELLSPACING="2" CELLPADDING="5" {
TR BGCOLOR="white" {
TH COLSPAN=2 { OUT "Unit" }
TH { OUT "Area" }
TH { OUT "Slack" }
foreach step $listOfSteps {
set setId [getResult step,$step,setId 0]
TH COLSPAN=3 {
if { $setId == 0 } {
OUT "$step"
} else {
HREF "/set?id=$setId&action=showgrid" $step
if { $displayMode != "simple" } {
BR
SMALL {
omitted: some links
}
}
}
}
}
}
set count 0
foreach unit $listOfUnits {
set setName "CDT:$user:unit:$unit"
set setId [vtk_set_find $setName]
if { $setId != 0 } {
set area [getResult $unit,area "n/a"]
set areaSt [getResult $unit,area,status "INVALID"]
set slack [getResult $unit,slack ""]
set slackSt [getResult $unit,slack,status "INVALID"]
TR {
TD ALIGN="RIGHT" { OUT [incr count] }
TH ALIGN="LEFT" { HREF "/set?id=$setId" $unit }
TD ALIGN=RIGHT BGCOLOR=$vov_color($areaSt) {
COLOR $vov_color($areaSt,fg) $area
}
TH ALIGN=RIGHT BGCOLOR=$vov_color($slackSt) {
if { $slack != "" } {
if { $slack %lt; 0 } {
COLOR "#FFFF88" "($slack)"
} else {
COLOR $vov_color($slackSt,fg) $slack
}
}
}
foreach step $listOfSteps {
showStepInfo $unit $step $displayMode
}
}
}
}
}
}
proc showUserSummary { user setId } {
global vov_color
if { $setId == 0 } {
set status EMPTY
set nodes 0
set places 0
} else {
set setInfo [vtk_set_statistics $setId]
set saveSetInfo $setInfo
set status [shift setInfo]
set nodes [shift setInfo]
set places [shift setInfo]
set jobs [shift setInfo]
set duration [shift setInfo]
set unknown [shift setInfo]
set placeStats [shift setInfo]
set jobStats [shift setInfo]
set statusList { INVALID RUNNING VALID FAILED }
foreach s $statusList { set js($s) 0 }
foreach { s n } $jobStats {
set js($s) $n
}
TR {
TH { print user name }
TD ALIGN="RIGHT" { OUT [vtk_time_pp $duration] }
TD ALIGN="RIGHT" { OUT $jobs }
foreach s $statusList {
omitted: show colored ball
}
}
}
}
showProjectSummary
The showProjectSummary procedure displays the summary page. First we get the list of users of the project (really the list of workspaces) by looking at the sets with name beginning with "CDT:", and then we call showUserSummary on each.
proc showProjectSummary { reloadMs } {
set listOfUsers {}
foreach setName [vtk_trace_list_sets] {
if [regexp {CDT:(.*):step} $setName all user] {
lappend_no_dup listOfUsers $user
}
}
set listOfUsers [lsort $listOfUsers]
EDADEMOPAGE "Project Summary $env(PROJECT)" $reloadMs {
omitted
} {
TABLE WIDTH="100%" border=0 CELLPADDING=10 {
TR BGCOLOR="#DDDDFF" {
foreach head {
Workspace Duration Jobs Invalid
Running Valid Failed Actions
} {
TH { OUT $head }
}
foreach user $listOfUsers {
showUserSummary $user [vtk_set_find "CDT:$user"]
}
}
TR BGCOLOR="#DDDDFF" {
TD COLSPAN=9 { OUT "Totals" }
}
showUserSummary "" [vtk_set_find "System:nodes"]
}
}
}
showUserReport
The procedure showUserReport generates the page showing the jobs in a user workspace. Notice the use of EDADEMOPAGE and showResults, which have been explained above.
proc showUserReport { user mode reloadMs } {
global argv
EDADEMOPAGE "EDA-Demo Report Workspace $user" $reloadMs {
if { $mode != "hlf" && $mode != "llf" } {
omitted: autoreload control
}
showMenu $user $mode
} {
switch $mode {
"llf" { showLowLevelFlow "$user" }
default { showResults $use }
}
}
}