Index: api.scm ================================================================== --- api.scm +++ api.scm @@ -66,11 +66,12 @@ delete-test-records delete-old-deleted-test-records test-set-status-state test-set-top-process-pid roll-up-pass-fail-counts - update-fail-pass-counts + update-pass-fail-counts + top-test-set-per-pf-counts ;; (db:top-test-set-per-pf-counts (db:get-db *db* 5) 5 "runfirst") ;; RUNS register-run set-tests-state-status delete-run @@ -133,10 +134,11 @@ ((delete-old-deleted-test-records) (apply db:delete-old-deleted-test-records dbstruct params)) ((test-set-status-state) (apply db:test-set-status-state dbstruct params)) ((test-set-top-process-pid) (apply db:test-set-top-process-pid dbstruct params)) ((roll-up-pass-fail-counts) (apply db:roll-up-pass-fail-counts dbstruct params)) ((update-pass-fail-counts) (apply db:general-call dbstruct 'update-pass-fail-counts params)) + ((top-test-set-per-pf-counts) (apply db:top-test-set-per-pf-counts dbstruct params)) ((test-set-archive-block-id) (apply db:test-set-archive-block-id dbstruct params)) ;; RUNS ((register-run) (apply db:register-run dbstruct params)) ((set-tests-state-status) (apply db:set-tests-state-status dbstruct params)) Index: archive.scm ================================================================== --- archive.scm +++ archive.scm @@ -7,11 +7,11 @@ ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') -(use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking format md5 message-digest) +(use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking format md5 message-digest srfi-18) (import (prefix sqlite3 sqlite3:)) (declare (unit archive)) (declare (uses db)) (declare (uses common)) @@ -99,11 +99,11 @@ ;; 1. create the bup dir if not exists ;; 2. start the du of each directory ;; 3. gen index ;; 4. save ;; -(define (archive:run-bup archive-command run-id run-name tests) +(define (archive:run-bup archive-command run-id run-name tests rp-mutex bup-mutex) ;; move the getting of archive space down into the below block so that a single run can ;; allocate as needed should a disk fill up ;; (let* ((min-space (string->number (or (configf:lookup *configdat* "archive" "minspace") "1000"))) (archive-info (archive:allocate-new-archive-block *toppath* (common:get-testsuite-name) min-space)) @@ -136,33 +136,39 @@ (toplevel/children (and (db:test-get-is-toplevel test-dat) (> (rmt:test-toplevel-num-items run-id test-name) 0))) (test-partial-path (conc target "/" run-name "/" (db:test-make-full-name test-name item-path))) ;; note the trailing slash to get the dir inspite of it being a link (test-path (conc linktree "/" test-partial-path)) - (test-physical-path (if (file-exists? test-path) (read-symbolic-link test-path #t) #f)) + (mutex-lock! rp-mutex) + (test-physical-path (if (file-exists? test-path) + (common:real-path test-path) + #f)) + (mutex-unlock! rp-mutex) (partial-path-index (if test-physical-path (substring-index test-partial-path test-physical-path) #f)) (test-base (if (and partial-path-index test-physical-path ) (substring test-physical-path 0 partial-path-index) #f))) - (if (or toplevel/children - (not (file-exists? test-path))) - #f - (begin - (debug:print 0 - "From test-dat=" test-dat " derived the following:\n" - "test-partial-path = " test-partial-path "\n" - "test-path = " test-path "\n" - "test-physical-path = " test-physical-path "\n" - "partial-path-index = " partial-path-index "\n" - "test-base = " test-base) - (hash-table-set! disk-groups test-base (cons test-physical-path (hash-table-ref/default disk-groups test-base '()))) - (hash-table-set! test-groups test-base (cons test-dat (hash-table-ref/default test-groups test-base '()))) - test-path)))) + (cond + (toplevel/children + (debug:print 0 "WARNING: cannot archive " test-name " with id " test-id " as it is a toplevel test with children")) + ((not (file-exists? test-path)) + (debug:print 0 "WARNING: Cannot archive " test-name "/" item-path " as path " test-path " does not exist")) + (else + (debug:print 0 + "From test-dat=" test-dat " derived the following:\n" + "test-partial-path = " test-partial-path "\n" + "test-path = " test-path "\n" + "test-physical-path = " test-physical-path "\n" + "partial-path-index = " partial-path-index "\n" + "test-base = " test-base) + (hash-table-set! disk-groups test-base (cons test-physical-path (hash-table-ref/default disk-groups test-base '()))) + (hash-table-set! test-groups test-base (cons test-dat (hash-table-ref/default test-groups test-base '()))) + test-path)))) tests) ;; for each disk-group (for-each (lambda (disk-group) (debug:print 0 "Processing disk-group " disk-group) @@ -180,15 +186,20 @@ (create-directory archive-dir #t)) (if (not (file-exists? (conc archive-dir "/HEAD"))) (begin ;; replace this with jobrunner stuff enventually (debug:print-info 0 "Init bup in " archive-dir) - (run-n-wait bup-exe params: bup-init-params print-cmd: print-prefix))) + ;; (mutex-lock! bup-mutex) + (run-n-wait bup-exe params: bup-init-params print-cmd: print-prefix) + ;; (mutex-unlock! bup-mutex) + )) (debug:print-info 0 "Indexing data to be archived") + ;; (mutex-lock! bup-mutex) (run-n-wait bup-exe params: bup-index-params print-cmd: print-prefix) (debug:print-info 0 "Archiving data with bup") (run-n-wait bup-exe params: bup-save-params print-cmd: print-prefix) + ;; (mutex-unlock! bup-mutex) (for-each (lambda (test-dat) (let ((test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat))) (rmt:test-set-archive-block-id run-id test-id archive-id) @@ -196,11 +207,11 @@ (runs:remove-test-directory test-dat 'archive-remove)))) (hash-table-ref test-groups disk-group)))) (hash-table-keys disk-groups)) #t)) -(define (archive:bup-restore archive-command run-id run-name tests) ;; move the getting of archive space down into the below block so that a single run can +(define (archive:bup-restore archive-command run-id run-name tests rp-mutex bup-mutex) ;; move the getting of archive space down into the below block so that a single run can ;; allocate as needed should a disk fill up ;; (let* ((bup-exe (or (configf:lookup *configdat* "archive" "bup") "bup")) (linktree (configf:lookup *configdat* "setup" "linktree"))) @@ -207,11 +218,11 @@ ;; from the test info bin the path to the test by stem ;; (for-each (lambda (test-dat) ;; When restoring test-dat will initially contain an old and invalid path to the test - (let* ((best-disk (get-best-disk *configdat*)) + (let* ((best-disk (get-best-disk *configdat* #f)) ;; BUG: get the testconfig and use it here. Otherwise data pulled out of archive could end up on the wrong kind of disk. (item-path (db:test-get-item-path test-dat)) (test-name (db:test-get-testname test-dat)) (test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat)) (keyvals (rmt:get-key-val-pairs run-id)) @@ -221,12 +232,16 @@ (> (rmt:test-toplevel-num-items run-id test-name) 0))) (test-partial-path (conc target "/" run-name "/" (db:test-make-full-name test-name item-path))) ;; note the trailing slash to get the dir inspite of it being a link (test-path (conc linktree "/" test-partial-path)) ;; if the old path was not deleted then prev-test-physical-path will end up pointing to a real directory - (prev-test-physical-path (if (file-exists? test-path) (read-symbolic-link test-path #t) #f)) - + (mutex-lock! rp-mutex) + (prev-test-physical-path (if (file-exists? test-path) + ;; (read-symbolic-link test-path #t) + (common:real-path test-path) + #f)) + (mutex-unlock! rp-mutex) (new-test-physical-path (conc best-disk "/" test-partial-path)) (archive-block-id (db:test-get-archived test-dat)) (archive-block-info (rmt:test-get-archive-block-info archive-block-id)) (archive-path (if (vector? archive-block-info) (vector-ref archive-block-info 2) ;; look in db.scm for test-get-archive-block-info for the vector record info @@ -266,10 +281,12 @@ (debug:print 0 "ERROR: unable to get data for run-id=" run-id ", test-id=" test-id) (exit 1)))) ;; new-test-path won't work - must use best-disk instead? Nope, new-test-path but tack on /.. (bup-restore-params (list "-d" archive-path "restore" "-C" (conc new-test-path "/..") archive-internal-path))) (debug:print-info 0 "Restoring archived data to " new-test-physical-path " from archive in " archive-path " ... " archive-internal-path) + ;; (mutex-lock! bup-mutex) (run-n-wait bup-exe params: bup-restore-params print-cmd: #f) + ;; (mutex-unlock! bup-mutex) (mt:test-set-state-status-by-id run-id test-id "COMPLETED" #f #f))) (debug:print 0 "ERROR: No archive path in the record for run-id=" run-id " test-id=" test-id)))) (filter vector? tests)))) Index: common.scm ================================================================== --- common.scm +++ common.scm @@ -587,10 +587,30 @@ (let* ((uname-res (cmd-run->list (conc "uname " (if (null? params) "-a" (car params))))) (uname #f)) (if (null? (car uname-res)) "unknown" (caar uname-res)))) + +;; for reasons I don't understand multiple calls to real-path in parallel threads +;; must be protected by mutexes +;; +(define (common:real-path inpath) + ;; (cmd-run-with-stderr->list "readlink" "-f" inpath)) ;; cmd . params) + ;; (let-values + ;; (((inp oup pid) (process "readlink" (list "-f" inpath)))) + ;; (with-input-from-port inp + ;; (let loop ((inl (read-line)) + ;; (res #f)) + ;; (print "inl=" inl) + ;; (if (eof-object? inl) + ;; (begin + ;; (close-input-port inp) + ;; (close-output-port oup) + ;; ;; (process-wait pid) + ;; res) + ;; (loop (read-line) inl)))))) + (with-input-from-pipe (conc "readlink -f " inpath) read-line)) ;;====================================================================== ;; D I S K S P A C E ;;====================================================================== Index: datashare-testing/.sd.config ================================================================== --- datashare-testing/.sd.config +++ datashare-testing/.sd.config @@ -8,11 +8,11 @@ [settings] storage /tmp/#{getenv USER}/datashare/disk1 \ /tmp/#{getenv USER}/datashare/disk2 -basepath #{getenv BASEPATH} +basepath #{scheme (or (getenv "BASEPATH") "/tmp/#{getenv USER}")} [areas] synthesis asic/synthesis verilog asic/verilog customlibs custom/oalibs Index: datashare.scm ================================================================== --- datashare.scm +++ datashare.scm @@ -655,11 +655,11 @@ )))) (define (datashare:gui configdat) (iup:show (iup:dialog - #:title (conc "DataShare dashboard " (current-user-name) ":" (current-directory)) + #:title (conc "DataShare dashboard " (current-user-name) ":" (current-directory)) #:menu (datashare:main-menu) (let* ((tabs (iup:tabs #:tabchangepos-cb (lambda (obj curr prev) (set! *datashare:current-tab-number* curr)) (datashare:publish-view configdat) Index: db.scm ================================================================== --- db.scm +++ db.scm @@ -1338,15 +1338,15 @@ (db:delay-if-busy dbdat) (for-each (lambda (toptest) (let ((test-name (list-ref toptest 3))) ;; (run-id (list-ref toptest 5))) - (db:top-test-set-per-pf-counts dbdat run-id test-name))) + (db:top-test-set-per-pf-counts dbstruct run-id test-name))) toplevels))) -(define (db:top-test-set-per-pf-counts dbdat run-id test-name) - (db:general-call dbdat 'top-test-set-per-pf-counts (list test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name))) +(define (db:top-test-set-per-pf-counts dbstruct run-id test-name) + (db:general-call (db:get-db dbstruct run-id) 'top-test-set-per-pf-counts (list test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name))) ;; Clean out old junk and vacuum the database ;; ;; Ultimately do something like this: @@ -2156,11 +2156,10 @@ (vector-ref inrec 5) ;; status -1 "" -1 -1 "" "-" (vector-ref inrec 3) ;; item-path -1 "-" "-")) - (define (db:get-tests-for-run-state-status dbstruct run-id testpatt) (let* ((res '()) (tests-match-qry (tests:match->sqlqry testpatt)) (qry (conc "SELECT id,testname,item_path,state,status FROM tests WHERE run_id=? " (if tests-match-qry (conc " AND (" tests-match-qry ") ") "")))) @@ -2243,14 +2242,16 @@ ;; set tests with state currstate and status currstatus to newstate and newstatus ;; use currstate = #f and or currstatus = #f to apply to any state or status respectively ;; WARNING: SQL injection risk. NB// See new but not yet used "faster" version below ;; - ;; AND NOT (item_path='' AND testname in (SELECT DISTINCT testname FROM tests WHERE testname=? AND item_path != ''));"))) - ;;(debug:print 0 "QRY: " qry) - ;; (db:delay-if-busy) - +;; AND NOT (item_path='' AND testname in (SELECT DISTINCT testname FROM tests WHERE testname=? AND item_path != ''));"))) +;; (debug:print 0 "QRY: " qry) +;; (db:delay-if-busy) +;; +;; NB// This call only operates on toplevel tests. Consider replacing it with more general call +;; (define (db:set-tests-state-status dbstruct run-id testnames currstate currstatus newstate newstatus) (for-each (lambda (testname) (let ((qry (conc "UPDATE tests SET state=?,status=? WHERE " (if currstate (conc "state='" currstate "' AND ") "") (if currstatus (conc "status='" currstatus "' AND ") "") @@ -2258,12 +2259,13 @@ (db:with-db dbstruct run-id #t (lambda (db) - (sqlite3:execute db qry newstate newstatus run-id testname) - (mt:process-triggers run-id test-id newstate newstatus) + (let ((test-id (db:get-test-id dbstruct run-id testname ""))) + (sqlite3:execute db qry newstate newstatus run-id testname) + (if test-id (mt:process-triggers run-id test-id newstate newstatus))) )))) testnames)) ;; speed up for common cases with a little logic ;; NB// Ultimately this will be deprecated in deference to mt:test-set-state-status-by-id @@ -2841,11 +2843,11 @@ (define (db:roll-up-pass-fail-counts dbstruct run-id test-name item-path state status) (if (not (equal? item-path "")) (let ((dbdat (db:get-db dbstruct run-id))) ;; (db (db:dbdat-get-db dbdat))) (db:general-call dbdat 'update-pass-fail-counts (list test-name test-name test-name)) - (db:top-test-set-per-pf-counts dbdat run-id test-name)))) + (db:top-test-set-per-pf-counts dbstruct run-id test-name)))) ;; (case (string->symbol status) ;; ((RUNNING) (db:general-call dbdat 'top-test-set-running (list test-name))) ;; ((LAUNCHED) (db:general-call dbdat 'top-test-set (list "LAUNCHED" test-name))) ;; ((ABORT INCOMPLETE) (db:general-call dbdat 'top-test-set (list status test-name)))) @@ -2941,11 +2943,11 @@ SET state=CASE WHEN (SELECT count(id) FROM tests WHERE testname=? AND item_path != '' AND status IN ('INCOMPLETE') - AND state in ('RUNNING','NOT_STARTED','LAUNCHED','REMOTEHOSTSTART')) > 0 THEN 'INCOMPLETE' + AND state in ('RUNNING','NOT_STARTED','LAUNCHED','REMOTEHOSTSTART')) > 0 THEN 'RUNNING' WHEN (SELECT count(id) FROM tests WHERE testname=? AND item_path != '' AND status NOT IN ('TEN_STRIKES','BLOCKED') AND state in ('RUNNING','NOT_STARTED','LAUNCHED','REMOTEHOSTSTART')) > 0 THEN 'RUNNING' @@ -2966,11 +2968,11 @@ AND state IN ('BLOCKED','INCOMPLETE')) > 0 THEN 'FAIL' WHEN (SELECT count(id) FROM tests WHERE testname=? AND item_path != '' AND state NOT IN ('DELETED') - AND status = 'ABORT') > 0 THEN 'ABORT' + AND status IN ('INCOMPLETE','ABORT')) > 0 THEN 'ABORT' WHEN (SELECT count(id) FROM tests WHERE testname=? AND item_path != '' AND state NOT IN ('DELETED') AND status = 'AUTO') > 0 THEN 'AUTO' @@ -3264,22 +3266,59 @@ ;; A routine to map itempaths using a itemmap (define (db:compare-itempaths patha pathb itemmap) (debug:print-info 6 "ITEMMAP is " itemmap) (if itemmap - (let* ((mapparts (string-split itemmap)) - (pattern (car mapparts)) - (replacement (if (> (length mapparts) 1) (cadr mapparts) ""))) - (if replacement - (equal? (string-substitute pattern replacement patha) - (string-substitute pattern replacement pathb)) - (equal? (string-substitute pattern "" patha) - (string-substitute pattern "" pathb)))) + (let ((path-b-mapped (db:convert-test-itempath pathb itemmap))) + (debug:print-info 6 "ITEMMAP is " itemmap ", path: " pathb ", mapped path: " path-b-mapped) + (equal? patha pathb)) (equal? patha pathb))) + +;; (let* ((mapparts (string-split itemmap)) +;; (pattern (car mapparts)) +;; (replacement (if (> (length mapparts) 1) (cadr mapparts) ""))) +;; (if replacement +;; (equal? (string-substitute pattern replacement patha) +;; (string-substitute pattern replacement pathb)) +;; (equal? (string-substitute pattern "" patha) +;; (string-substitute pattern "" pathb)))) + +;; A routine to convert test/itempath using a itemmap +(define (db:convert-test-itempath path-in itemmap) + (debug:print-info 6 "ITEMMAP is " itemmap) + (let* ((path-parts (string-split path-in "/")) + (test-name (if (null? path-parts) "" (car path-parts))) + (item-path (string-intersperse (if (null? path-parts) '() (cdr path-parts)) "/"))) + (conc test-name "/" + (db:multi-pattern-apply item-path itemmap)))) + +;; patterns are: +;; "rx1" "replacement1"\n +;; "rx2" "replacement2" +;; etc. +;; +(define (db:multi-pattern-apply item-path itemmap) + (let ((all-patts (string-split itemmap "\n"))) + (if (null? all-patts) + item-path + (let loop ((hed (car all-patts)) + (tal (cdr all-patts)) + (res item-path)) + (let* ((parts (string-split hed)) + (patt (car parts)) + (repl (if (> (length parts) 1)(cadr parts) "")) + (newr (if (and patt repl) + (string-substitute patt repl res) + (begin + (debug:print 0 "WARNING: itemmap has problem \"" itemmap "\", patt: " patt ", repl: " repl) + res)))) + (if (null? tal) + newr + (loop (car tal)(cdr tal) newr))))))) ;; the new prereqs calculation, looks also at itempath if specified -;; all prereqs must be met: +;; all prereqs must be met ;; if prereq test with itempath='' is COMPLETED and PASS, WARN, CHECK, or WAIVED then prereq is met ;; if prereq test with itempath=ref-item-path and COMPLETED with PASS, WARN, CHECK, or WAIVED then prereq is met ;; ;; Note: mode 'normal means that tests must be COMPLETED and ok (i.e. PASS, WARN, CHECK, SKIP or WAIVED) ;; mode 'toplevel means that tests must be COMPLETED only Index: docs/manual/howto.txt ================================================================== --- docs/manual/howto.txt +++ docs/manual/howto.txt @@ -78,11 +78,11 @@ # match. flexi-launcher yes ------------------------ Tricks ------- +====== This section is a compendium of a various useful tricks for debugging, configuring and generally getting the most out of Megatest. Limiting your running jobs Index: docs/manual/megatest_manual.html ================================================================== --- docs/manual/megatest_manual.html +++ docs/manual/megatest_manual.html @@ -986,17 +986,13 @@ flexi-launcher yes -
This section is a compendium of a various useful tricks for debugging, configuring and generally getting the most out of Megatest.
The following example will limit a test in the jobgroup "group1" to no more than 10 tests simultaneously.
In your testconfig:
runfirst/sum% remote
Attempt to rerun tests in "STUCK/DEAD", "n/a", "ZERO_ITEMS" states.
[setup] +reruns 5+
[skip] rundelay 15m 15s
A disks section in testconfig will override the disks section in +megatest.config. This can be used to allocate disks on a per-test or per item +basis.
If test is FAIL and previous test in run with same MT_TARGET is WAIVED then apply the following rules from the testconfig: If a waiver check is specified in the testconfig apply the check and if it passes then set this FAIL to WAIVED
[ezsteps] +lookittmp ls /tmp + +[logpro] +lookittmp ;; Note: config file format supports multi-line entries where leading whitespace is removed from each line + ;; a blank line indicates the end of the block of text + (expect:required in "LogFileBody" > 0 "A file name that should never exist!" #/This is a awfully stupid file name that should never be found in the temp dir/)+
To transfer the environment to the next step you can do the following:
$MT_MEGATEST -env2file .ezsteps/${stepname}