Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-adaptor.git] / adaptors / scripts / dalireslog.sh
1 #!/bin/bash
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
6
7 set -u
8
9 #global variables
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
16
17 DLOGTEMPFILE=/tmp/dalidlog.txt
18 DLOGUTIL=/usr/bin/dlogutil
19 USING_DLOG=
20 INPUTFILE=""
21
22
23
24 #possible states
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]
31
32 #colors for marking resource state
33 COLOR_CPU=5
34 COLOR_CPUGPU=1
35 COLOR_GPU=2
36 COLOR_DISC=6
37
38 declare -a COLORS=( $COLOR_CPU $COLOR_CPUGPU $COLOR_GPU $COLOR_DISC )
39
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=( )
46
47 ATLASMEM=0
48 ATLAS_NO=0
49
50 CPUMEM=0
51 GPUMEM=0
52
53 #process ID of last running Dali app
54 PID_G=0
55
56 #distinguish texture atlases from framebuffer textures
57 BITMAP_ID_ATLAS=0
58 BITMAP_ID_FB_TEXTURE="-"
59
60 ###################################string formatting, command line and error handling
61 function error
62 {
63   echo "Error: $1"
64   cleanup
65   exit 1
66 }
67
68 function usage
69 {
70     echo "usage: ./dalireslog.sh [FILE]"
71     echo "if FILE isn't specified script will try to use dlogutil"
72 }
73
74 function getTermSize
75 {
76     TERM_W=$(tput cols)
77     TERM_H=$(tput lines)
78
79     let MAXFILENO=$(($TERM_H-$SEPARATOR_H-2)) #leave space for keyboard shortcuts and separator itself
80     let MAXP=${#FILENAMES_G[@]}/$MAXFILENO
81
82     # don't show empty page if list just fits on screen
83     local rmd=0
84     let rmd=${#FILENAMES_G[@]}%$MAXFILENO
85     if [ $rmd -eq 0 ]
86     then
87         let MAXP-=1;
88     fi
89 }
90
91 # print string, notifying user if it doesn't fit in one line. takes one parameter
92 function printString
93 {
94     echo -n ${1:0:$TERM_W}
95     if [[ $TERM_W -lt ${#1} ]]
96     then
97         tput cub 1;
98         tput setab 1; tput smso; echo -n '>'; tput el; tput rmso
99         return 1
100     else
101         tput el
102         return 0
103     fi
104 }
105
106 # print string, clear until end of line, print newline. takes one parameter
107 function printLine
108 {
109     printString "$1"
110     local RET=$?
111     printf '\n'
112     return $RET
113 }
114
115 function parseCmdLine
116 {
117     if [[ $# -lt 1 ]]
118     then
119         # try using dlogutil
120         if [[ ! -e "$DLOGUTIL" ]]
121         then
122             echo "dlogutil not installed"
123             usage
124             exit 1
125         fi
126
127         INPUTFILE="$DLOGTEMPFILE"
128         USING_DLOG=true
129     else
130         # check if help is requested
131         if [[ $1 == '-h' || $1 == '--help' ]]
132         then
133             usage
134             exit 0
135         # try reading from file
136         else
137             INPUTFILE=$1
138             if [[ ! -e "$INPUTFILE" ]]
139             then
140                 echo cannot read file "$INPUTFILE"
141                 usage
142                 exit 1
143             fi
144         fi
145     fi
146 }
147
148 # print filename or basename or "..." depending on terminal size, takes one parameter
149 function printPath
150 {
151     if [ -z "$1" ]
152     then
153         echo "ERROR in printPath";
154         cleanup; exit 1
155     fi
156
157     FILENAME="$1"
158     FBASENAME=$(basename $FILENAME)
159     if [[ ${#FILENAME} -lt $TERM_W ]]
160     then
161         printLine "$FILENAME"
162     else
163         if [[ ${#FBASENAME} -lt $TERM_W ]]
164         then
165             printLine "$FBASENAME"
166         else
167             printLine ...
168         fi
169     fi
170 }
171
172 ###################################memory query functions
173 function getGpuMemUsage
174 {
175   GPUMEM=0
176   local i=0
177   for state in ${STATES_G[@]}
178   do
179     if [[ $state == 1 || $state == 2 ]]
180     then
181       let GPUMEM+=${SIZES_G[$i]}
182     fi
183     let i+=1
184   done
185   return $GPUMEM
186 }
187
188 function getCpuMemUsage
189 {
190   CPUMEM=0
191   local i=0
192   for state in ${STATES_G[@]}
193   do
194     if [[ $state == 0 || $state == 1 ]]
195     then
196       let CPUMEM+=${SIZES_G[$i]}
197     fi
198     let i+=1
199   done
200   return $CPUMEM
201 }
202
203 function getAtlasNumber
204 {
205   ATLAS_NO=0
206   local i=0
207   for bitmap in ${BITMAPS_G[@]}
208   do
209     if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
210     then
211       let ATLAS_NO+=1
212     fi
213     let i+=1
214   done
215   return $ATLAS_NO
216 }
217
218 function getAtlasMemUsage
219 {
220   ATLASMEM=0
221   local i=0
222   for bitmap in ${BITMAPS_G[@]}
223   do
224     if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
225     then
226       let ATLASMEM+=${SIZES_G[$i]}
227     fi
228     let i+=1
229   done
230   return $ATLASMEM
231 }
232
233 ##################################global arrays manipulation
234 #adds record to resource list
235 #params: filename, bitmap, texture, state, size, size detail
236 function addRecord
237 {
238   if [ $# -ne 6 ]
239   then
240     error "addRecord - number of arguments is $#"
241   fi
242   FILENAMES_G+=("$1")
243   BITMAPS_G+=("$2")
244   TEXTURES_G+=("$3")
245   STATES_G+=("$4")
246   SIZES_G+=("$5")
247   SIZE_DETAILS_G+=("$6")
248 }
249
250 #adds image resource to list
251 #params: filename, bitmap, size, size detail
252 function fileLoaded
253 {
254   if [ $# -ne 4 ]
255   then
256     error "fileLoaded"
257   fi
258   FILENAMES_G+=("$1")
259   BITMAPS_G+=("$2")
260   SIZES_G+=("$3")
261   SIZE_DETAILS_G+=("$4")
262   TEXTURES_G+=(0)
263   STATES_G+=(0)
264 }
265
266 #params: texture, size, size detail
267 function atlasUploaded
268 {
269   FILENAMES_G+=("-")
270   BITMAPS_G+=("$BITMAP_ID_ATLAS")
271   TEXTURES_G+=("$1")
272   STATES_G+=(2)
273   SIZES_G+=("$2")
274   SIZE_DETAILS_G+=("$3")
275 }
276
277 #params: size, size detail
278 function frameBufUploaded
279 {
280   FILENAMES_G+=("$1")
281   BITMAPS_G+=("$BITMAP_ID_FB_TEXTURE")
282   TEXTURES_G+=("$2")
283   STATES_G+=(2)
284   SIZES_G+=("$3")
285   SIZE_DETAILS_G+=("$4")
286 }
287
288
289 ##################################log parsing functions
290 function checkLoaded
291 {
292   if [[ "$1" =~ .*DALI.*[LOAD].*file\ (.*)\ to\ Bitmap\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
293   then
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]}"
298
299     local found=0
300
301     #check if file was loaded before with same size
302     local i=0
303     if [ ${#FILENAMES_G[@]} -ne 0 ]
304     then
305
306     for filenameIter in ${FILENAMES_G[@]}
307     do
308       if [[ "$filenameIter" == "$FILENAME" ]]
309       then
310         if [[ ${SIZES_G[$i]} == "$SIZE" && ${SIZE_DETAILS_G[$i]} == "$SIZE_DETAILS" ]]
311         then
312           found=1
313           case ${STATES_G[$i]} in
314             0) #CPU
315               BITMAPS_G[$i]="$BITMAP"
316               ;;
317             1) #CPUGPU
318               BITMAPS_G[$i]="$BITMAP"
319               ;;
320             2) #GPU
321               STATES_G[$i]=1 #GPU->CPUGPU  loaded into memory again
322               BITMAPS_G[$i]="$BITMAP"
323               ;;
324             3) #DISC
325               #previously discarded, load again
326               STATES_G[$i]=0
327               BITMAPS_G[$i]="$BITMAP"
328               ;;
329             *)
330               error "checkLoaded - unknown state"
331               ;;
332           esac
333         else
334           #filename is same, but its loaded in different size
335           :
336         fi
337       fi
338       let i+=1
339     done
340     fi
341
342     if [ $found -ne 1 ]
343     then
344       fileLoaded "$FILENAME" "$BITMAP" "$SIZE" "$SIZE_DETAILS"
345     fi
346
347     return 0
348   else
349     error "checkLoaded"
350   fi
351 }
352
353 function checkUploaded
354 {
355   if [[ "$1" =~ .*DALI.*[UPLOAD].*Bitmap\ (.*)\ to\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
356   then
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]}"
361
362     local i=0
363     local lastIdx=-1
364
365     if [[ "$BITMAP" =~ \(nil\) ]]
366     then
367       atlasUploaded $TEXTURE $SIZE "$SIZE_DETAILS"
368       return 0
369     else
370       #not a texture atlas
371       if [ ${#BITMAPS_G[@]} -ne $BITMAP_ID_ATLAS ]
372       then
373         for bitmap in ${BITMAPS_G[@]}
374         do
375           if [ $bitmap == $BITMAP ]
376           then
377             lastIdx=$i
378           fi
379         let i+=1
380         done
381       fi
382     fi
383
384     if [ $lastIdx != -1 ]
385     then
386       #Bitmap found
387       if [[ ${TEXTURES_G[$lastIdx]} == 0 && ${STATES_G[$lastIdx]} == 0 ]]
388       then
389         #File loaded in memory -> upload to GPU
390         TEXTURES_G[$lastIdx]="$TEXTURE"
391         STATES_G[$lastIdx]=1
392       elif [[ ${FILENAMES_G[$lastIdx]} == "-" && ${STATES_G[$lastIdx]} == 1 ]]
393       then
394         #BufferImage already in memory and GPU mem. -> updated
395         SIZES_G[$lastIdx]=$SIZE
396         SIZE_DETAILS_G[$lastIdx]="$SIZE_DETAILS"
397       else
398         #bitmap uploaded to new texture
399         addRecord ${FILENAMES_G[$lastIdx]} $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
400       fi
401     else
402       #bitmapImage - not loaded from file
403       #newly added
404       addRecord "-" $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
405     fi
406     return 0
407   elif [[ "$1" =~ .*DALI.*[UPLOAD].*FrameBufferTexture\ (.*)\ GL\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
408   then
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"
414     return 0
415   else
416     echo "$1"
417     error "checkUploaded"
418   fi
419 }
420
421 function checkDeletedBuf
422 {
423   if [[ "$1" =~ .*DALI.*[DELBUF].*Bitmap\ (.*)\ -\ .*size\ (.*) ]]
424   then
425     local BITMAP=${BASH_REMATCH[1]}
426     local i=0
427
428     for bitmap in ${BITMAPS_G[@]}
429     do
430       if [ $bitmap == "$BITMAP" ]
431       then
432         case ${STATES_G[$i]} in
433         0)
434             STATES_G[$i]=3 #CPU->DISC
435             ;;
436         1)
437             STATES_G[$i]=2 #CPUGPU->GPU
438             ;;
439         2)
440             #GPU->?
441             #probably previously freed bitmap buffer but memory is reused since
442             ;;
443         3)
444             #DISC->?
445             #probably previously freed but memory is reused since
446             ;;
447         *)
448             error "checkDeletedBuf - unkown state"
449             ;;
450         esac
451       fi
452     let i+=1
453     done
454
455     return 0
456   else
457     echo "$1"
458     error "checkDeletedBuf"
459   fi
460 }
461
462 function checkDeletedTexture
463 {
464   if [[ "$1" =~ .*DALI.*[DELTEXTURE].*Texture\ (.*)\ -\ size\ (.*) ]]
465   then
466     local TEXTURE="${BASH_REMATCH[1]}"
467     local i=0
468     local lastIdx=-1
469
470     for texture in ${TEXTURES_G[@]}
471     do
472       if [ $texture == $TEXTURE ]
473       then
474         lastIdx=$i
475       fi
476     let i+=1
477     done
478
479     if [ $lastIdx != -1 ]
480     then
481       case ${STATES_G[$lastIdx]} in
482       0)
483           #CPU->?
484           echo "$1"
485           error "checkDeletedTexture - state CPU"
486           ;;
487       1)
488           STATES_G[$lastIdx]=0 #CPUGPU->CPU
489           ;;
490       2)
491           STATES_G[$lastIdx]=3 #GPU->DISC
492           ;;
493       3)
494           #DISC->?
495           echo "$1"
496           error "checkDeletedTexture - state DISC"
497           ;;
498       *)
499           error "checkDeletedTexture - unkown state"
500           ;;
501       esac
502     else
503       echo "$1"
504       error "checkDeletedTexture - texture not uploaded"
505     fi
506     return 0
507   else
508     echo "$1"
509     error "checkDeletedTexture"
510   fi
511 }
512
513 function processLine
514 {
515   if [[ "$1" =~ .*DALI.*\ \[(.*)\].* ]]
516   then
517     RESCMD=${BASH_REMATCH[1]}
518     case "$RESCMD" in
519     LOAD)
520         checkLoaded "$1"
521         ;;
522     UPLOAD)
523         checkUploaded "$1"
524         ;;
525     DELBUF)
526         checkDeletedBuf "$1"
527         ;;
528     DELTEXTURE)
529         checkDeletedTexture "$1"
530         ;;
531     INIT)
532         ;;
533     FIN)
534         return 1 #end of last log session
535         ;;
536     *)
537         error "Unkown command $RESCMD"
538         ;;
539     esac
540   fi
541   return 0
542 }
543
544 function parseFile
545 {
546   if [ -z "$1" ]
547   then
548     echo "ERROR in parseFile";
549     cleanup; exit 1
550   fi
551
552   #return if file does not contain dali resource log
553   if ! grep -q -m 1 -E "DALI.*\[INIT\]" $1
554   then
555     return 1
556   fi
557
558   #find last resource log session
559   local LOGBUFFER=$(sed -n 'H; /DALI.*\[INIT\]/h; ${g;p;}' $1)
560
561   while read -r line
562   do
563     #show PID of last process
564     PID_G=$(echo "$line" | sed 's/[^0-9]*\([0-9]*\).*/\1/')
565     if [ ! -z "$PID_G" ]
566     then
567       break
568     fi
569   done <<< "$LOGBUFFER"
570
571   while read -r line
572   do
573     if ! processLine "$line" #stop parsing at the end of last session
574     then
575       break
576     fi
577   done <<< "$LOGBUFFER"
578 }
579
580 ##################################draw and main functions
581 function redraw
582 {
583   tput cup 0 0 #move cursor to top left
584
585   # print info (4 lines)
586   tput bold
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";
592   tput sgr0
593
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)"
597   local FILL_W=0
598   let FILL_W=$TERM_W-${#PAGEIND}
599   tput setab 4; printf $PAGEIND%"$FILL_W"s; printf '\n'; tput sgr0
600
601   # print filenames
602   local count=0
603   local index=0
604   let index=$CURPAGE*$MAXFILENO
605
606   filecount=${#FILENAMES_G[@]}
607
608   tput setaf 252
609
610   while [[ $count -lt $MAXFILENO ]]
611   do
612     if [[ $index -lt $filecount ]]
613     then
614       tput setab ${COLORS[${STATES_G[$index]}]}
615 #     printPath "${FILENAMES_G[$count]}"
616       printLine "${FILENAMES_G[$index]} ${SIZES_G[$index]} ${SIZE_DETAILS_G[$index]}"
617     else
618       tput sgr0
619       printLine "" #clear remaining lines to fill screen
620     fi
621     let count+=1
622     let index+=1
623   done
624
625   # print keyboard shortcuts
626   tput setab 4; tput bold
627   IFS= printString "  |  n: next page  |  p: previous page  |  ^C: exit  |  Resource state: "
628   # print color codes
629   if [[ $TERM_W -gt 100 ]]
630   then
631     tput setab ${COLORS[0]}
632     echo -n " CPU "
633     tput setab ${COLORS[1]}
634     echo -n " CPUGPU "
635     tput setab ${COLORS[2]}
636     echo -n " GPU "
637     tput setab ${COLORS[3]}
638     echo -n " DISCARDED "
639   fi
640
641   tput sgr0
642 }
643
644 function readInput
645 {
646     local key
647     read -n1 -t 0.3 key
648
649     case "$key" in
650         'p')
651             if [[ $CURPAGE -ne 0 ]]
652             then
653               let CURPAGE-=1
654             fi
655             ;;
656         'n')
657             if [[ $CURPAGE -lt $MAXP ]]
658             then
659               let CURPAGE+=1
660             fi
661             ;;
662     esac
663 }
664
665 function initVars
666 {
667   FILENAMES_G=( )
668   BITMAPS_G=( )
669   TEXTURES_G=( )
670   SIZES_G=( )
671   SIZE_DETAILS_G=( )
672   STATES_G=( )
673 }
674
675 function cleanup
676 {
677   tput cup 9999 0 #go to bottom of screen
678   tput cnorm #show cursor
679   tput sgr0
680   if [ -f "$DLOGTEMPFILE" ]
681   then
682     rm "$DLOGTEMPFILE"
683   fi
684 }
685
686 function update
687 {
688   initVars
689   if [ -n "$USING_DLOG" ]
690   then
691     if [ -f "$DLOGTEMPFILE" ]
692     then
693       rm "$DLOGTEMPFILE"
694     fi
695     "$DLOGUTIL" DALI:I -d -f "$DLOGTEMPFILE" 2>/dev/null
696   fi
697
698   if [ ! -e "$INPUTFILE" ]
699   then
700     return 1
701   fi
702
703   parseFile "$INPUTFILE"
704
705   if [[ $? -gt 0 || ${#STATES_G[@]} -lt 1 ]]
706   then
707     return 1
708   fi
709
710   getCpuMemUsage
711   getGpuMemUsage
712   getAtlasMemUsage
713   getAtlasNumber
714
715   getTermSize
716   readInput
717   redraw
718 }
719
720 function main
721 {
722   parseCmdLine $@
723
724   if [ -z "$INPUTFILE" ]
725   then
726     echo No input file specified;
727     cleanup
728     exit 1
729   fi
730
731   tput civis #hide cursor
732   tput clear #clear screen
733
734   echo "waiting for log..."
735
736   while [ 1 ]
737   do
738     update
739 #    sleep 0.3  # we are now reading input for 0.3
740   done
741
742   cleanup
743 }
744
745 trap "cleanup; exit 0" SIGINT SIGTERM  #reset terminal when ^C is pressed
746 # trap "getTermSize" SIGWINCH            #handle window resize
747
748 main $@