#!/usr/bin/awk -f # # $Id$ # ######################################################################## # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed # with this work for additional information regarding copyright # ownership. The ASF licenses this file to you under the Apache # License, Version 2.0 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # ######################################################################## # # SYNOPSIS # myname [bodyonly=0|1 logdir= version=] logs... # # VARIABLES: # bodyonly when non-zero, suppresses the tags # logdir # version stdcxx version (branch) to generate results for. # ######################################################################## BEGIN { # array of component counts for each section and component # compcnts [section, compname] # array of lists of component names for each section with # each list maintaining the same order as in the logs # sectcomponents [section] # map of [FILENAME,components] to component status # compstatuses [FILENAME, compcnts] sectnames [1] = "locale" sectnames [2] = "test" sectnames [3] = "example" # names of build stages buildstages [1] = "config" buildstages [2] = "lib" buildstages [3] = "examples" buildstages [4] = "bin" buildstages [5] = "tests" buildstages [6] = "runall" buildstages [7] = "total" # displayed and cout as failures states ["ASSERT"] = 1 states ["BUILD"] = 1 states ["COMP"] = 1 states ["DIFF"] = 1 states ["EXEC"] = 1 states ["FORMAT"] = 1 states ["EXIT"] = 1 states ["LINK"] = 1 states ["SIGNAL"] = 1 # displayed but don't cout as failures states ["OUTPUT"] = -1 states ["WARN"] = -1 # expected failures are displayed but not counted as failures states ["XASSERT"] = -1 states ["XBUILD"] = -1 states ["XCOMP"] = -1 states ["XDIFF"] = -1 states ["XEXEC"] = -1 states ["XFORMAT"] = -1 states ["XEXIT"] = -1 states ["XLINK"] = -1 states ["XPASS"] = -1 states ["XSIGNAL"] = -1 # not displayed and doesn't cout as a failure states ["MISS"] = 0 states ["OK"] = 0 # add all states/classes that count as failures to failclasses for (e in states) { if (1 == states [e]) failclasses [e] } # month numbers used to format dates monthnames ["Jan"] = 1 monthnames ["Feb"] = 2 monthnames ["Mar"] = 3 monthnames ["Apr"] = 4 monthnames ["May"] = 5 monthnames ["Jun"] = 6 monthnames ["Jul"] = 7 monthnames ["Aug"] = 8 monthnames ["Sep"] = 9 monthnames ["Oct"] = 10 monthnames ["Nov"] = 11 monthnames ["Dec"] = 12 # mapping from build type to the more descriptive build mode buildmodes ["8a"] = "shared archive, optimized" buildmodes ["8A"] = "shared archive, optimized, wide" buildmodes ["8d"] = "shared, optimized" buildmodes ["8D"] = "shared, optimized, wide" buildmodes ["8s"] = "archive, optimized" buildmodes ["8S"] = "archive, optimized, wide" buildmodes ["11a"] = "shared archive, debug" buildmodes ["11A"] = "shared archive, debug, wide" buildmodes ["11d"] = "shared, debug" buildmodes ["11D"] = "shared, debug, wide" buildmodes ["11s"] = "archive, debug" buildmodes ["11S"] = "archive, debug, wide" buildmodes ["12a"] = "shared archive, optimized, reentrant" buildmodes ["12A"] = "shared archive, optimized, reentrant, wide" buildmodes ["12d"] = "shared, optimized, reentrant" buildmodes ["12D"] = "shared, optimized, reentrant, wide" buildmodes ["12s"] = "archive, optimized, reentrant" buildmodes ["12S"] = "archive, optimized, reentrant, wide" buildmodes ["15a"] = "shared archive, debug, reentrant" buildmodes ["15A"] = "shared archive, debug, reentrant, wide" buildmodes ["15d"] = "shared, debug, reentrant" buildmodes ["15D"] = "shared, debug, reentrant, wide" buildmodes ["15s"] = "archive, debug, reentrant" buildmodes ["15S"] = "archive, debug, reentrant, wide" # regular expression to match a name (e.g., compiler or OS) re_name = "[A-Za-z][A-Za-z_0-9]*" # regular expression to match a version string (includes 0) re_version = "[0-9]+(\\.[0-9]+)*" # regular expression matching the buildtype string re_buildtype = "(8|11|12|15)[aAdDsS](-(solaris|win32))?" # regular expresssion matching a log file name re_logname = re_name "-" re_version \ "-" re_name "-" re_name "-" re_version \ "-" re_buildtype "-" "[1-9][0-9]*-log" # get today's date cmd = "LC_ALL=C date" cmd | getline todays_date close(cmd) # set the conversion format to two decimal places CONVFMT = "%.3g" # field separator character (not an awk variable) FSEP = "|" } # BEGIN ######################################################################## # detect the type of file 1 == FNR { if (svnpath == "") { # initialize svnpath using version (assume trunk by default) svnpath = "http://svn.apache.org/viewvc/stdcxx" if (version == "" || version == "trunk") svnpath = svnpath "/trunk" else svnpath = svnpath "/branches/" version } section = 0 if (0 == match(FILENAME, re_logname)) { # treat files whose names don't match the log file name pattern # as lists of expected failures expect_file = 1 } else { expect_file = 0 logsections [FILENAME] = 0 logcompcnts [1, FILENAME] = 0 logcompcnts [2, FILENAME] = 0 logcompcnts [3, FILENAME] = 0 ++logcount # append the current log file name to the list logfnames [logcount] = FILENAME } } # process file containing specification of expected failures 1 == expect_file && $1 ~ "^[^#][^#]" { if (1 == index($0, " ")) { # component specification continued from previous line cont = 1 } else { compname = $1 cont = 0 } pattern = $(2 - cont) status = $(3 - cont) comment = $(4 - cont) # convert shell globbing pattern to a regular expression by # escaping periods and replacing astersisks with ".*" and # question marks with "." gsub("\\.", "\\.", pattern) gsub("\\*", ".*", pattern) gsub("\\?", ".", pattern) # if patter contains an open brace expand it using the shell if (0 < index(pattern, "{")) { cmd = "echo " pattern cmd | getline pattern close(cmd) } # split the (potentially expanded) pattern into an array n = split(pattern, patlist, " ") spec = "" sep = "" # concatenate the array of expanded patters, the status, # and the comment, to form a single specification for (i = 1; i <= n; ++i) { spec = spec sep patlist [i] " " status " " comment sep = ":" } # insert the specification to the expected_statuses array if (compname in nexpected_statuses) spec = expected_statuses [compname] ":" spec expected_statuses [compname] = spec # skip the actions below next } ######################################################################## # logfile only processing below # extract operating system name and its version, and hardware # architecture (if possible) /^ *#+ *uname / { getline uname_output = $0 osname = $1 osver = "" osdesc = uname_output arch = "" archdesc = "" if (osname == "AIX") { # AIX 2 5 00CBEEBE4C00 osver = $4 "." $3 arch = "PowerPC" } else if (osname ~ "^CYGWIN") { # CYGWIN_NT-5.1 1.5.24(0.156/4/2) 2007-01-31 10:57 i686 Cygwin osname = "Cygwin" osver = substr($3, 1, index($3, "(") - 1) pos = match(uname_output, " i[2-6]86 ") if (0 < pos) { arch = substr(uname_output, pos + 1, 4) } else if (uname_output ~ " x86 ") { arch = "x86" } } else if (osname == "FreeBSD") { # osver = $3 } else if (osname == "HP-UX") { # HP-UX B.11.31 U ia64 3417177861 unlimited-user license # HP-UX B.11.23 U 9000/800 3952255646 unlimited-user license # HP-UX B.11.11 U 9000/800 1936254444 unlimited-user license osver = $3 arch = $5 } else if (osname == "IRIX64") { # IRIX64 6.5 04101930 IP27 osver = $3 arch = "MIPS" } else if (osname == "Linux") # Linux #1 SMP x86_64 x86_64 x86_64 GNU/Linux osver = "" else if (osname == "SunOS") { # SunOS Generic_118855-33 i86pc i386 i86pc # SunOS Generic_118833-33 sun4u sparc SUNW,Sun-Fire-V215 # SunOS Generic_117350-43 sun4u sparc SUNW,Sun-Fire-V240 osver = $3 if (0 < index($0, "sparc")) arch = "SPARC" else arch = "x86" } else if (osname == "OSF1") { # OSF1 V5.1 1885 alpha osver = $3 } logos [FILENAME] = osname " " osver FSEP osdesc FSEP arch FSEP archdesc } # extract Linux distro name and version /^ *#+ *cat *\/etc\/.*-release/ { getline if (1 == match($1, "^LSB_VERSION")) getline osname = "" osver = "" osdesc = $0 arch = "" archdesc = "" # Red Hat Enterprise Linux Server release 5 (Tikanga) # Red Hat Enterprise Linux AS release 4 (Nahant Update 4) # Red Hat Enterprise Linux AS release 4 (Nahant Update 2) # Red Hat Enterprise Linux AS release 3 (Taroon Update 8) # SUSE Linux Enterprise Server 10 (x86_64) # SUSE LINUX Enterprise Server 9 (x86_64) # remove the Red Hat code name including the release # and keep the distribution code name and update info: # RHEL 5: Tikanga (Update 1 through 2) # RHEL 4: Nahant (Update 1 through 6) # RHEL 3: Taroon (Update 1 through 9) # RHEL 2.1 AS: Pensacola # RHEL 2.1 ES: Panama if ("RedHat" == $1 $2) { if ("EnterpriseLinux" == $3 $4) { if ("AS" == $5) osname = "RHAS" else if ("ES" == $5) osname = "RHES" else if ("WS" == $5) osname = "RHWS" else osname = "RHEL" } else osname = "RHL" match($0, "release " re_version) if (0 < RSTART) osver = substr($0, RSTART + 8, RLENGTH - 8) match($0, "Update [1-9][0-9]*") if (0 < RSTART) osver = osver "." substr($0, RSTART + 7, RLENGTH - 7) else osver = osver ".0" } else if ($1 == "SUSE") { osname = "SLES" osver = $5 } logos [FILENAME] = osname " " osver FSEP osdesc FSEP arch FSEP archdesc } # extract x86 processor name and version /^ *#+ *cat *\/proc\/cpuinfo/ { arch = "" archdesc = "" # look for CPU manufacturer and other goodies in the contents # of /proc/cpuinfo do { getline if ($1 $2 $3 == "modelname:") { $1 = "" # model $2 = "" # name $3 = "" # : archdesc = $0 } if ($1 $2 == "arch:") { $1 = "" # arch $2 = "" # : arch = $0 } if ($1 $2 == "family:") { $1 = "" # family $2 = "" # : if (arch == "") arch = "IA64" archdesc = $0 } if (arch != "" && archdesc != "") break } while (0 < NF) # bail if no architecture could be determined if (arch == "" && archdesc == "") next # strip leading whitespace (result of assigning $N = "") archdesc = substr(archdesc, match(archdesc, "[A-Za-z]")) n = split(logos [FILENAME], platfields, FSEP) osname = platfields [1] osdesc = platfields [2] # arch = platfields [3] # archdesc = platfields [4] if (uname_output ~ " x86_64 ") { if (archdesc ~ "Intel\\(R\\)") arch = "EM64T" else if (archdesc ~ "AMD ") arch = "AMD64" else arch = "x86_64" } else if (uname_output ~ " ia64 ") { if (arch == "") arch = "IA64" } else if (arch == "") { pos = match(uname_output, " i[3456]86 ") if (0 < pos) arch = substr(uname_output, pos + 1, 4) else if (uname_output ~ " x86 ") arch = "x86" } logos [FILENAME] = osname FSEP osdesc FSEP arch FSEP archdesc } # extract processor architecture info on Windows /^PROCESSOR_IDENTIFIER=/ { n = split(logos [FILENAME], platfields, FSEP) osname = platfields [1] osdesc = platfields [2] arch = platfields [3] archdesc = substr($0, index($0, "=") + 1) if ("" == arch) arch = substr(archdesc, 1, index(archdesc, " ") - 1) logos [FILENAME] = osname FSEP osdesc FSEP arch FSEP archdesc } # extract the (POSIX) build date and time (date output) /^ *#+ *date *: *$/ { getline logdates [FILENAME] = $0 } # extract the Windows build date (date /T output) />date *\/T *$/ { getline logdates [FILENAME] = $0 } # extract compiler name and version /^configuring stdcxx / { cxxdesc = $5 pos = index(cxxdesc, "-") if (0 < pos) { cxxname = substr(cxxdesc, 1, pos - 1) cxxver = substr(cxxdesc, pos + 1) } else cxxname = cxxdesc if (cxxname == "aCC") cxxname = "HP aCC" else if (cxxname == "CC" && uname_output ~ "^IRIX64") cxxname = "SGI MIPSpro" else if (cxxname == "cxx" && uname_output ~ "^OSF1") cxxname = "HP C++" else if (cxxname == "eccp") cxxname = "EDG eccp" else if (cxxname == "icc") cxxname = "Intel C++" else if (cxxname ~ "^xlC") cxxname = "IBM XLC++" logos [FILENAME] = logos [FILENAME] FSEP cxxname " " cxxver FSEP cxxdesc } # extract compiler name and version (Visual Studio build) /^Configuring for / { cxxdesc = $3 pos = index(cxxdesc, "-") if (0 < pos) { cxxname = substr(cxxdesc, 1, pos - 1) cxxver = substr(cxxdesc, pos + 1) } else cxxname = cxxdesc if (cxxname == "msvc") cxxname = "MSVC" else if (cxxname = "icc") cxxname = "Intel C++" logos [FILENAME] = logos [FILENAME] FSEP cxxname " " cxxver FSEP cxxdesc } # extract compiler name and version (Visual Studio build) /^Selected compiler: / { $1 = "" $2 = "" cxxdesc = $0 if (cxxdesc ~ "Intel.*C++") { cxxname = "Intel C++" cxxver = $5 } else { cxxname = $1 " " $2 cxxver = $3 } logos [FILENAME] = logos [FILENAME] FSEP cxxname " " cxxver FSEP cxxdesc } # see if the library failed to configure or build (UNIX) /^g?make: \*\*\* \[(config|lib)\] Error/ { buildstatus [FILENAME] = "LIB" } # see if the library failed to configure or build (Windows) /.stdcxx - [1-9][0-9]* error(s), [1-9][0-9]* warning(s)/ { buildstatus [FILENAME] = "LIB" } # extract the real, user and system times for the children of the shell # that executed the commands from the log # the format of the output is: # # # with looking like: # [1-9][0-9]*m[1-9][0-9]s # and with being the output of the POSIX standard times # built-in utility, i.e., the first line giving the system and user times # for the shell and the second line giving the system and user times for # its children in the format: # "%dm%fs %dm%fs" # we don't care about the shell times, just the times for its children, # so we skip that line /^ *#+ real, user, system time \(/ { stage = substr($6, 2, index($6, ")") - 2); getline # real time times = $0 getline # ignore shell times getline # times for all children pos = index($0, " ") times = times FSEP substr($0, 1, pos - 1) times = times FSEP substr($0, pos + 1) # times is: FSEP FSEP logstagetimes [FILENAME, stage] = times } # extract the size of the library /^ *#+ ls -l/ { while (0 < NF) { size = $5 getline } libsizes [FILENAME] = size } # extract the full build size or the size after the clean target /^ *#+ *du -sk / { getline if (FILENAME in buildsizes) cleansizes [FILENAME] = $1 else buildsizes [FILENAME] = $1 } # count the number of (make) errors /^g?make: \*\*\* \[.*\] Error /{ ++logerrors [FILENAME] } # count the number of (Visual Studio) errors / - [1-9][0-9]* error\(s\), [1-9][0-9]* warning\(s\)/{ if (cxxname ~ "^MSVC") ++logerrors [FILENAME] } # count the number of warnings /[^A-Z_0-9](WARNING|[Ww]arning)[^A-Z_0-9]/ { # if the library hasn't been seen yet count this as a library warning if (!(FILENAME in libsizes)) ++libwarnings [FILENAME] else ++logwarnings [FILENAME] } # action at the beginning of component table /^NAME *STATUS WARN/ { start = 1 ++section ++logsections [FILENAME] logcompcnts [section, FILENAME] = 0 # skip this record next } # end of component table /^PROGRAM SUMMARY:$/ { start = 0 } 0 == start { # skip this record next } # component (locale, example, or test) section 1 == start { # store the name of the component compname = $1 # trim suffix from component name sub("(\\.bat|\\.exe|\\.sh)$", "", compname) # store the component status compstatus = $2 # the default expected status is empty (no record for it exists) expect = "" comment = "" # append the component name to the list of component names # for the current section if (0 == ((section, compname) in compcnts)) sectcomponents [section] = sectcomponents [section] " " compname # increment the number of times the current component occurs # in the current section across all logs ++compcnts [section, compname] # increment the number of components in the current section # and log ++logcompcnts [section, FILENAME] # if appropriate, increase the maximum number of components # across all logs if (sectmaxcompcnts [section] < logcompcnts [section, FILENAME]) sectmaxcompcnts [section] = logcompcnts [section, FILENAME] # look up the component's name in the array of components each # with a record of the platform(s) and the expecred status of # the component on the platform(s), something like # "aix-.*-ppc-.*-.*-12{d,D} SEGV STDCXX-123" # ":linux.*-.*-gcc ABRT STDCXX-345" # ^ ^ ^ # | | | # | | +-- required comment (issue) # | +-- expected component status # +-- platform matching ERE pattern if (compname in expected_statuses) expspec = expected_statuses [compname] else expspec = "" # split the list of platforms/expected statuses into an array # with one element for each status and a pattern matching one # or more platforms n = split(expspec, slist, ":") for (i = 1; i <= n; ++i) { # get the platform matching pattern, expected status, and # the required comment split(slist [i], fields, " ") # try to match the log file name against the specified pattern if (match(FILENAME, fields [1])) { # extract the expected component status and the comment expect = fields [2] comment = fields [3] break } } # class (determins the color of the cell), value (the text displayed # in the cell), and the optional detail for the cell class = "" value = "" detail = "" # compstatus: # :[]:[] if (0 == compstatus) { # successful exit status: component built but may have failed # assertions or runtime warnings class = "OK" if (3 != section) { # locales and tests but not examples runwarns = $3 # number of runtime warnings asserts = $4 # number of assertions tried failed = $5 # number of failed assertions if (0 < failed) { # non-zero number of assertions class = "ASSERT" value = failed detail = asserts } else if (0 < runwarns) { # non-zero runtime warnings class = "RUNWARN" value = "(" runwarns ")" } } if (expect != "") { if ("OK" == class && expect != class) { # unexpected success class = "XPASS" value = "XPASS
(X" expect ")" detail = "unexpected success" } else if ("OK" != class) { # expected status doesn't match ++xmatchcounts [section, FILENAME] value = value "
" expect } } } else if (0 < compstatus && compstatus < 256) { # non-zero exit status class = "EXIT" value = compstatus if (expect != "") { if (expect == value) { # actual exit status matches the expected status ++xfailcounts [section, FILENAME] class = "X" class } else { ++xmatchcounts [section, FILENAME] value = value "
(X" expect ")" detail = "expected failure doesn't match actual status" } } } else if ( "COMP" == compstatus \ || "DIFF" == compstatus \ || "FORMAT" == compstatus \ || "LINK" == compstatus \ || "NOUT" == compstatus \ || "OUTPUT" == compstatus) { # DIFF unexpected (example) output # FORMAT unexpected (test) output format # NOUT no (test) output # OUTPUT no (example) master output file class = compstatus if (expect != "") { if (expect == class) { # actual status matches expected status ++xfailcounts [section, FILENAME] class = "X" class } else { # actual status doesn't match expected status ++xmatchcounts [section, FILENAME] value = class "
(X" expect ")" detail = "expected failure doesn't match actual status" } } } else { # signal class = "SIGNAL" value = compstatus if (expect != "") { if (expect == value) { # received signal matches the expected signal ++xfailcounts [section, FILENAME] # prepend "X" to the class/value to indicate that # the signal was expected class = "X" class value = "X" value } else { # received signal doesn't match expected status ++xmatchcounts [section, FILENAME] value = value "
(X" expect ")" detail = "expected failure doesn't match actual status" } } } compstatus = class ":" value ":" detail compstatuses [section, FILENAME, compname] = compstatus } # locale section 1 == section && 1 == start { } # test section 2 == section && 1 == start { } # example section 3 == section && 1 == start { } ######################################################################## # functions function get_date(fulldate) { n = split(fulldate, fields) if (2 == n) { # assume Windows 'date /T' format (i.e., "AbWeekDay MM/DD/YYYY") date = fields [2] split(date, fields, "/") date = (0 + fields [1]) "/" (0 + fields [2]) } else if (2 < n) { # assume POSIX standard 'date' format in the "C" locale # i.e., "AbWeekDay AbMon D HH:MM:SS $TZ YYYY" month = fields [2] mday = fields [3] date = monthnames [month] "/" mday } else date = "N/A" return date } function get_time(fulldate) { split(fulldate, fields) return fields [4] } # extracts operating system name and version from the log file name function get_osname(fname) { # strip directory prefix from filename pos = match(fname, ".*/") if (0 < pos) fname = substr(fname, RLENGTH + 1) # strip anything after the first dash pos = match(fname, "-") if (0 == pos) return "" osname = substr(fname, 1, pos - 1) # TO DO: extract version here return osname } # extracts the build type from the log file name function get_buildtype(fname) { # look for the beginning of the buildtype component followed # by the (Subversion) revision number pos = match(fname, "-(8|11|12|15)[aAdDsS]-[1-9][0-9]*-log") # is not found, try looking for the buildtype followed by # the name of the threads library and only then followed # by the (Subversion) revision number if (0 == pos) pos = match(fname, "-(8|11|12|15)[aAdDsS]-[a-z][a-z_0-9]*-[1-9][0-9]*-log*") buildtype = substr(fname, pos + 1) pos = index(buildtype, "-") buildtype = substr(buildtype, 1, pos - 1) return buildtype } function get_dispname(section, compname) { dir = "" if (1 == section) { # compose a URL pointing to the character set description # file and the locale defintion file in the repository pos = index(compname, ".") if (0 < pos) { locale = substr(compname, 1, pos - 1) codeset = substr(compname, pos + 1); url = svnpath "/etc/nls/src/" locale "?view=markup" dispname = "" locale "" url = svnpath "/etc/nls/charmaps/" codeset "?view=markup" dispname = dispname "." codeset "" } else { dispname = compname } } else if (2 == section) { dir = "tests" if (match(compname, "\\.stdcxx-")) dir = dir "/regress" else if (match(compname, "^0\\.")) dir = dir "/self" else if (match(compname, "^17\\.")) dir = dir "/intro" else if (match(compname, "^18\\.")) dir = dir "/support" else if (match(compname, "^19\\.")) dir = dir "/diagnostics" else if (match(compname, "^20\\.")) dir = dir "/utilities" else if (match(compname, "^21\\.")) dir = dir "/strings" else if (match(compname, "^22\\.")) dir = dir "/localization" else if (match(compname, "^23\\.")) dir = dir "/containers" else if (match(compname, "^24\\.")) dir = dir "/iterators" else if (match(compname, "^25\\.")) dir = dir "/algorithm" else if (match(compname, "^26\\.")) dir = dir "/numerics" else if (match(compname, "^27\\.")) dir = dir "/iostream" else if (match(compname, "^d_")) ; # dir = dir "/depr" else dir = "" if (dir != "") { dispname = "" dispname = dispname compname "" } else { dispname = compname } } else { dispname = compname } return dispname } # prints a row of columns for the given section and component function print_component(section, compname) { # increment for each component, regardless of whether it gets # included in the output or not ++compinx row = "" # the number of failures and warning states of the current # component across all logs to decide whether to include # the component in the output or not nfailures = 0 nwarnings = 0 # maximum number of assertions exercised by the current # test across all logs maxasserts = 0 # the number of columns to span the same class/value repeat = 1 last_class = "" last_value = "" last_title = "" # iterate over all log files for (i = 1; i <= logcount; ++i) { # only process the specified section # if (section != substr(fi, 1, 1)) # continue # extract the name of the log file from the key # fname = substr(fi, 3) fname = logfnames [i] # check to see if the component was found in the current # log file being careful not to add a new entry to the # array if ((section, fname, compname) in compstatuses) { # component found status = compstatuses [section, fname, compname] n = split(status, triple, ":") class = triple [1] value = "" == triple [2] ? class : triple [2] title = triple [3] if ("ASSERT" == class) { if (0 < value) { title = "failed " value " out of " \ triple [3] " assertions" } else title = "" if (maxasserts < triple [3]) maxasserts = triple [3] } } else { # component missing from log file class = "MISS" title = "not tested" value = "N/A" } if (class in failclasses) { ++nfailures ++logcompfails [fname] } else if (class != "OK" && class != "MISS") { ++nwarnings ++logcompwarns [fname] } if ("" == last_class) { last_class = class last_title = title last_value = value } else if ( last_class == class \ && last_value == value \ && last_title == title) { ++repeat } else { row = row " " last_value "\n" repeat = 1 last_class = class last_title = title last_value = value } ++statuscnts [fname, class] } row = row " " last_value "" repeat = 0 if (0 < nfailures || nwarnings) { # increment only for components included in the output ++rowinx dispname = get_dispname(section, compname) print " " print " " compinx "" print " " dispname "" if (2 == section) print " " maxasserts "" print row print " " return 1 } return 0 } # prints a table for each of the three sections (examples, locales, # and tests) function print_section(section) { # the name of this section ("example", "locale", or "test") sectname = sectnames [section] if (0 == sectmaxcompcnts [section]) { print print " " print "

