3cee791f13c664935d181265a71dee3d0f30492a
[pstop.git] / lib / common.go
1 // package lib - common routines for pstop
2 package lib
3
4 import (
5         "fmt"
6         _ "github.com/go-sql-driver/mysql"
7         _ "github.com/sjmudd/pstop/version"
8         "strconv"
9 )
10
11 const (
12         myname    = "pstop"
13         copyright = "Copyright (C) 2014 Simon J Mudd <sjmudd@pobox.com>"
14         i_1024_2  = 1024 * 1024
15         i_1024_3  = 1024 * 1024 * 1024
16         i_1024_4  = 1024 * 1024 * 1024 * 1024
17 )
18
19 // myround converts this floating value to the right width etc.
20 // There must be a function in Go to do this. Find it.
21 func myround(f float64, width, decimals int) string {
22         format := "%" + fmt.Sprintf("%d", width) + "." + fmt.Sprintf("%d", decimals) + "f"
23         return fmt.Sprintf(format, f)
24 }
25
26 // MyName returns the program's name.
27 func MyName() string {
28         return myname
29 }
30
31 // Copyright provides a copyright message for pstop
32 func Copyright() string {
33         return copyright
34 }
35
36 // sec_to_time() converts a number of hours, minutes and seconds into hh:mm:ss format.
37 // e.g. 7384 = 2h 3m 4s, 7200 + 180 + 4
38 func sec_to_time(d uint64) string {
39         hours := d / 3600                // integer value
40         minutes := (d - hours*3600) / 60 // integer value
41         seconds := d - hours*3600 - minutes*60
42
43         return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
44 }
45
46 // similar to sec_to_time() spaces if 0 and takes seconds as input.
47 func FormatSeconds(seconds uint64) string {
48         if seconds == 0 {
49                 return "        "
50         } else {
51                 return sec_to_time(seconds)
52         }
53 }
54
55 // FormatTime is based on sys.format_time. It
56 // formats to 10 characters including space and suffix.
57 // All values have 2 decimal places. Zero is returned as
58 // an empty string.
59 func FormatTime(picoseconds uint64) string {
60         if picoseconds == 0 {
61                 return ""
62         }
63         if picoseconds >= 3600000000000000 {
64                 return myround(float64(picoseconds)/3600000000000000, 8, 2) + " h"
65         }
66         if picoseconds >= 60000000000000 {
67                 return sec_to_time(picoseconds / 1000000000000)
68         }
69         if picoseconds >= 1000000000000 {
70                 return myround(float64(picoseconds)/1000000000000, 8, 2) + " s"
71         }
72         if picoseconds >= 1000000000 {
73                 return myround(float64(picoseconds)/1000000000, 7, 2) + " ms"
74         }
75         if picoseconds >= 1000000 {
76                 return myround(float64(picoseconds)/1000000, 7, 2) + " us"
77         }
78         if picoseconds >= 1000 {
79                 return myround(float64(picoseconds)/1000, 7, 2) + " ns"
80         }
81         return strconv.Itoa(int(picoseconds)) + " ps"
82 }
83
84 // FormatPct() formats a floating point number as a percentage
85 // including the trailing % sign. Print the value as a %5.1f with
86 // a % suffix if there's a value.
87 // If the value is 0 print as 6 spaces.
88 // if the value is > 999.9 then show +++.+% to indicate an overflow.
89 func FormatPct(pct float64) string {
90         var s string
91         if pct < 0.0001 {
92                 s = "      "
93         } else if pct > 999.9 {
94                 s = "+++.+%" // too large to fit! (probably a bug as we don't expect this value to be > 100.00)
95         } else {
96                 s = fmt.Sprintf("%5.1f", 100.0*pct) + "%"
97         }
98
99         return s
100 }
101
102 // FormatAmount() convert numbers to k = 1024 , M = 1024 x 1024, G = 1024 x 1024 x 1024, P = 1024x1024x1024x1024.
103 // For values = 0 return an empty string.
104 // For values < 1000 show 6,2 decimal places.
105 // For values >= 1000 show 6,1 decimal place.
106 func FormatAmount(amount uint64) string {
107         var suffix string
108         var formatted string
109         var decimal_amount float64
110
111         if amount == 0 {
112                 return ""
113         }
114         if amount <= 1024 {
115                 return strconv.Itoa(int(amount))
116         }
117
118         if amount > i_1024_4 {
119                 suffix = "P"
120                 decimal_amount = float64(amount) / i_1024_4
121         } else if amount > i_1024_3 {
122                 suffix = "G"
123                 decimal_amount = float64(amount) / i_1024_3
124         } else if amount > i_1024_2 {
125                 suffix = "M"
126                 decimal_amount = float64(amount) / i_1024_2
127         } else if amount > 1024 {
128                 suffix = "k"
129                 decimal_amount = float64(amount) / 1024
130         }
131
132         if decimal_amount > 1000.0 {
133                 formatted = fmt.Sprintf("%6.1f %s", decimal_amount, suffix)
134         } else {
135                 formatted = fmt.Sprintf("%6.2f %s", decimal_amount, suffix)
136         }
137         return formatted
138 }
139
140 // like Amount but tigher in space
141 func FormatCounter( counter int, width int ) string {
142         if counter == 0 {
143                 pattern := "%" + fmt.Sprintf("%d", width) + "s"
144                 return fmt.Sprintf( pattern, " " )
145         } else {
146                 pattern := "%" + fmt.Sprintf("%d", width) + "d"
147                 return fmt.Sprintf( pattern, counter )
148         }
149 }
150
151 // MyDivide() divides a by b except if b is 0 in which case we return 0.
152 func MyDivide(a uint64, b uint64) float64 {
153         if b == 0 {
154                 return float64(0)
155         } else {
156                 return float64(a) / float64(b)
157         }
158 }
159
160 // Uptime() provides a  usable form of uptime.
161 // Note: this doesn't return a string of a fixed size!
162 // Minimum value: 1s.
163 // Maximum value: 100d 23h 59m 59s (sort of).
164 func Uptime(uptime int) string {
165         var result string
166
167         days := uptime / 24 / 60 / 60
168         hours := (uptime - days*86400) / 3600
169         minutes := (uptime - days*86400 - hours*3600) / 60
170         seconds := uptime - days*86400 - hours*3600 - minutes*60
171
172         result = strconv.Itoa(seconds) + "s"
173
174         if minutes > 0 {
175                 result = strconv.Itoa(minutes) + "m " + result
176         }
177         if hours > 0 {
178                 result = strconv.Itoa(hours) + "h " + result
179         }
180         if days > 0 {
181                 result = strconv.Itoa(days) + "d " + result
182         }
183
184         return result
185 }