Output to files from ps2dot
[khome.git] / home / bin / ps2dot
index 1db1ce4..c6bf85f 100755 (executable)
 #! /bin/sh
 
+set -e
+
 usage() {
     echo "EXAMPLE (whole tree)   : $0 | neato -T png > ps.png && open ps.png"
     echo "EXAMPLE (user clusters): $0 | sdp   -T png > ps.png && open ps.png"
 }
 
 
-compile() {
+ps2dot() {
     awk -v kernel="$(uname -v)" -v whoami="$(whoami)" \
     '
         function num_scale(src_cur, src_max, dst_min, dst_max) {
             return dst_min + ((src_cur * (dst_max - dst_min)) / src_max)
         }
 
-        function vert_print(v,    _color) {
+        function vert_print(v,    _color, _fontcolor, _shape, _state, _size, _height, _label, _label_base, _label_ext) {
+            _state = child2state[v]
+            _style = "filled,solid"
+
+            # -----------------------------------------------------------------
+            # Sleeping/idling
+            # -----------------------------------------------------------------
+            # D uninterruptible sleep (usually IO)
+            if (_state == "D") {
+                _shape = "circle"
+            # I Idle kernel thread
+            } else if (_state == "I") {
+                _shape = "circle"
+            # S interruptible sleep (waiting for an event to complete)
+            } else if (_state == "S") {
+                _shape = "circle"
+            # -----------------------------------------------------------------
+            # Running
+            # -----------------------------------------------------------------
+            # R running or runnable (on run queue)
+            } else if (_state == "R") {
+                _shape = "rarrow"
+            # -----------------------------------------------------------------
+            # Stopped
+            # -----------------------------------------------------------------
+            # T stopped by job control signal
+            } else if (_state == "T") {
+                _shape = "square"
+            # t stopped by debugger during the tracing
+            } else if (_state == "t") {
+                _shape = "square"
+            # -----------------------------------------------------------------
+            # Dead
+            # -----------------------------------------------------------------
+            # Z defunct ("zombie") process, terminated but not reaped by its parent
+            } else if (_state == "Z") {
+                _shape = "Msquare"
+                _style = "solid"
+            # -----------------------------------------------------------------
+            # UNKNOWN STATE
+            # -----------------------------------------------------------------
+            } else {
+                _shape = "doublecircle"
+            }
+
             _color =\
                 num_scale(\
-                    parent2child_count[v],
-                    max_children,
-                    COLORSCHEME_MIN,
-                    COLORSCHEME_MAX\
+                    child2cpu[v],
+                    max_cpu,
+                    VERT_COLORSCHEME_MAX,
+                    VERT_COLORSCHEME_MIN\
                 )
-            fontcolor = _color >= 5 ? 1 : 9
+            _size =\
+                num_scale(\
+                    child2mem[v],
+                    max_mem,
+                    1,
+                    4\
+                ) / 4
+            _height = _size
+            _width  = _size
+            _fontcolor = \
+                _color == VERT_COLORSCHEME_MAX || _color == VERT_COLORSCHEME_MIN \
+                ? sprintf("/%s/%d", VERT_COLORSCHEME, VERT_COLORSCHEME_MID) \
+                : sprintf("/%s/%d", "greys9", 9)
+            _fontcolor = \
+                _size < 0.5 \
+                ? sprintf("/%s/%d", "greys9", 9) \
+                : _fontcolor
+            _label_base = \
+                sprintf("%s\n%d", child2comm[v], v)
+            _label_ext = \
+                _size >= 0.5 \
+                ? sprintf("\ncpu: %.1f%%\nmem: %.1f%%", child2cpu[v], child2mem[v]) \
+                : ""
+            _label = _label_base _label_ext
             printf(\
                 "\"%d\"\
                 [ fontsize=8 \
-                , style=filled \
+                , fixedsize=true \
+                , height=%f \
+                , width=%f \
+                , border=1 \
+                , style=\"%s\" \
                 , fontname=Helvetica \
-                , shape=ellipse \
-                , label=\"%s\n%d\" \
-                , colorscheme=%s \
-                , color=%d \
-                , fontcolor=%d \
+                , label=\"%s\" \
+                , shape=\"%s\" \
+                , fillcolor=\"/%s/%d\" \
+                , fontcolor=\"%s\" \
                 ];",
                 v,
-                child2cmd[v],
-                v,
-                COLORSCHEME,
+                _height,
+                _width,
+                _style,
+                _label,
+                _shape,
+                VERT_COLORSCHEME,
                 _color,
-                fontcolor\
+                _fontcolor\
             )
         }
 
-        function edge_print(child,    _parent, _color) {
+        function edge_print(child,    _parent) {
             _parent = child2parent[child]
-            _color =\
-                num_scale(\
-                    parent2child_count[_parent],
-                    max_children,
-                    COLORSCHEME_MIN,
-                    COLORSCHEME_MAX\
-                )
             printf(\
                 "\"%s\" -> \"%s\"\
                 [ fontsize=8 \
                 , fontname=Helvetica \
                 , len=2.0 \
-                , colorscheme=%s \
-                , color=%d \
+                , color=\"%s\" \
                 ];\n",
                 _parent,
                 child,
-                COLORSCHEME,
-                _color\
+                EDGE_COLOR\
             )
         }
 
         BEGIN {
-            COLORSCHEME = "orrd9"
-            # Good gradient colorschemes:
-            # - "orrd9"
-            # - "oranges9"
-            # - "bupu9"
-            # - "greys9"
-
-            COLORSCHEME_MIN = 2
-            COLORSCHEME_MAX = 9
-            child2cmd[0] = "swapper/sched"
+            # Hot->Cold gradual colorschemes:
+            # - rdbu11
+            # - rdbu9
+            # - rdbu8
+            # - rdylgn10  # 3 - 11
+
+            # Light->Dark gradual colorschemes:
+            # - reds9
+            # - blues9
+            # - orrd9
+            # - oranges9
+            # - bupu9
+            # - greys9
+
+            VERT_COLORSCHEME_MIN = 1
+            VERT_COLORSCHEME_MID = 4
+            VERT_COLORSCHEME_MAX = 8
+            VERT_COLORSCHEME = "rdylgn10"
+
+            EDGE_COLOR = "/ylorbr9/3"
+
+            child2comm[0] = "swapper/sched"
         }
 
         NR > 1 {
@@ -88,8 +166,14 @@ compile() {
             child2parent[$1]    = $2
             child2user_id[$1]   = $3
             child2user_name[$1] = $4
-            child2cmd[$1]       = $5
+            child2nice[$1]      = $5
+            child2state[$1]     = $6
+            child2cpu[$1]       = $7
+            child2mem[$1]       = $8
+            child2comm[$1]      = $9
             user_names[$4]      = 1
+            max_cpu = $7 > max_cpu ? $7 : max_cpu
+            max_mem = $8 > max_mem ? $8 : max_mem
         }
 
         END {
@@ -99,8 +183,7 @@ compile() {
             print "fontsize=8;";
             print "fontname=Helvetica;";
             print "label=\"" kernel "\";";
-            printf "colorscheme=%s;\n", COLORSCHEME
-            print "fontcolor=9;"
+            print "fontcolor=\"/greys9/9\";"
 
             ##### Vertices (clustered by user)
             for (user_name in user_names) {
@@ -113,7 +196,7 @@ compile() {
             }
 
             ##### Vertices (without a user)
-            for (c in child2cmd)
+            for (c in child2comm)
                 if (!child2user_name[c])
                     vert_print(c)
 
@@ -129,18 +212,31 @@ compile() {
 
 procs() {
     if [ "$(uname)" = 'Linux' ]; then
-        ps -eo pid,ppid,euid,euser,comm
+        ps -eo  'pid,ppid,euid,euser,nice,s,%cpu,%mem,comm'
     else
-        ps -eco pid,ppid,euid,euser,comm
+        ps -eco 'pid,ppid,euid,euser,nice,s,%cpu,%mem,comm'
     fi
 }
 
 
 main() {
     case "$1" in
-        '--help') usage
+        '--help')
+            usage
         ;;
-        *) procs | grep "$1" | compile
+        *)
+            timestamp="$(date +'%Y-%m-%d_%H:%M:%S%z')"
+            host="$(hostname)"
+            kernel="$(uname -s | awk '{print tolower($0)}')"
+            filename_base=$(mktemp "ps.$host.$kernel.$timestamp.XXXXX")
+            file_log="$filename_base.log"
+            file_dot="$filename_base.dot"
+            mv "$filename_base" "$file_log"
+            procs | grep "$1" | ps2dot 2> "$file_log" > "$file_dot"
+            time neato -T png "$file_dot" 2> "$file_log" > "$filename_base.neato.png"
+            time fdp   -T png "$file_dot" 2> "$file_log" > "$filename_base.fdp.png"
+            time dot   -T png "$file_dot" 2> "$file_log" > "$filename_base.dot.png"
+            ls -1 "$filename_base"*
         ;;
     esac
 }
This page took 0.034444 seconds and 4 git commands to generate.