No " sectname "s found in " logcount " logs

" return } # create the table header roughly in the following format: # # | ### | component | 1 | 2 | 3 | 4 | 5 | 6 | ... | 16 | # | | name | 8d | 8D | 8s | 8S | 11d | 11D | ... | 15S | # | | | date | date | ... | date| thead = " \n" thead = thead " \n" thead = thead " ###\n" thead = thead " " thead = thead sectname " name\n" if (2 == section) { # for tests only, insert a column at offset 2 with the maximum # number of assertions found in the test on the given row across # all build logs thead = thead " " thead = thead "max
asserts\n" } row0 = "" row1 = " \n" row2 = " \n" colnos = "" lastdate = "" # date (M/d) of the last log lastfull = "" # full date and time of the last log datespan = 0 # number of same consecutive dates # iterate over the array of section counts for each log file # and compose the column headers for each log for (i = 1; i <= logcount; ++i) { logname = logfnames [i] # strip directory prefix from file name loghref = get_gzlogfname(logname) colnos = colnos " " colnos = colnos "" i "" buildtype = get_buildtype(logname) buildmode = buildmodes [buildtype] row1 = row1 " " buildtype "\n" if (logname in logdates) { # parse the date and time from the date extracted # from the log fulldate = logdates [logname] date = get_date(fulldate) time = get_time(fulldate) } else { # date not available fulldate = "unknown date" date = "N/A" } if (0 == datespan) { # first iteration lastdate = date lastfull = fulldate datespan = 1 } else if (date == lastdate) { # increment the span of the last seen date ++datespan } else { row2 = row2 " " lastdate "\n" else row2 = row2 " title=\"" lastfull "\">" lastdate "\n" lastdate = date lastfull = fulldate datespan = 1 } } # append the date of last set of logs row2 = row2 " " lastdate "\n" else row2 = row2 " title=\"" lastfull "\">" lastdate "\n" row0 = row0 colnos "\n \n" row1 = row1 " \n" row2 = row2 " \n" thead = thead row0 row1 row2 " " print " " print "

