2 # Log resource analyser tool for Dali
3 # Monitors resource usage of last run Dali app
4 # Shows memory uploaded to GPU or normal RAM
5 # Texture atlas usage usually reflects used Font atlases
10 TERM_W=0 # latest width of terminal window
11 TERM_H=0 # latest height of terminal window
12 SEPARATOR_H=5 # 5 lines in info bar
13 CURPAGE=0 # current page number
14 MAXFILENO=0 # maximum lines to display from resourcelist
15 MAXP=0 # number of pages
17 DLOGTEMPFILE=/tmp/dalidlog.txt
18 DLOGUTIL=/usr/bin/dlogutil
25 # ID| Desc | Color | Tags
26 #---+----------------------------------+-----------+-------
27 # 0.| loaded in CPU memory | [CPU] | [LOAD]
28 # 1.| present in both memories | [CPUGPU] | [LOAD] [UPLOAD]
29 # 2.| GPU memory only, buffer discarded| [GPU] | [UPLOAD] [DELBUF]
30 # 3.| loaded but discarded later on | [DISC] | [LOAD] [DELBUF] or [DELBUF] [DELTEXTURE]
32 #colors for marking resource state
38 declare -a COLORS=( $COLOR_CPU $COLOR_CPUGPU $COLOR_GPU $COLOR_DISC )
40 declare -a FILENAMES_G=( )
41 declare -a BITMAPS_G=( )
42 declare -a TEXTURES_G=( )
43 declare -a STATES_G=( )
44 declare -a SIZES_G=( )
45 declare -a SIZE_DETAILS_G=( )
53 #process ID of last running Dali app
56 #distinguish texture atlases from framebuffer textures
58 BITMAP_ID_FB_TEXTURE="-"
60 ###################################string formatting, command line and error handling
70 echo "usage: ./dalireslog.sh [FILE]"
71 echo "if FILE isn't specified script will try to use dlogutil"
79 let MAXFILENO=$(($TERM_H-$SEPARATOR_H-2)) #leave space for keyboard shortcuts and separator itself
80 let MAXP=${#FILENAMES_G[@]}/$MAXFILENO
82 # don't show empty page if list just fits on screen
84 let rmd=${#FILENAMES_G[@]}%$MAXFILENO
91 # print string, notifying user if it doesn't fit in one line. takes one parameter
94 echo -n ${1:0:$TERM_W}
95 if [[ $TERM_W -lt ${#1} ]]
98 tput setab 1; tput smso; echo -n '>'; tput el; tput rmso
106 # print string, clear until end of line, print newline. takes one parameter
115 function parseCmdLine
120 if [[ ! -e "$DLOGUTIL" ]]
122 echo "dlogutil not installed"
127 INPUTFILE="$DLOGTEMPFILE"
130 # check if help is requested
131 if [[ $1 == '-h' || $1 == '--help' ]]
135 # try reading from file
138 if [[ ! -e "$INPUTFILE" ]]
140 echo cannot read file "$INPUTFILE"
148 # print filename or basename or "..." depending on terminal size, takes one parameter
153 echo "ERROR in printPath";
158 FBASENAME=$(basename $FILENAME)
159 if [[ ${#FILENAME} -lt $TERM_W ]]
161 printLine "$FILENAME"
163 if [[ ${#FBASENAME} -lt $TERM_W ]]
165 printLine "$FBASENAME"
172 ###################################memory query functions
173 function getGpuMemUsage
177 for state in ${STATES_G[@]}
179 if [[ $state == 1 || $state == 2 ]]
181 let GPUMEM+=${SIZES_G[$i]}
188 function getCpuMemUsage
192 for state in ${STATES_G[@]}
194 if [[ $state == 0 || $state == 1 ]]
196 let CPUMEM+=${SIZES_G[$i]}
203 function getAtlasNumber
207 for bitmap in ${BITMAPS_G[@]}
209 if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
218 function getAtlasMemUsage
222 for bitmap in ${BITMAPS_G[@]}
224 if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
226 let ATLASMEM+=${SIZES_G[$i]}
233 ##################################global arrays manipulation
234 #adds record to resource list
235 #params: filename, bitmap, texture, state, size, size detail
240 error "addRecord - number of arguments is $#"
247 SIZE_DETAILS_G+=("$6")
250 #adds image resource to list
251 #params: filename, bitmap, size, size detail
261 SIZE_DETAILS_G+=("$4")
266 #params: texture, size, size detail
267 function atlasUploaded
270 BITMAPS_G+=("$BITMAP_ID_ATLAS")
274 SIZE_DETAILS_G+=("$3")
277 #params: size, size detail
278 function frameBufUploaded
281 BITMAPS_G+=("$BITMAP_ID_FB_TEXTURE")
285 SIZE_DETAILS_G+=("$4")
289 ##################################log parsing functions
292 if [[ "$1" =~ .*DALI.*[LOAD].*file\ (.*)\ to\ Bitmap\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
294 local FILENAME="${BASH_REMATCH[1]}"
295 local BITMAP="${BASH_REMATCH[2]}"
296 local SIZE="${BASH_REMATCH[3]}"
297 local SIZE_DETAILS="${BASH_REMATCH[4]}"
301 #check if file was loaded before with same size
303 if [ ${#FILENAMES_G[@]} -ne 0 ]
306 for filenameIter in ${FILENAMES_G[@]}
308 if [[ "$filenameIter" == "$FILENAME" ]]
310 if [[ ${SIZES_G[$i]} == "$SIZE" && ${SIZE_DETAILS_G[$i]} == "$SIZE_DETAILS" ]]
313 case ${STATES_G[$i]} in
315 BITMAPS_G[$i]="$BITMAP"
318 BITMAPS_G[$i]="$BITMAP"
321 STATES_G[$i]=1 #GPU->CPUGPU loaded into memory again
322 BITMAPS_G[$i]="$BITMAP"
325 #previously discarded, load again
327 BITMAPS_G[$i]="$BITMAP"
330 error "checkLoaded - unknown state"
334 #filename is same, but its loaded in different size
344 fileLoaded "$FILENAME" "$BITMAP" "$SIZE" "$SIZE_DETAILS"
353 function checkUploaded
355 if [[ "$1" =~ .*DALI.*[UPLOAD].*Bitmap\ (.*)\ to\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
357 local BITMAP="${BASH_REMATCH[1]}"
358 local TEXTURE="${BASH_REMATCH[2]}"
359 local SIZE="${BASH_REMATCH[3]}"
360 local SIZE_DETAILS="${BASH_REMATCH[4]}"
365 if [[ "$BITMAP" =~ \(nil\) ]]
367 atlasUploaded $TEXTURE $SIZE "$SIZE_DETAILS"
371 if [ ${#BITMAPS_G[@]} -ne $BITMAP_ID_ATLAS ]
373 for bitmap in ${BITMAPS_G[@]}
375 if [ $bitmap == $BITMAP ]
384 if [ $lastIdx != -1 ]
387 if [[ ${TEXTURES_G[$lastIdx]} == 0 && ${STATES_G[$lastIdx]} == 0 ]]
389 #File loaded in memory -> upload to GPU
390 TEXTURES_G[$lastIdx]="$TEXTURE"
392 elif [[ ${FILENAMES_G[$lastIdx]} == "-" && ${STATES_G[$lastIdx]} == 1 ]]
394 #BufferImage already in memory and GPU mem. -> updated
395 SIZES_G[$lastIdx]=$SIZE
396 SIZE_DETAILS_G[$lastIdx]="$SIZE_DETAILS"
398 #bitmap uploaded to new texture
399 addRecord ${FILENAMES_G[$lastIdx]} $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
402 #bitmapImage - not loaded from file
404 addRecord "-" $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
407 elif [[ "$1" =~ .*DALI.*[UPLOAD].*FrameBufferTexture\ (.*)\ GL\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
409 local FBTEXTURE="${BASH_REMATCH[1]}"
410 local TEXTURE="${BASH_REMATCH[2]}"
411 local SIZE="${BASH_REMATCH[3]}"
412 local SIZE_DETAILS="${BASH_REMATCH[4]}"
413 frameBufUploaded "$FBTEXTURE" "$TEXTURE" "$SIZE" "$SIZE_DETAILS"
417 error "checkUploaded"
421 function checkDeletedBuf
423 if [[ "$1" =~ .*DALI.*[DELBUF].*Bitmap\ (.*)\ -\ .*size\ (.*) ]]
425 local BITMAP=${BASH_REMATCH[1]}
428 for bitmap in ${BITMAPS_G[@]}
430 if [ $bitmap == "$BITMAP" ]
432 case ${STATES_G[$i]} in
434 STATES_G[$i]=3 #CPU->DISC
437 STATES_G[$i]=2 #CPUGPU->GPU
441 #probably previously freed bitmap buffer but memory is reused since
445 #probably previously freed but memory is reused since
448 error "checkDeletedBuf - unkown state"
458 error "checkDeletedBuf"
462 function checkDeletedTexture
464 if [[ "$1" =~ .*DALI.*[DELTEXTURE].*Texture\ (.*)\ -\ size\ (.*) ]]
466 local TEXTURE="${BASH_REMATCH[1]}"
470 for texture in ${TEXTURES_G[@]}
472 if [ $texture == $TEXTURE ]
479 if [ $lastIdx != -1 ]
481 case ${STATES_G[$lastIdx]} in
485 error "checkDeletedTexture - state CPU"
488 STATES_G[$lastIdx]=0 #CPUGPU->CPU
491 STATES_G[$lastIdx]=3 #GPU->DISC
496 error "checkDeletedTexture - state DISC"
499 error "checkDeletedTexture - unkown state"
504 error "checkDeletedTexture - texture not uploaded"
509 error "checkDeletedTexture"
515 if [[ "$1" =~ .*DALI.*\ \[(.*)\].* ]]
517 RESCMD=${BASH_REMATCH[1]}
529 checkDeletedTexture "$1"
534 return 1 #end of last log session
537 error "Unkown command $RESCMD"
548 echo "ERROR in parseFile";
552 #return if file does not contain dali resource log
553 if ! grep -q -m 1 -E "DALI.*\[INIT\]" $1
558 #find last resource log session
559 local LOGBUFFER=$(sed -n 'H; /DALI.*\[INIT\]/h; ${g;p;}' $1)
563 #show PID of last process
564 PID_G=$(echo "$line" | sed 's/[^0-9]*\([0-9]*\).*/\1/')
569 done <<< "$LOGBUFFER"
573 if ! processLine "$line" #stop parsing at the end of last session
577 done <<< "$LOGBUFFER"
580 ##################################draw and main functions
583 tput cup 0 0 #move cursor to top left
585 # print info (4 lines)
587 printLine "PID: $PID_G"
588 printLine "MEM 3D: $GPUMEM"
589 printLine "MEM Atlas: $ATLASMEM";
590 printLine "MEM CPU: $CPUMEM"
591 printLine "Number of atlases: $ATLAS_NO";
594 # separator bar (colored bar with (actual/number of files) count)
595 tput cup $SEPARATOR_H 0
596 local PAGEIND="$(expr $CURPAGE + 1)/$(expr $MAXP + 1)"
598 let FILL_W=$TERM_W-${#PAGEIND}
599 tput setab 4; printf $PAGEIND%"$FILL_W"s; printf '\n'; tput sgr0
604 let index=$CURPAGE*$MAXFILENO
606 filecount=${#FILENAMES_G[@]}
610 while [[ $count -lt $MAXFILENO ]]
612 if [[ $index -lt $filecount ]]
614 tput setab ${COLORS[${STATES_G[$index]}]}
615 # printPath "${FILENAMES_G[$count]}"
616 printLine "${FILENAMES_G[$index]} ${SIZES_G[$index]} ${SIZE_DETAILS_G[$index]}"
619 printLine "" #clear remaining lines to fill screen
625 # print keyboard shortcuts
626 tput setab 4; tput bold
627 IFS= printString " | n: next page | p: previous page | ^C: exit | Resource state: "
629 if [[ $TERM_W -gt 100 ]]
631 tput setab ${COLORS[0]}
633 tput setab ${COLORS[1]}
635 tput setab ${COLORS[2]}
637 tput setab ${COLORS[3]}
638 echo -n " DISCARDED "
651 if [[ $CURPAGE -ne 0 ]]
657 if [[ $CURPAGE -lt $MAXP ]]
677 tput cup 9999 0 #go to bottom of screen
678 tput cnorm #show cursor
680 if [ -f "$DLOGTEMPFILE" ]
689 if [ -n "$USING_DLOG" ]
691 if [ -f "$DLOGTEMPFILE" ]
695 "$DLOGUTIL" DALI:I -d -f "$DLOGTEMPFILE" 2>/dev/null
698 if [ ! -e "$INPUTFILE" ]
703 parseFile "$INPUTFILE"
705 if [[ $? -gt 0 || ${#STATES_G[@]} -lt 1 ]]
724 if [ -z "$INPUTFILE" ]
726 echo No input file specified;
731 tput civis #hide cursor
732 tput clear #clear screen
734 echo "waiting for log..."
739 # sleep 0.3 # we are now reading input for 0.3
745 trap "cleanup; exit 0" SIGINT SIGTERM #reset terminal when ^C is pressed
746 # trap "getTermSize" SIGWINCH #handle window resize