1 #library of useful PWGPP related bash functions
2 #it REQUIRES BASH 4 !!!!
3 #blame: Mikolaj Krzewicki, mkrzewic@cern.ch
5 if [ ${BASH_VERSINFO} -lt 4 ]; then
6 echo "bash version >= 4 needed, you have ${BASH_VERSION}, exiting..."
24 #first, check if the config file is configured
25 #is yes - source it so that other options can override it
27 #recommended way of using (at the beginning of your funcion/script):
28 # if ! parseConfig "${@}"; then return; fi
32 #first check if we will need to decode spaces
33 local encodedSpaces=""
34 for opt in "${args[@]}"; do
35 [[ "${opt}" =~ encodedSpaces=.* ]] \
40 #then look for a configFile (if any)
41 for opt in "${args[@]}"; do
42 if [[ ${opt} =~ configFile=.* ]]; then
44 [[ ! -f ${configFile} ]] \
45 && echo "configFile ${configFile} not found, exiting..." \
47 echo "using config file: ${configFile}"
48 source "${configFile}"
53 #then, parse the options as they override the options from configFile
54 for opt in "${args[@]}"; do
55 [[ -n ${encodedSpaces} ]] && opt="$(decSpaces ${opt})"
56 if [[ ! "${opt}" =~ .*=.* ]]; then
57 echo "badly formatted option ${var}, should be: option=value, stopping..."
60 local var="${opt%%=*}"
61 local value="${opt#*=}"
62 #echo "${var}=${value}"
63 export ${var}="${value}"
70 #guess the period from the path, pick the rightmost one
84 declare -a path=( $1 )
86 local dirDepth=$(( ${#path[*]}-1 ))
87 for ((x=${dirDepth};x>=0;x--)); do
89 [[ $((x-1)) -ge 0 ]] && local fieldPrev=${path[$((x-1))]}
90 local field=${path[${x}]}
91 local fieldNext=${path[$((x+1))]}
93 [[ ${field} =~ ^[0-9]*$ && ${fieldNext} =~ (.*\.zip$|.*\.root$) ]] && legoTrainRunNumber=${field}
94 [[ -n ${legoTrainRunNumber} && -z ${pass} ]] && pass=${fieldPrev}
95 [[ ${field} =~ ^LHC[0-9][0-9][a-z].*$ ]] && period=${field%_*} && originalPeriod=${field}
96 [[ ${field} =~ ^000[0-9][0-9][0-9][0-9][0-9][0-9]$ ]] && runNumber=${field#000}
97 [[ ${field} =~ ^[0-9][0-9][0-9][0-9][0-9][0-9]$ ]] && shortRunNumber=${field}
98 [[ ${field} =~ ^20[0-9][0-9]$ ]] && year=${field}
99 [[ ${field} =~ ^(^sim$|^data$) ]] && dataType=${field}
103 [[ -n ${shortRunNumber} && "${legoTrainRunNumber}" =~ ${shortRunNumber} ]] && legoTrainRunNumber=""
104 [[ -z ${legoTrainRunNumber} ]] && pass=${path[$((dirDepth-1))]}
105 [[ "${dataType}" =~ ^sim$ ]] && pass="passMC" && runNumber=${shortRunNumber} && originalPass="" #for MC not from lego, the runnumber is identified as lego train number, thus needs to be nulled
106 [[ -n ${legoTrainRunNumber} ]] && pass+="_lego${legoTrainRunNumber}"
108 #modify the OCDB: set the year
109 if [[ ${dataType} =~ sim ]]; then
110 anchorYear=$(run2year $runNumber)
111 if [[ -z "${anchorYear}" ]]; then
112 echo "WARNING: anchorYear not available for this production: ${originalPeriod}, runNumber: ${runNumber}. Cannot set the OCDB."
115 ocdbStorage=$(setYear ${anchorYear} ${ocdbStorage})
117 ocdbStorage=$(setYear ${year} ${ocdbStorage})
120 #if [[ -z ${dataType} || -z ${year} || -z ${period} || -z ${runNumber}} || -z ${pass} ]];
121 if [[ -z ${runNumber} ]]
134 # ${1} - year to be set
135 # ${2} - where to set the year
136 local year1=$(guessYear ${1})
137 local year2=$(guessYear ${2})
139 [[ ${year1} -ne ${year2} && -n ${year2} && -n ${year1} ]] && path=${2/\/${year2}\//\/${year1}\/}
146 #guess the year from the path, pick the rightmost one
148 declare -a pathArray=( ${1} )
151 for field in ${pathArray[@]}; do
152 [[ ${field} =~ ^20[0-9][0-9]$ ]] && year=${field}
160 #for a given run print the year.
161 #the run-year table is ${PWGPP_runMap} (a string)
162 #one line per year, format: year runMin runMax
164 [[ -z ${run} ]] && return 1
168 while read year runMin runMax; do
169 [[ -z ${year} || -z ${runMin} || -z ${runMax} ]] && continue
170 [[ ${run} -ge ${runMin} && ${run} -le ${runMax} ]] && echo ${year} && break
171 done < <(echo "${PWGPP_runMap}")
177 # Hallo world - Print AliRoot/Root/Alien system info
183 echo --------------------------------------
187 echo HOSTINFO HOSTNAME" "$HOSTNAME
188 echo HOSTINFO DATE" "`date`
189 echo HOSTINFO gccpath" "`which gcc`
190 echo HOSTINFO gcc version" "`gcc --version | grep gcc`
191 echo --------------------------------------
196 echo --------------------------------------
200 echo ROOTINFO ROOT" "`which root`
201 echo ROOTINFO VERSION" "`root-config --version`
203 echo --------------------------------------
209 echo --------------------------------------
213 echo ALIROOTINFO ALIROOT" "`which aliroot`
214 echo ALIROOTINFO VERSION" "`echo $ALICE_LEVEL`
215 echo ALIROOTINFO TARGET" "`echo $ALICE_TARGET`
217 echo --------------------------------------
222 #echo --------------------------------------
225 #for a in `alien --printenv`; do echo ALIENINFO $a; done
227 #echo --------------------------------------
244 #validate and summarize the status of logs
245 #input is a list of logs, or a glob:
246 #example (summarizes logs in current and subdirs):
247 # summarizeLogs * */*
248 #exit code 1 if some logs are not validated
250 #print a summary of logs
255 [[ -z "${input[*]}" ]] && input=( "${PWD}"/* )
257 #double inclusion protection+make full paths
258 for file in "${input[@]}"; do
259 [[ ! "${file}" =~ ^/ ]] && file="${PWD}/${file}"
260 files["${file}"]="${file}"
264 logFiles=".*log|stdout|stderr"
268 local errorSummary=""
269 local validationStatus=""
271 for file in "${files[@]}"; do
272 [[ ! -f ${file} ]] && continue
273 #keep track of core files for later processing
274 [[ "${file}" =~ core$ ]] && coreFiles[${file}]="${file}" && continue
275 [[ ! "${file}" =~ ${logFiles} ]] && continue
276 errorSummary=$(validateLog ${file})
278 [[ validationStatus -ne 0 ]] && logStatus=1
279 if [[ ${validationStatus} -eq 0 ]]; then
280 #in pretend mode randomly report an error in rec.log some cases
282 elif [[ ${validationStatus} -eq 1 ]]; then
283 echo "${file} BAD ${errorSummary}"
284 elif [[ ${validationStatus} -eq 2 ]]; then
285 echo "${file} OK MWAH ${errorSummary}"
290 for x in "${coreFiles[@]}"; do
293 #gdb --batch --quiet -ex "bt" -ex "quit" aliroot ${x} > stacktrace_${x//\//_}.log
294 gdb --batch --quiet -ex "bt" -ex "quit" aliroot ${x} > stacktrace.log
296 #nLines=($(wc -l stacktrace_${x//\//_}.log))
297 nLines=($(wc -l stacktrace.log))
298 if [[ ${nLines[0]} -eq 0 ]]; then
299 #rm stacktrace_${x//\//_}.log
303 echo "${x%/*}/stacktrace.log"
312 #validate one log file
313 #input is path to log file
314 #output an error summary on stdout
315 #exit code is 0 if validated, 1 otherwise
320 'error while loading shared libraries'
323 'Thread [0-9]* (Thread'
325 '\.C.*error:.*\.h: No such file'
328 'Interpreter error recovered'
329 ': command not found'
330 ': comando non trovato'
339 local errorSummary=""
340 local warningSummary=""
341 local errorCondition=""
342 for errorCondition in "${errorConditions[@]}"; do
343 local tmp=$(grep -m1 -e "${errorCondition}" ${log})
345 [[ -n ${tmp} ]] && error=" : ${errorCondition}"
346 errorSummary+=${error}
349 local warningCondition=""
350 for warningCondition in "${warningConditions[@]}"; do
351 local tmp=$(grep -m1 -e "${warningCondition}" ${log})
353 [[ -n ${tmp} ]] && warning=" : ${warningCondition}"
354 warningSummary+=${warning}
357 if [[ -n ${errorSummary} ]]; then
358 echo "${errorSummary}"
362 if [[ -n ${warningSummary} ]]; then
363 echo "${warningSummary}"
372 if [[ $# -lt 2 ]]; then
373 echo 'merge syslogs to an output file'
375 echo 'mergeSysLogs outputFile inputFile1 inputFile2 ...'
387 if ! ls -1 ${inputFiles} &>/dev/null; then echo "the files dont exist!: ${inputFiles}"; return 1; fi
389 runNumber=$(guessRunNumber ${x})
390 [[ -z ${runNumber} ]] && echo "run number cannot be guessed for ${x}" && continue
391 awk -v run=${runNumber} -v i=${i} 'NR > 1 {print run" "$0} NR==1 && i==0 {print "run/I:"$0}' ${x}
393 done < <(ls -1 ${inputFiles}) > ${outputFile}
399 if [[ $# -lt 1 ]]; then
400 echo 'make stacktrace processing in case of standard root crash log'
401 echo 'input is a (list of) text files with the stack trace (either gdb aoutput'
402 echo 'produced with e.g. gdb --batch --quiet -ex "bt" -ex "quit" aliroot core,'
403 echo 'or the root crash log), output is a TTree formatted table.'
404 echo 'example usage:'
405 echo 'benchmark.sh stackTraceTree /foo/*/rec.log'
406 echo 'benchmark.sh stackTraceTree $(cat file.list)'
407 echo 'benchmark.sh stackTraceTree `cat file.list`'
413 print "frame/I:method/C:line/C:cpass/I:aliroot/I:file/C";
418 /There was a crash/ {read=1;}
419 /The lines below might hint at the cause of the crash/ {read=0;}
421 if ($3 ~ /Ali*/) aliroot=1; else aliroot=0;
423 if ($NF!="" && RT!="" && $3!="") print RT" "$3" "$NF" "0" "aliroot" "FILENAME
430 #plot the stacktrace tree,
431 #first arg is the text file in the root tree format
432 #second arg is optional: a plot is written to file instead of screen
433 #third arg is optional: selection for plotting, default skip G_ stuff
435 local plot=${2:-"crashes.png"}
436 local selection=${3:-'!strstr(method,\"G__\")'}
438 [[ ! -f ${tree} ]] && echo "no input" && return 1
440 TTree* t=AliSysInfo::MakeTree("${tree}");
441 TCanvas* canvas = new TCanvas("QA crashes","QA crashes",1);
442 t->Draw("method","${selection}","");
443 canvas->SaveAs("${plot}");
461 if [[ $# -lt 1 ]]; then
462 echo "print the full path of a file, like \"readlink -f\" on linux"
464 echo " get_realpath <someFile>"
470 if cd "$(echo "${1%/*}")" &>/dev/null
472 # file *may* not be local
473 # exception is ./file.ext
474 # try 'cd .; cd -;' *works!*
478 # file *must* be local
482 # file *cannot* exist
485 # reassemble realpath
486 echo "$tmppwd"/"${1##*/}"
492 #this function processes the summary logs and prints some stats
493 #relies on the summary log format produced by summarizeLogs()
494 # - how many checked logs in total
495 # - number of each type of problem
497 # printLogStatistics */*.log
498 [[ ! -f $1 ]] && return 1
499 echo "log statistics from: ${1%/*}"
502 BEGIN {nOK=0; nCores=0; nStackTraces=0;}
504 /\/stacktrace.log/ {nStackTraces++}
505 /OK/ {nOK++; nLogs++;}
510 for (i=3; i<=NF; i++)
523 if (err != "" && (write==1 || i==NF))
531 print ("number of succesful jobs: " nOK" out of "nLogs )
534 print key": "sumBAD[key]
536 if (nCores>0) print "core files: "nCores", stack traces: "nStackTraces