Results of " sectmaxcompcnts [section] " " \ sectname "s from " logcount " logs

" print " " print thead print " " # reset the arrays split("", logcompwarns) split("", logcompfails) split("", statuscnts) # iterate over elements of the compcnts array using the section # number and the name of the comoponent as the key (index) if (2 == section) colspan = " colspan=2" else colspan = "" # one-based component index (of all found) # not every component makes it into the table compinx = 0 # one-based row index (of all rows printed) rowinx = 1 # split the list of components in the current section into an array # (the list of component names is in the same order as in the log) compcount = split(sectcomponents [section], components, " ") # iterate over the array for (ci = 1; ci <= compcount; ++ci) { compname = components [ci] # determine whether the current component should be included # in output or not and if so, print it out printed = print_component(section, compname) if (printed && (rowinx % 20) == 0) { print " " print " " print " " print colnos print " " } } print " " # print totals in the table footer print " " ################################################################## ### print column headers again print " " print " " print " " print colnos print " " ################################################################## ### print totals for each interesting status (class) print " " print " " print " status" print " " print " " for (si in states) { row = " \n" row = row " \n" row = row " \n" nfails = 0 # the number of times the same value consecutively repeats repeat = 1 last_value = "?" for (i = 1; i <= logcount; ++i) { fname = logfnames [i] if ((fname, si) in statuscnts) { ++nfails value = statuscnts [fname, si] } else value = "" if ("?" == last_value) last_value = value else if (value == last_value) ++repeat else { row = row " \n" last_value = value repeat = 1 } } if (0 < nfails) { row = row " \n" print row " " } } ################################################################## # print number of expected failures row = "" nfails = 0 # the number of times the same value consecutively repeats repeat = 1 last_value = "?" for (i = 1; i <= logcount; ++i) { fname = logfnames [i] if ((section, fname) in xfailcounts) { ++nfails value = xfailcounts [section, fname] } else value = "" if ("?" == last_value) last_value = value else if (value == last_value) ++repeat else { row = row " \n" last_value = value repeat = 1 } } if (0 < nfails) { row = row " \n" print " " print " " print " " print row " " } ################################################################## # print expected/unexpected mismatches row = "" nfails = 0 # the number of times the same value consecutively repeats repeat = 1 last_value = "?" for (i = 1; i <= logcount; ++i) { fname = logfnames [i] if ((section, fname) in xmatchcounts) { ++nfails value = xmatchcounts [section, fname] } else value = "" if ("?" == last_value) last_value = value else if (value == last_value) ++repeat else { row = row " \n" last_value = value repeat = 1 } } if (0 < nfails) { row = row " \n" print " " print " " print " " print row " " } ################################################################## # print total number of failures row = "" nfails = 0 # the number of times the same value consecutively repeats repeat = 1 last_value = "?" for (i = 1; i <= logcount; ++i) { fname = logfnames [i] if (fname in logcompfails) { ++nfails value = logcompfails [fname] } else value = "" if ("?" == last_value) last_value = value else if (value == last_value) ++repeat else { row = row " \n" last_value = value repeat = 1 } } if (0 < nfails) { row = row " \n" print " " print " " print " " print row " " } ################################################################## # print total number of components exercised row = "" nfails = 0 # the number of times the same value consecutively repeats repeat = 1 last_value = "?" for (i = 1; i <= logcount; ++i) { fname = logfnames [i] if ((section, fname) in logcompcnts) { ++nfails value = logcompcnts [section, fname] } else value = "" if ("?" == last_value) last_value = value else if (value == last_value) ++repeat else { row = row " \n" last_value = value repeat = 1 } } if (0 < nfails) { row = row " \n" print " " print " " print " " print row " " } ################################################################## print " " print "
column number and log
column number and log
totals for status
" si "" last_value "" last_value "
" last_value "" last_value "
expected failures
" last_value "" last_value "
expected/actual mismatches
" last_value "" last_value "
failures
" last_value "" last_value "
total
" } function format_size(size) { if (1000000000 <= size) return size / 1073741824.0 " GB" if (1000000 <= size) return size / 1048576.0 " MB " if (1000 <= size) return size / 1024 " kB" if (0 < size) return size " B" return size } function get_gzlogfname(fname) { # strip directory prefix from file name pos = match(fname, ".*/") if (0 < pos) fref = substr(fname, RLENGTH + 1) else fref = fname # replace the temporary PID suffix with ".gz" pos = match(fref, "\\.[1-9][0-9]*$") if (0 < pos) fref = substr(fref, 1, pos - 1) # replace the trailing .txt suffix with .gz.txt sub("\\.txt$", ".gz.txt", fref) return "logs/" fref } function print_logtable() { thead = \ " \n" \ " \n" \ " " \ "log\n" \ " operating
system\n" \ " " \ "arch\n" \ " compiler\n" \ " build
type\n" \ " start date and time\n" \ " " \ "age\n" \ " revision\n" \ " sizes\n" \ " diagnostics\n" \ " \n" \ " \n" \ " \n" \ " " \ "library\n" \ " log\n" \ " build\n" \ " " \ "errors\n" \ " " \ "warnings\n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " gzip\n" \ " text\n" \ " full\n" \ " clean\n" \ " lib\n" \ " other\n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " " print "

