2 PATH=/bin:/usr/bin:/sbin:/usr/sbin
3 # Log resource analyser tool for Dali
4 # Monitors resource usage of last run Dali app
5 # Shows memory uploaded to GPU or normal RAM
6 # Texture atlas usage usually reflects used Font atlases
11 TERM_W=0 # latest width of terminal window
12 TERM_H=0 # latest height of terminal window
13 SEPARATOR_H=5 # 5 lines in info bar
14 CURPAGE=0 # current page number
15 MAXFILENO=0 # maximum lines to display from resourcelist
16 MAXP=0 # number of pages
18 DLOGTEMPFILE=/tmp/dalidlog.txt
19 DLOGUTIL=/usr/bin/dlogutil
26 # ID| Desc | Color | Tags
27 #---+----------------------------------+-----------+-------
28 # 0.| loaded in CPU memory | [CPU] | [LOAD]
29 # 1.| present in both memories | [CPUGPU] | [LOAD] [UPLOAD]
30 # 2.| GPU memory only, buffer discarded| [GPU] | [UPLOAD] [DELBUF]
31 # 3.| loaded but discarded later on | [DISC] | [LOAD] [DELBUF] or [DELBUF] [DELTEXTURE]
33 #colors for marking resource state
39 declare -a COLORS=( $COLOR_CPU $COLOR_CPUGPU $COLOR_GPU $COLOR_DISC )
41 declare -a FILENAMES_G=( )
42 declare -a BITMAPS_G=( )
43 declare -a TEXTURES_G=( )
44 declare -a STATES_G=( )
45 declare -a SIZES_G=( )
46 declare -a SIZE_DETAILS_G=( )
54 #process ID of last running Dali app
57 #distinguish texture atlases from framebuffer textures
59 BITMAP_ID_FB_TEXTURE="-"
61 ###################################string formatting, command line and error handling
71 echo "usage: ./dalireslog.sh [FILE]"
72 echo "if FILE isn't specified script will try to use dlogutil"
80 let MAXFILENO=$(($TERM_H-$SEPARATOR_H-2)) #leave space for keyboard shortcuts and separator itself
81 let MAXP=${#FILENAMES_G[@]}/$MAXFILENO
83 # don't show empty page if list just fits on screen
85 let rmd=${#FILENAMES_G[@]}%$MAXFILENO
92 # print string, notifying user if it doesn't fit in one line. takes one parameter
95 echo -n ${1:0:$TERM_W}
96 if [[ $TERM_W -lt ${#1} ]]
99 tput setab 1; tput smso; echo -n '>'; tput el; tput rmso
107 # print string, clear until end of line, print newline. takes one parameter
116 function parseCmdLine
121 if [[ ! -e "$DLOGUTIL" ]]
123 echo "dlogutil not installed"
128 INPUTFILE="$DLOGTEMPFILE"
131 # check if help is requested
132 if [[ $1 == '-h' || $1 == '--help' ]]
136 # try reading from file
139 if [[ ! -e "$INPUTFILE" ]]
141 echo cannot read file "$INPUTFILE"
149 # print filename or basename or "..." depending on terminal size, takes one parameter
154 echo "ERROR in printPath";
159 FBASENAME=$(basename $FILENAME)
160 if [[ ${#FILENAME} -lt $TERM_W ]]
162 printLine "$FILENAME"
164 if [[ ${#FBASENAME} -lt $TERM_W ]]
166 printLine "$FBASENAME"
173 ###################################memory query functions
174 function getGpuMemUsage
178 for state in ${STATES_G[@]}
180 if [[ $state == 1 || $state == 2 ]]
182 let GPUMEM+=${SIZES_G[$i]}
189 function getCpuMemUsage
193 for state in ${STATES_G[@]}
195 if [[ $state == 0 || $state == 1 ]]
197 let CPUMEM+=${SIZES_G[$i]}
204 function getAtlasNumber
208 for bitmap in ${BITMAPS_G[@]}
210 if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
219 function getAtlasMemUsage
223 for bitmap in ${BITMAPS_G[@]}
225 if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
227 let ATLASMEM+=${SIZES_G[$i]}
234 ##################################global arrays manipulation
235 #adds record to resource list
236 #params: filename, bitmap, texture, state, size, size detail
241 error "addRecord - number of arguments is $#"
248 SIZE_DETAILS_G+=("$6")
251 #adds image resource to list
252 #params: filename, bitmap, size, size detail
262 SIZE_DETAILS_G+=("$4")
267 #params: texture, size, size detail
268 function atlasUploaded
271 BITMAPS_G+=("$BITMAP_ID_ATLAS")
275 SIZE_DETAILS_G+=("$3")
278 #params: size, size detail
279 function frameBufUploaded
282 BITMAPS_G+=("$BITMAP_ID_FB_TEXTURE")
286 SIZE_DETAILS_G+=("$4")
290 ##################################log parsing functions
293 if [[ "$1" =~ .*DALI.*[LOAD].*file\ (.*)\ to\ Bitmap\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
295 local FILENAME="${BASH_REMATCH[1]}"
296 local BITMAP="${BASH_REMATCH[2]}"
297 local SIZE="${BASH_REMATCH[3]}"
298 local SIZE_DETAILS="${BASH_REMATCH[4]}"
302 #check if file was loaded before with same size
304 if [ ${#FILENAMES_G[@]} -ne 0 ]
307 for filenameIter in ${FILENAMES_G[@]}
309 if [[ "$filenameIter" == "$FILENAME" ]]
311 if [[ ${SIZES_G[$i]} == "$SIZE" && ${SIZE_DETAILS_G[$i]} == "$SIZE_DETAILS" ]]
314 case ${STATES_G[$i]} in
316 BITMAPS_G[$i]="$BITMAP"
319 BITMAPS_G[$i]="$BITMAP"
322 STATES_G[$i]=1 #GPU->CPUGPU loaded into memory again
323 BITMAPS_G[$i]="$BITMAP"
326 #previously discarded, load again
328 BITMAPS_G[$i]="$BITMAP"
331 error "checkLoaded - unknown state"
335 #filename is same, but its loaded in different size
345 fileLoaded "$FILENAME" "$BITMAP" "$SIZE" "$SIZE_DETAILS"
354 function checkUploaded
356 if [[ "$1" =~ .*DALI.*[UPLOAD].*Bitmap\ (.*)\ to\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
358 local BITMAP="${BASH_REMATCH[1]}"
359 local TEXTURE="${BASH_REMATCH[2]}"
360 local SIZE="${BASH_REMATCH[3]}"
361 local SIZE_DETAILS="${BASH_REMATCH[4]}"
366 if [[ "$BITMAP" =~ \(nil\) ]]
368 atlasUploaded $TEXTURE $SIZE "$SIZE_DETAILS"
372 if [ ${#BITMAPS_G[@]} -ne $BITMAP_ID_ATLAS ]
374 for bitmap in ${BITMAPS_G[@]}
376 if [ $bitmap == $BITMAP ]
385 if [ $lastIdx != -1 ]
388 if [[ ${TEXTURES_G[$lastIdx]} == 0 && ${STATES_G[$lastIdx]} == 0 ]]
390 #File loaded in memory -> upload to GPU
391 TEXTURES_G[$lastIdx]="$TEXTURE"
393 elif [[ ${FILENAMES_G[$lastIdx]} == "-" && ${STATES_G[$lastIdx]} == 1 ]]
395 #BufferImage already in memory and GPU mem. -> updated
396 SIZES_G[$lastIdx]=$SIZE
397 SIZE_DETAILS_G[$lastIdx]="$SIZE_DETAILS"
399 #bitmap uploaded to new texture
400 addRecord ${FILENAMES_G[$lastIdx]} $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
403 #bitmapImage - not loaded from file
405 addRecord "-" $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
408 elif [[ "$1" =~ .*DALI.*[UPLOAD].*FrameBufferTexture\ (.*)\ GL\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
410 local FBTEXTURE="${BASH_REMATCH[1]}"
411 local TEXTURE="${BASH_REMATCH[2]}"
412 local SIZE="${BASH_REMATCH[3]}"
413 local SIZE_DETAILS="${BASH_REMATCH[4]}"
414 frameBufUploaded "$FBTEXTURE" "$TEXTURE" "$SIZE" "$SIZE_DETAILS"
418 error "checkUploaded"
422 function checkDeletedBuf
424 if [[ "$1" =~ .*DALI.*[DELBUF].*Bitmap\ (.*)\ -\ .*size\ (.*) ]]
426 local BITMAP=${BASH_REMATCH[1]}
429 for bitmap in ${BITMAPS_G[@]}
431 if [ $bitmap == "$BITMAP" ]
433 case ${STATES_G[$i]} in
435 STATES_G[$i]=3 #CPU->DISC
438 STATES_G[$i]=2 #CPUGPU->GPU
442 #probably previously freed bitmap buffer but memory is reused since
446 #probably previously freed but memory is reused since
449 error "checkDeletedBuf - unkown state"
459 error "checkDeletedBuf"
463 function checkDeletedTexture
465 if [[ "$1" =~ .*DALI.*[DELTEXTURE].*Texture\ (.*)\ -\ size\ (.*) ]]
467 local TEXTURE="${BASH_REMATCH[1]}"
471 for texture in ${TEXTURES_G[@]}
473 if [ $texture == $TEXTURE ]
480 if [ $lastIdx != -1 ]
482 case ${STATES_G[$lastIdx]} in
486 error "checkDeletedTexture - state CPU"
489 STATES_G[$lastIdx]=0 #CPUGPU->CPU
492 STATES_G[$lastIdx]=3 #GPU->DISC
497 error "checkDeletedTexture - state DISC"
500 error "checkDeletedTexture - unkown state"
505 error "checkDeletedTexture - texture not uploaded"
510 error "checkDeletedTexture"
516 if [[ "$1" =~ .*DALI.*\ \[(.*)\].* ]]
518 RESCMD=${BASH_REMATCH[1]}
530 checkDeletedTexture "$1"
535 return 1 #end of last log session
538 error "Unkown command $RESCMD"
549 echo "ERROR in parseFile";
553 #return if file does not contain dali resource log
554 if ! grep -q -m 1 -E "DALI.*\[INIT\]" $1
559 #find last resource log session
560 local LOGBUFFER=$(sed -n 'H; /DALI.*\[INIT\]/h; ${g;p;}' $1)
564 #show PID of last process
565 PID_G=$(echo "$line" | sed 's/[^0-9]*\([0-9]*\).*/\1/')
570 done <<< "$LOGBUFFER"
574 if ! processLine "$line" #stop parsing at the end of last session
578 done <<< "$LOGBUFFER"
581 ##################################draw and main functions
584 tput cup 0 0 #move cursor to top left
586 # print info (4 lines)
588 printLine "PID: $PID_G"
589 printLine "MEM 3D: $GPUMEM"
590 printLine "MEM Atlas: $ATLASMEM";
591 printLine "MEM CPU: $CPUMEM"
592 printLine "Number of atlases: $ATLAS_NO";
595 # separator bar (colored bar with (actual/number of files) count)
596 tput cup $SEPARATOR_H 0
597 local PAGEIND="$(expr $CURPAGE + 1)/$(expr $MAXP + 1)"
599 let FILL_W=$TERM_W-${#PAGEIND}
600 tput setab 4; printf $PAGEIND%"$FILL_W"s; printf '\n'; tput sgr0
605 let index=$CURPAGE*$MAXFILENO
607 filecount=${#FILENAMES_G[@]}
611 while [[ $count -lt $MAXFILENO ]]
613 if [[ $index -lt $filecount ]]
615 tput setab ${COLORS[${STATES_G[$index]}]}
616 # printPath "${FILENAMES_G[$count]}"
617 printLine "${FILENAMES_G[$index]} ${SIZES_G[$index]} ${SIZE_DETAILS_G[$index]}"
620 printLine "" #clear remaining lines to fill screen
626 # print keyboard shortcuts
627 tput setab 4; tput bold
628 IFS= printString " | n: next page | p: previous page | ^C: exit | Resource state: "
630 if [[ $TERM_W -gt 100 ]]
632 tput setab ${COLORS[0]}
634 tput setab ${COLORS[1]}
636 tput setab ${COLORS[2]}
638 tput setab ${COLORS[3]}
639 echo -n " DISCARDED "
652 if [[ $CURPAGE -ne 0 ]]
658 if [[ $CURPAGE -lt $MAXP ]]
678 tput cup 9999 0 #go to bottom of screen
679 tput cnorm #show cursor
681 if [ -f "$DLOGTEMPFILE" ]
690 if [ -n "$USING_DLOG" ]
692 if [ -f "$DLOGTEMPFILE" ]
696 "$DLOGUTIL" DALI:I -d -f "$DLOGTEMPFILE" 2>/dev/null
699 if [ ! -e "$INPUTFILE" ]
704 parseFile "$INPUTFILE"
706 if [[ $? -gt 0 || ${#STATES_G[@]} -lt 1 ]]
725 if [ -z "$INPUTFILE" ]
727 echo No input file specified;
732 tput civis #hide cursor
733 tput clear #clear screen
735 echo "waiting for log..."
740 # sleep 0.3 # we are now reading input for 0.3
746 trap "cleanup; exit 0" SIGINT SIGTERM #reset terminal when ^C is pressed
747 # trap "getTermSize" SIGWINCH #handle window resize