1: /*
2: * unit.c Unit Definitions
3: *
4: * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
5: * Copyright (c) 2013 Red Hat, Inc.
6: *
7: * Permission is hereby granted, free of charge, to any person obtaining a
8: * copy of this software and associated documentation files (the "Software"),
9: * to deal in the Software without restriction, including without limitation
10: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11: * and/or sell copies of the Software, and to permit persons to whom the
12: * Software is furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included
15: * in all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23: * DEALINGS IN THE SOFTWARE.
24: */
25:
26: #include <bmon/bmon.h>
27: #include <bmon/conf.h>
28: #include <bmon/utils.h>
29: #include <bmon/unit.h>
30:
31: static struct unit *byte_unit, *bit_unit;
32:
33: static LIST_HEAD(units);
34:
35: static struct list_head *get_flist(struct unit *unit)
36: {
37: int div = UNIT_DEFAULT;
38:
39: if (cfg_getbool(cfg, "use_bit"))
40: div = UNIT_BIT;
41: else if (cfg_getbool(cfg, "use_si"))
42: div = UNIT_SI;
43:
44: if (!list_empty(&unit->u_div[div]))
45: return &unit->u_div[div];
46: else
47: return &unit->u_div[UNIT_DEFAULT];
48: }
49:
50: struct unit *unit_lookup(const char *name)
51: {
52: struct unit *unit;
53:
54: list_for_each_entry(unit, &units, u_list)
55: if (!strcmp(name, unit->u_name))
56: return unit;
57:
58: return NULL;
59: }
60:
61: /**
62: * Lookup best divisor to use for a certain situation
63: * @hint Value in question (for DYNAMIC_EXP)
64: * @unit Unit of value
65: * @name Place to store name of divisor used
66: * @prec Place to store suggested precision
67: *
68: * Searches for the best divisor to be used depending on the unit
69: * exponent configured by the user. If a dynamic exponent is
70: * configured, the divisor is selected based on the value of hint
71: * so that hint is dividied into a small float >= 1.0. The name
72: * of the divisor used is stored in *name.
73: *
74: * If prec points to a vaild integer, a number of precision digits
75: * is suggested to avoid n.00 to make pretty printing easier.
76: */
77: double unit_divisor(uint64_t hint, struct unit *unit, char **name,
78: int *prec)
79: {
80: struct list_head *flist = get_flist(unit);
81: struct fraction *f;
82:
83: if (prec)
84: *prec = 2;
85:
86: if (cfg_unit_exp == DYNAMIC_EXP) {
87: list_for_each_entry_reverse(f, flist, f_list) {
88: if (hint >= f->f_divisor)
89: goto found_it;
90: }
91: } else {
92: int n = cfg_unit_exp;
93: list_for_each_entry(f, flist, f_list) {
94: if (--n == 0)
95: goto found_it;
96: }
97: }
98:
99: *name = "";
100: return 1;
101:
102: found_it:
103: if (f->f_divisor == 1.0f && prec)
104: *prec = 0;
105:
106: *name = f->f_name;
107: return f->f_divisor;
108: }
109:
110: double unit_value2str(uint64_t value, struct unit *unit,
111: char **name, int *prec)
112: {
113: double div = unit_divisor(value, unit, name, prec);
114: double v = (double) value;
115:
116: if (fmod(v, div) == 0.0f && prec)
117: *prec = 0;
118:
119: return v / div;
120: }
121:
122: void fraction_free(struct fraction *f)
123: {
124: if (!f)
125: return;
126:
127: list_del(&f->f_list);
128: xfree(f->f_name);
129: xfree(f);
130: }
131:
132: void unit_add_div(struct unit *unit, int type, const char *txt, float div)
133: {
134: struct fraction *f;
135:
136: if (!unit)
137: BUG();
138:
139: f = xcalloc(1, sizeof(*f));
140:
141: init_list_head(&f->f_list);
142:
143: f->f_divisor = div;
144: f->f_name = strdup(txt);
145:
146: list_add_tail(&f->f_list, &unit->u_div[type]);
147: }
148:
149: struct unit *unit_add(const char *name)
150: {
151: struct unit *unit;
152: int i;
153:
154: if (!(unit = unit_lookup(name))) {
155: unit = xcalloc(1, sizeof(*unit));
156: unit->u_name = strdup(name);
157:
158: for (i = 0; i < __UNIT_MAX; i++)
159: init_list_head(&unit->u_div[i]);
160:
161: list_add_tail(&unit->u_list, &units);
162: }
163:
164: return unit;
165: }
166:
167: static void unit_free(struct unit *u)
168: {
169: struct fraction *f, *n;
170:
171: if (!u)
172: return;
173:
174: list_for_each_entry_safe(f, n, &u->u_div[UNIT_DEFAULT], f_list)
175: fraction_free(f);
176:
177: list_for_each_entry_safe(f, n, &u->u_div[UNIT_SI], f_list)
178: fraction_free(f);
179:
180: xfree(u->u_name);
181: xfree(u);
182: }
183:
184: char *unit_bytes2str(uint64_t bytes, char *buf, size_t len)
185: {
186: char *ustr;
187: int prec;
188: double v;
189:
190: if (byte_unit) {
191: v = unit_value2str(bytes, byte_unit, &ustr, &prec);
192: snprintf(buf, len, "%'.*f%3s", prec, v, ustr);
193: } else
194: snprintf(buf, len, "%" PRIu64, bytes);
195:
196: return buf;
197: }
198:
199: char *unit_bit2str(uint64_t bits, char *buf, size_t len)
200: {
201: char *ustr;
202: int prec;
203: double v;
204:
205: if (bit_unit) {
206: v = unit_value2str(bits, bit_unit, &ustr, &prec);
207: snprintf(buf, len, "%'.*f%3s", prec, v, ustr);
208: } else
209: snprintf(buf, len, "%" PRIu64, bits);
210:
211: return buf;
212: }
213:
214: static void __exit unit_exit(void)
215: {
216: struct unit *u, *n;
217:
218: list_for_each_entry_safe(u, n, &units, u_list)
219: unit_free(u);
220: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>