Logs and Columns

" print " " print thead print " " for (i = 1; i <= logcount; ++i) { fname = logfnames [i] n = split(logos [fname], platfields, FSEP) osname = platfields [1] osdesc = platfields [2] arch = platfields [3] archdesc = platfields [4] cxxname = platfields [5] cxxdesc = platfields [6] if (fname in buildstatus) print " " else print " " # strip directory prefix from file name loghref = get_gzlogfname(fname) print " " ################################################################ # extract and format the operating system name and version oscell = "" osname"" ################################################################ # extract and format the hardware architecture archcell = "" arch "" ################################################################ # extract and format the compiler and version cxxcell = "" cxxname "" print " " oscell print " " archcell print " " cxxcell ################################################################ # extract build type from log file name buildtype = get_buildtype(fname) buildmode = buildmodes [buildtype] print " " print " " # compute and format the age of the build duration = "duration -f \"" logdates [fname] \ "\" \"" todays_date "\"" duration | getline fullage close(duration) pos = index(fullage, ", ") buildage = substr(fullage, 1, pos - 1) print " " pos = match(fname, "-[1-9][0-9]*-log") buildrev = substr(fname, pos + 1, RLENGTH - 5) ################################################################ # format a ViewVC URL to the revision number/log revurl = "http://svn.apache.org/viewvc?view=rev&rev=" buildrev print " " ################################################################ # library size fullsize = fname in libsizes ? libsizes [fname] : "" size = format_size(libsizes [fname]) print " " print " " ################################################################ # format the size of the expanded log file cmd = "du -k " fname cmd | getline close(cmd) fullsize = $1 size = format_size(fullsize * 1024) print " " ################################################################ # compute the full build size fullsize = fname in buildsizes ? buildsizes [fname] : "" size = format_size(fullsize * 1024) print " " ################################################################ # format the build size after the clean target has been run fullsize = fname in cleansizes ? cleansizes [fname] : "" size = format_size(fullsize * 1024) print " " print " " print " " print " " print " " } print " " print " " print " " print "
" i "" buildtype "" logdates [fname] "" buildage "" buildrev "" size "" gzlogsize "" size "" size "" size "" logerrors [fname] "" libwarnings [fname] "" logwarnings [fname] "
" } # reformat time string argument in the original format of "NmN.NNNs" # (i.e., as produced by the times shell utility), as "M:SS" rounding # fractional seconds as necessary function format_time(timestr) { pos = index(timestr, "m") mins = substr(timestr, 1, pos - 1) secs = substr(timestr, pos + 1) secs = substr(secs, 1, length(secs) - 1) timestr = mins ":" if (int(secs) < 10) timestr = timestr "0" timestr = timestr int(secs) return timestr } function print_timingstable() { thead = \ "\n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" \ " \n" print "

Timings

" print "
" \ "logbuild
type
build and run times (M:SS)
" \ "config" \ "library" \ "examples" \ "utilities" \ "tests" \ "run times" \ "total
realusersysrealusersysrealusersysrealusersysrealusersysrealusersysrealusersys
" print thead print " " for (i = 1; i <= logcount; ++i) { fname = logfnames [i] if (fname in buildstatus) print " " else print " " # strip directory prefix from file name loghref = get_gzlogfname(fname) print " " buildtype = get_buildtype(fname) print " " timecells = "" for (j = 1; j in buildstages; ++j) { stage = buildstages [j]; if ((fname, stage) in logstagetimes) { # format real, user, and system times for the stage timestr = logstagetimes [fname, stage] split(timestr, atimes, FSEP) realtim = format_time(atimes [1]) usrtim = format_time(atimes [2]) systim = format_time(atimes [3]) # highlight total times in bold if ("total" == stage) { pfx = "" sfx = "" } else { pfx = "" sfx = "" } timecells = timecells "" timecells = timecells "" timecells = timecells "" } else { timecells = timecells "" } } print timecells "" } print " " print " " print " " print "
" i "" buildtype "" pfx realtim sfx "" pfx usrtim sfx "" pfx systim sfx "
" } END { if (0 == bodyonly) { print "" print " " print " " print " " print " " } print_logtable() print_timingstable() for (section = 1; section <= 3; ++section) print_section(section) if (0 == bodyonly) { print " " print "" } }