blob: ae16d8548fccbd82b0b200a9f1bce53e76a182f9 [file] [log] [blame]
Denis Vlasenko1db39b22006-10-11 20:59:02 +00001/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02002 * Licensed under GPLv2, see file LICENSE in this source tree.
3 *
4 * Based on nanotop.c from floppyfw project
5 *
Denys Vlasenkobdaea462010-08-16 20:42:14 +02006 * Contact me: vda.linux@googlemail.com
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 */
Denys Vlasenkoa6041862010-12-13 15:17:22 +01008//config:config NMETER
Denys Vlasenkob097a842018-12-28 03:20:17 +01009//config: bool "nmeter (11 kb)"
Denys Vlasenkoa6041862010-12-13 15:17:22 +010010//config: default y
11//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020012//config: Prints selected system stats continuously, one line per update.
Denys Vlasenkoa6041862010-12-13 15:17:22 +010013
Denys Vlasenkob9f2d9f2011-01-18 13:58:01 +010014//applet:IF_NMETER(APPLET(nmeter, BB_DIR_USR_BIN, BB_SUID_DROP))
Denys Vlasenkoa6041862010-12-13 15:17:22 +010015
16//kbuild:lib-$(CONFIG_NMETER) += nmeter.o
17
18//usage:#define nmeter_trivial_usage
19//usage: "[-d MSEC] FORMAT_STRING"
20//usage:#define nmeter_full_usage "\n\n"
21//usage: "Monitor system in real time"
22//usage: "\n"
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +010023//usage: "\n -d MSEC Milliseconds between updates, default:1000, none:-1"
Denys Vlasenkoa6041862010-12-13 15:17:22 +010024//usage: "\n"
25//usage: "\nFormat specifiers:"
Denys Vlasenkof3d705f2017-01-21 03:46:35 +010026//usage: "\n %Nc or %[cN] CPU. N - bar size (default 10)"
Denys Vlasenkoa6041862010-12-13 15:17:22 +010027//usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)"
Denys Vlasenkoabb09522011-05-26 09:00:23 +020028//usage: "\n %[nINTERFACE] Network INTERFACE"
29//usage: "\n %m Allocated memory"
30//usage: "\n %[mf] Free memory"
31//usage: "\n %[mt] Total memory"
32//usage: "\n %s Allocated swap"
33//usage: "\n %f Number of used file descriptors"
34//usage: "\n %Ni Total/specific IRQ rate"
35//usage: "\n %x Context switch rate"
36//usage: "\n %p Forks"
37//usage: "\n %[pn] # of processes"
38//usage: "\n %b Block io"
39//usage: "\n %Nt Time (with N decimal points)"
Denys Vlasenkoa6041862010-12-13 15:17:22 +010040//usage: "\n %r Print <cr> instead of <lf> at EOL"
41
Denis Vlasenko1db39b22006-10-11 20:59:02 +000042//TODO:
43// simplify code
44// /proc/locks
45// /proc/stat:
46// disk_io: (3,0):(22272,17897,410702,4375,54750)
47// btime 1059401962
Denis Vlasenkoa6163ca2007-06-17 00:35:15 +000048//TODO: use sysinfo libc call/syscall, if appropriate
49// (faster than open/read/close):
50// sysinfo({uptime=15017, loads=[5728, 15040, 16480]
51// totalram=2107416576, freeram=211525632, sharedram=0, bufferram=157204480}
52// totalswap=134209536, freeswap=134209536, procs=157})
Denis Vlasenko1db39b22006-10-11 20:59:02 +000053
Denis Vlasenkoa6163ca2007-06-17 00:35:15 +000054#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020055#include "common_bufsiz.h"
Denis Vlasenko1db39b22006-10-11 20:59:02 +000056
57typedef unsigned long long ullong;
Denis Vlasenko1db39b22006-10-11 20:59:02 +000058
Denis Vlasenkobfc93a32008-09-26 11:12:09 +000059enum { /* Preferably use powers of 2 */
60 PROC_MIN_FILE_SIZE = 256,
61 PROC_MAX_FILE_SIZE = 16 * 1024,
62};
Denis Vlasenko1db39b22006-10-11 20:59:02 +000063
64typedef struct proc_file {
Denis Vlasenko1db39b22006-10-11 20:59:02 +000065 char *file;
Denis Vlasenkobfc93a32008-09-26 11:12:09 +000066 int file_sz;
Denis Vlasenko199c0d52007-05-30 14:48:38 +000067 smallint last_gen;
Denis Vlasenko1db39b22006-10-11 20:59:02 +000068} proc_file;
69
Denis Vlasenko199c0d52007-05-30 14:48:38 +000070static const char *const proc_name[] = {
71 "stat", // Must match the order of proc_file's!
72 "loadavg",
73 "net/dev",
74 "meminfo",
75 "diskstats",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000076 "sys/fs/file-nr"
Denis Vlasenko199c0d52007-05-30 14:48:38 +000077};
78
79struct globals {
80 // Sample generation flip-flop
81 smallint gen;
82 // Linux 2.6? (otherwise assumes 2.4)
83 smallint is26;
84 // 1 if sample delay is not an integer fraction of a second
85 smallint need_seconds;
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +010086 char final_char;
Denis Vlasenko199c0d52007-05-30 14:48:38 +000087 char *cur_outbuf;
Denis Vlasenko199c0d52007-05-30 14:48:38 +000088 int delta;
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +010089 unsigned deltanz;
Denis Vlasenko199c0d52007-05-30 14:48:38 +000090 struct timeval tv;
91#define first_proc_file proc_stat
92 proc_file proc_stat; // Must match the order of proc_name's!
93 proc_file proc_loadavg;
94 proc_file proc_net_dev;
95 proc_file proc_meminfo;
96 proc_file proc_diskstats;
97 proc_file proc_sys_fs_filenr;
98};
99#define G (*ptr_to_globals)
100#define gen (G.gen )
101#define is26 (G.is26 )
102#define need_seconds (G.need_seconds )
103#define cur_outbuf (G.cur_outbuf )
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000104#define tv (G.tv )
105#define proc_stat (G.proc_stat )
106#define proc_loadavg (G.proc_loadavg )
107#define proc_net_dev (G.proc_net_dev )
108#define proc_meminfo (G.proc_meminfo )
109#define proc_diskstats (G.proc_diskstats )
110#define proc_sys_fs_filenr (G.proc_sys_fs_filenr)
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +0200111#define outbuf bb_common_bufsiz1
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000112#define INIT_G() do { \
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +0200113 setup_common_bufsiz(); \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000114 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
115 cur_outbuf = outbuf; \
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100116 G.final_char = '\n'; \
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100117 G.deltanz = G.delta = 1000000; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000118} while (0)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000119
120static inline void reset_outbuf(void)
121{
122 cur_outbuf = outbuf;
123}
124
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000125static void print_outbuf(void)
126{
127 int sz = cur_outbuf - outbuf;
128 if (sz > 0) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000129 xwrite(STDOUT_FILENO, outbuf, sz);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000130 cur_outbuf = outbuf;
131 }
132}
133
134static void put(const char *s)
135{
Denys Vlasenko99c71c92016-03-15 15:28:49 +0100136 char *p = cur_outbuf;
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +0200137 int sz = outbuf + COMMON_BUFSIZE - p;
Denys Vlasenko99c71c92016-03-15 15:28:49 +0100138 while (*s && --sz >= 0)
139 *p++ = *s++;
140 cur_outbuf = p;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000141}
142
143static void put_c(char c)
144{
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +0200145 if (cur_outbuf < outbuf + COMMON_BUFSIZE)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000146 *cur_outbuf++ = c;
147}
148
149static void put_question_marks(int count)
150{
151 while (count--)
152 put_c('?');
153}
154
Denis Vlasenkobfc93a32008-09-26 11:12:09 +0000155static void readfile_z(proc_file *pf, const char* fname)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000156{
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000157// open_read_close() will do two reads in order to be sure we are at EOF,
158// and we don't need/want that.
Denis Vlasenkobfc93a32008-09-26 11:12:09 +0000159 int fd;
160 int sz, rdsz;
161 char *buf;
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000162
Denis Vlasenkobfc93a32008-09-26 11:12:09 +0000163 sz = pf->file_sz;
164 buf = pf->file;
165 if (!buf) {
166 buf = xmalloc(PROC_MIN_FILE_SIZE);
167 sz = PROC_MIN_FILE_SIZE;
168 }
169 again:
170 fd = xopen(fname, O_RDONLY);
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000171 buf[0] = '\0';
Denis Vlasenkobfc93a32008-09-26 11:12:09 +0000172 rdsz = read(fd, buf, sz-1);
Denis Vlasenkobc2fd372008-06-30 07:33:52 +0000173 close(fd);
Denis Vlasenkobfc93a32008-09-26 11:12:09 +0000174 if (rdsz > 0) {
175 if (rdsz == sz-1 && sz < PROC_MAX_FILE_SIZE) {
176 sz *= 2;
177 buf = xrealloc(buf, sz);
178 goto again;
179 }
180 buf[rdsz] = '\0';
181 }
182 pf->file_sz = sz;
183 pf->file = buf;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000184}
185
186static const char* get_file(proc_file *pf)
187{
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000188 if (pf->last_gen != gen) {
189 pf->last_gen = gen;
Denis Vlasenkobfc93a32008-09-26 11:12:09 +0000190 readfile_z(pf, proc_name[pf - &first_proc_file]);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000191 }
192 return pf->file;
193}
194
Denis Vlasenkodadfb492008-07-29 10:16:05 +0000195static ullong read_after_slash(const char *p)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000196{
197 p = strchr(p, '/');
198 if (!p) return 0;
199 return strtoull(p+1, NULL, 10);
200}
201
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100202enum conv_type {
203 conv_decimal = 0,
204 conv_slash = 1
205};
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000206
207// Reads decimal values from line. Values start after key, for example:
208// "cpu 649369 0 341297 4336769..." - key is "cpu" here.
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100209// Values are stored in vec[].
210// posbits is a bit lit of positions we are interested in.
211// for example: 00100110 - we want 1st, 2nd and 5th value.
212// posbits.bit0 encodes conversion type.
213static int rdval(const char* p, const char* key, ullong *vec, long posbits)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000214{
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100215 unsigned curpos;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000216
217 p = strstr(p, key);
218 if (!p) return 1;
219
220 p += strlen(key);
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100221 curpos = 1 << 1;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000222 while (1) {
223 while (*p == ' ' || *p == '\t') p++;
224 if (*p == '\n' || *p == '\0') break;
225
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100226 if (curpos & posbits) { // read this value
227 *vec++ = (posbits & 1) == conv_decimal ?
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000228 strtoull(p, NULL, 10) :
229 read_after_slash(p);
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100230 posbits -= curpos;
231 if (posbits <= 1)
Denys Vlasenkoe4de8c62016-03-15 15:22:42 +0100232 return 0;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000233 }
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100234 while (*p > ' ') // skip over the value
235 p++;
236 curpos <<= 1;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000237 }
238 return 0;
239}
240
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000241// Parses files with lines like "... ... ... 3/148 ...."
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100242static int rdval_loadavg(const char* p, ullong *vec, long posbits)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000243{
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000244 int result;
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100245 result = rdval(p, "", vec, posbits | conv_slash);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000246 return result;
247}
248
249// Parses /proc/diskstats
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100250// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000251// 3 0 hda 51292 14441 841783 926052 25717 79650 843256 3029804 0 148459 3956933
252// 3 1 hda1 0 0 0 0 <- ignore if only 4 fields
Denys Vlasenko3b160342011-11-01 23:34:46 +0100253// Linux 3.0 (maybe earlier) started printing full stats for hda1 too.
254// Had to add code which skips such devices.
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000255static int rdval_diskstats(const char* p, ullong *vec)
256{
Denys Vlasenko3b160342011-11-01 23:34:46 +0100257 char devname[32];
258 unsigned devname_len = 0;
259 int value_idx = 0;
260
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000261 vec[0] = 0;
262 vec[1] = 0;
263 while (1) {
Denys Vlasenko3b160342011-11-01 23:34:46 +0100264 value_idx++;
265 while (*p == ' ' || *p == '\t')
266 p++;
267 if (*p == '\0')
268 break;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000269 if (*p == '\n') {
Denys Vlasenko3b160342011-11-01 23:34:46 +0100270 value_idx = 0;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000271 p++;
272 continue;
273 }
Denys Vlasenko3b160342011-11-01 23:34:46 +0100274 if (value_idx == 3) {
275 char *end = strchrnul(p, ' ');
276 /* If this a hda1-like device (same prefix as last one + digit)? */
277 if (devname_len && strncmp(devname, p, devname_len) == 0 && isdigit(p[devname_len])) {
278 p = end;
279 goto skip_line; /* skip entire line */
280 }
281 /* It is not. Remember the name for future checks */
282 devname_len = end - p;
283 if (devname_len > sizeof(devname)-1)
284 devname_len = sizeof(devname)-1;
285 strncpy(devname, p, devname_len);
286 /* devname[devname_len] = '\0'; - not really needed */
287 p = end;
288 } else
289 if (value_idx == 6) {
290 // TODO: *sectorsize (don't know how to find out sectorsize)
291 vec[0] += strtoull(p, NULL, 10);
292 } else
293 if (value_idx == 10) {
294 // TODO: *sectorsize (don't know how to find out sectorsize)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000295 vec[1] += strtoull(p, NULL, 10);
Denys Vlasenko3b160342011-11-01 23:34:46 +0100296 skip_line:
297 while (*p != '\n' && *p != '\0')
298 p++;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000299 continue;
300 }
Denys Vlasenko3b160342011-11-01 23:34:46 +0100301 while ((unsigned char)(*p) > ' ') // skip over value
302 p++;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000303 }
304 return 0;
305}
306
307static void scale(ullong ul)
308{
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000309 char buf[5];
Denis Vlasenko56ea65c2008-01-06 03:26:53 +0000310
311 /* see http://en.wikipedia.org/wiki/Tera */
Denys Vlasenkoa407cf72013-09-06 12:53:14 +0200312 smart_ulltoa4(ul, buf, " kmgtpezy")[0] = '\0';
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000313 put(buf);
314}
315
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000316#define S_STAT(a) \
317typedef struct a { \
318 struct s_stat *next; \
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200319 void (*collect)(struct a *s) FAST_FUNC; \
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000320 const char *label;
321#define S_STAT_END(a) } a;
322
323S_STAT(s_stat)
324S_STAT_END(s_stat)
325
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200326static void FAST_FUNC collect_literal(s_stat *s UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000327{
328}
329
330static s_stat* init_literal(void)
331{
Denis Vlasenkobefd5ea2008-06-28 23:33:02 +0000332 s_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000333 s->collect = collect_literal;
334 return (s_stat*)s;
335}
336
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000337static s_stat* init_cr(const char *param UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000338{
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100339 G.final_char = '\r';
340 return NULL;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000341}
342
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000343// user nice system idle iowait irq softirq (last 3 only in 2.6)
344//cpu 649369 0 341297 4336769 11640 7122 1183
345//cpuN 649369 0 341297 4336769 11640 7122 1183
346enum { CPU_FIELDCNT = 7 };
347S_STAT(cpu_stat)
348 ullong old[CPU_FIELDCNT];
Denys Vlasenko85b380f2019-08-06 16:56:00 +0200349 unsigned bar_sz;
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100350 char bar[1];
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000351S_STAT_END(cpu_stat)
352
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200353static void FAST_FUNC collect_cpu(cpu_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000354{
355 ullong data[CPU_FIELDCNT] = { 0, 0, 0, 0, 0, 0, 0 };
356 unsigned frac[CPU_FIELDCNT] = { 0, 0, 0, 0, 0, 0, 0 };
357 ullong all = 0;
Denys Vlasenko85b380f2019-08-06 16:56:00 +0200358 unsigned norm_all = 0;
359 unsigned bar_sz = s->bar_sz;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000360 char *bar = s->bar;
361 int i;
362
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100363 if (rdval(get_file(&proc_stat), "cpu ", data, 0
364 | (1 << 1)
365 | (1 << 2)
366 | (1 << 3)
367 | (1 << 4)
368 | (1 << 5)
369 | (1 << 6)
370 | (1 << 7))
371 ) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000372 put_question_marks(bar_sz);
373 return;
374 }
375
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000376 for (i = 0; i < CPU_FIELDCNT; i++) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000377 ullong old = s->old[i];
378 if (data[i] < old) old = data[i]; //sanitize
379 s->old[i] = data[i];
380 all += (data[i] -= old);
381 }
382
383 if (all) {
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000384 for (i = 0; i < CPU_FIELDCNT; i++) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000385 ullong t = bar_sz * data[i];
386 norm_all += data[i] = t / all;
387 frac[i] = t % all;
388 }
389
390 while (norm_all < bar_sz) {
391 unsigned max = frac[0];
392 int pos = 0;
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000393 for (i = 1; i < CPU_FIELDCNT; i++) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000394 if (frac[i] > max) max = frac[i], pos = i;
395 }
396 frac[pos] = 0; //avoid bumping up same value twice
397 data[pos]++;
398 norm_all++;
399 }
400
401 memset(bar, '.', bar_sz);
402 memset(bar, 'S', data[2]); bar += data[2]; //sys
403 memset(bar, 'U', data[0]); bar += data[0]; //usr
404 memset(bar, 'N', data[1]); bar += data[1]; //nice
405 memset(bar, 'D', data[4]); bar += data[4]; //iowait
406 memset(bar, 'I', data[5]); bar += data[5]; //irq
407 memset(bar, 'i', data[6]); bar += data[6]; //softirq
408 } else {
409 memset(bar, '?', bar_sz);
410 }
411 put(s->bar);
412}
413
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000414static s_stat* init_cpu(const char *param)
415{
416 int sz;
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100417 cpu_stat *s;
Denys Vlasenko85b380f2019-08-06 16:56:00 +0200418 sz = param[0] ? strtoul(param, NULL, 0) : 10;
419 if (sz <= 0) sz = 1;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000420 if (sz > 1000) sz = 1000;
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100421 s = xzalloc(sizeof(*s) + sz);
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000422 /*s->bar[sz] = '\0'; - xzalloc did it */
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000423 s->bar_sz = sz;
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100424 s->collect = collect_cpu;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000425 return (s_stat*)s;
426}
427
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000428S_STAT(int_stat)
429 ullong old;
430 int no;
431S_STAT_END(int_stat)
432
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200433static void FAST_FUNC collect_int(int_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000434{
435 ullong data[1];
436 ullong old;
437
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100438 if (rdval(get_file(&proc_stat), "intr", data, 1 << s->no)) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000439 put_question_marks(4);
440 return;
441 }
442
443 old = s->old;
444 if (data[0] < old) old = data[0]; //sanitize
445 s->old = data[0];
446 scale(data[0] - old);
447}
448
449static s_stat* init_int(const char *param)
450{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000451 int_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000452 s->collect = collect_int;
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000453 if (param[0] == '\0') {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000454 s->no = 1;
455 } else {
Denys Vlasenko77832482010-08-12 14:14:45 +0200456 int n = xatoi_positive(param);
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000457 s->no = n + 2;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000458 }
459 return (s_stat*)s;
460}
461
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000462S_STAT(ctx_stat)
463 ullong old;
464S_STAT_END(ctx_stat)
465
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200466static void FAST_FUNC collect_ctx(ctx_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000467{
468 ullong data[1];
469 ullong old;
470
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100471 if (rdval(get_file(&proc_stat), "ctxt", data, 1 << 1)) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000472 put_question_marks(4);
473 return;
474 }
475
476 old = s->old;
477 if (data[0] < old) old = data[0]; //sanitize
478 s->old = data[0];
479 scale(data[0] - old);
480}
481
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000482static s_stat* init_ctx(const char *param UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000483{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000484 ctx_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000485 s->collect = collect_ctx;
486 return (s_stat*)s;
487}
488
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000489S_STAT(blk_stat)
490 const char* lookfor;
491 ullong old[2];
492S_STAT_END(blk_stat)
493
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200494static void FAST_FUNC collect_blk(blk_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000495{
496 ullong data[2];
497 int i;
498
499 if (is26) {
500 i = rdval_diskstats(get_file(&proc_diskstats), data);
501 } else {
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100502 i = rdval(get_file(&proc_stat), s->lookfor, data, 0
503 | (1 << 1)
504 | (1 << 2)
505 );
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000506 // Linux 2.4 reports bio in Kbytes, convert to sectors:
507 data[0] *= 2;
508 data[1] *= 2;
509 }
510 if (i) {
511 put_question_marks(9);
512 return;
513 }
514
515 for (i=0; i<2; i++) {
516 ullong old = s->old[i];
517 if (data[i] < old) old = data[i]; //sanitize
518 s->old[i] = data[i];
519 data[i] -= old;
520 }
521 scale(data[0]*512); // TODO: *sectorsize
522 put_c(' ');
523 scale(data[1]*512);
524}
525
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000526static s_stat* init_blk(const char *param UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000527{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000528 blk_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000529 s->collect = collect_blk;
530 s->lookfor = "page";
531 return (s_stat*)s;
532}
533
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000534S_STAT(fork_stat)
535 ullong old;
536S_STAT_END(fork_stat)
537
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200538static void FAST_FUNC collect_thread_nr(fork_stat *s UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000539{
540 ullong data[1];
541
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100542 if (rdval_loadavg(get_file(&proc_loadavg), data, 1 << 4)) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000543 put_question_marks(4);
544 return;
545 }
546 scale(data[0]);
547}
548
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200549static void FAST_FUNC collect_fork(fork_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000550{
551 ullong data[1];
552 ullong old;
553
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100554 if (rdval(get_file(&proc_stat), "processes", data, 1 << 1)) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000555 put_question_marks(4);
556 return;
557 }
558
559 old = s->old;
560 if (data[0] < old) old = data[0]; //sanitize
561 s->old = data[0];
562 scale(data[0] - old);
563}
564
565static s_stat* init_fork(const char *param)
566{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000567 fork_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000568 if (*param == 'n') {
569 s->collect = collect_thread_nr;
570 } else {
571 s->collect = collect_fork;
572 }
573 return (s_stat*)s;
574}
575
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000576S_STAT(if_stat)
577 ullong old[4];
578 const char *device;
579 char *device_colon;
580S_STAT_END(if_stat)
581
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200582static void FAST_FUNC collect_if(if_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000583{
584 ullong data[4];
585 int i;
586
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100587 if (rdval(get_file(&proc_net_dev), s->device_colon, data, 0
588 | (1 << 1)
589 | (1 << 3)
590 | (1 << 9)
591 | (1 << 11))
592 ) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000593 put_question_marks(10);
594 return;
595 }
596
597 for (i=0; i<4; i++) {
598 ullong old = s->old[i];
599 if (data[i] < old) old = data[i]; //sanitize
600 s->old[i] = data[i];
601 data[i] -= old;
602 }
603 put_c(data[1] ? '*' : ' ');
604 scale(data[0]);
605 put_c(data[3] ? '*' : ' ');
606 scale(data[2]);
607}
608
609static s_stat* init_if(const char *device)
610{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000611 if_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000612
613 if (!device || !device[0])
614 bb_show_usage();
615 s->collect = collect_if;
616
617 s->device = device;
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000618 s->device_colon = xasprintf("%s:", device);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000619 return (s_stat*)s;
620}
621
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000622S_STAT(mem_stat)
623 char opt;
624S_STAT_END(mem_stat)
625
626// "Memory" value should not include any caches.
627// IOW: neither "ls -laR /" nor heavy read/write activity
628// should affect it. We'd like to also include any
629// long-term allocated kernel-side mem, but it is hard
630// to figure out. For now, bufs, cached & slab are
631// counted as "free" memory
632//2.6.16:
633//MemTotal: 773280 kB
634//MemFree: 25912 kB - genuinely free
635//Buffers: 320672 kB - cache
636//Cached: 146396 kB - cache
637//SwapCached: 0 kB
638//Active: 183064 kB
639//Inactive: 356892 kB
640//HighTotal: 0 kB
641//HighFree: 0 kB
642//LowTotal: 773280 kB
643//LowFree: 25912 kB
644//SwapTotal: 131064 kB
645//SwapFree: 131064 kB
646//Dirty: 48 kB
647//Writeback: 0 kB
648//Mapped: 96620 kB
649//Slab: 200668 kB - takes 7 Mb on my box fresh after boot,
650// but includes dentries and inodes
651// (== can take arbitrary amount of mem)
652//CommitLimit: 517704 kB
653//Committed_AS: 236776 kB
654//PageTables: 1248 kB
655//VmallocTotal: 516052 kB
656//VmallocUsed: 3852 kB
657//VmallocChunk: 512096 kB
658//HugePages_Total: 0
659//HugePages_Free: 0
660//Hugepagesize: 4096 kB
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200661static void FAST_FUNC collect_mem(mem_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000662{
663 ullong m_total = 0;
664 ullong m_free = 0;
665 ullong m_bufs = 0;
666 ullong m_cached = 0;
667 ullong m_slab = 0;
668
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100669 if (rdval(get_file(&proc_meminfo), "MemTotal:", &m_total, 1 << 1)) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000670 put_question_marks(4);
671 return;
672 }
Denis Vlasenko8a2e4212008-02-29 07:46:19 +0000673 if (s->opt == 't') {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000674 scale(m_total << 10);
675 return;
676 }
677
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100678 if (rdval(proc_meminfo.file, "MemFree:", &m_free , 1 << 1)
679 || rdval(proc_meminfo.file, "Buffers:", &m_bufs , 1 << 1)
680 || rdval(proc_meminfo.file, "Cached:", &m_cached, 1 << 1)
681 || rdval(proc_meminfo.file, "Slab:", &m_slab , 1 << 1)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000682 ) {
683 put_question_marks(4);
684 return;
685 }
686
687 m_free += m_bufs + m_cached + m_slab;
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000688 switch (s->opt) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000689 case 'f':
690 scale(m_free << 10); break;
691 default:
692 scale((m_total - m_free) << 10); break;
693 }
694}
695
696static s_stat* init_mem(const char *param)
697{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000698 mem_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000699 s->collect = collect_mem;
700 s->opt = param[0];
701 return (s_stat*)s;
702}
703
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000704S_STAT(swp_stat)
705S_STAT_END(swp_stat)
706
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200707static void FAST_FUNC collect_swp(swp_stat *s UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000708{
709 ullong s_total[1];
710 ullong s_free[1];
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100711 if (rdval(get_file(&proc_meminfo), "SwapTotal:", s_total, 1 << 1)
712 || rdval(proc_meminfo.file, "SwapFree:" , s_free, 1 << 1)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000713 ) {
714 put_question_marks(4);
715 return;
716 }
717 scale((s_total[0]-s_free[0]) << 10);
718}
719
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000720static s_stat* init_swp(const char *param UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000721{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000722 swp_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000723 s->collect = collect_swp;
724 return (s_stat*)s;
725}
726
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000727S_STAT(fd_stat)
728S_STAT_END(fd_stat)
729
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200730static void FAST_FUNC collect_fd(fd_stat *s UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000731{
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000732 ullong data[2];
733
Denys Vlasenko8a26fda2016-03-15 15:52:40 +0100734 if (rdval(get_file(&proc_sys_fs_filenr), "", data, 0
735 | (1 << 1)
736 | (1 << 2))
737 ) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000738 put_question_marks(4);
739 return;
740 }
741
742 scale(data[0] - data[1]);
743}
744
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000745static s_stat* init_fd(const char *param UNUSED_PARAM)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000746{
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000747 fd_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000748 s->collect = collect_fd;
749 return (s_stat*)s;
750}
751
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000752S_STAT(time_stat)
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100753 unsigned prec;
754 unsigned scale;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000755S_STAT_END(time_stat)
756
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200757static void FAST_FUNC collect_time(time_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000758{
759 char buf[sizeof("12:34:56.123456")];
760 struct tm* tm;
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100761 unsigned us = tv.tv_usec + s->scale/2;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000762 time_t t = tv.tv_sec;
763
764 if (us >= 1000000) {
765 t++;
766 us -= 1000000;
767 }
768 tm = localtime(&t);
769
770 sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
771 if (s->prec)
772 sprintf(buf+8, ".%0*d", s->prec, us / s->scale);
773 put(buf);
774}
775
776static s_stat* init_time(const char *param)
777{
778 int prec;
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000779 time_stat *s = xzalloc(sizeof(*s));
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000780
781 s->collect = collect_time;
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000782 prec = param[0] - '0';
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000783 if (prec < 0) prec = 0;
784 else if (prec > 6) prec = 6;
785 s->prec = prec;
786 s->scale = 1;
787 while (prec++ < 6)
788 s->scale *= 10;
789 return (s_stat*)s;
790}
791
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200792static void FAST_FUNC collect_info(s_stat *s)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000793{
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000794 gen ^= 1;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000795 while (s) {
796 put(s->label);
797 s->collect(s);
798 s = s->next;
799 }
800}
801
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000802typedef s_stat* init_func(const char *param);
803
Denys Vlasenko41b1e2c2016-03-15 16:13:23 +0100804static const char options[] ALIGN1 = "ncmsfixptbr";
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000805static init_func *const init_functions[] = {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000806 init_if,
807 init_cpu,
808 init_mem,
809 init_swp,
810 init_fd,
811 init_int,
812 init_ctx,
813 init_fork,
814 init_time,
815 init_blk,
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000816 init_cr
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000817};
818
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000819int nmeter_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko2ec91ae2010-01-04 14:15:38 +0100820int nmeter_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000821{
822 char buf[32];
823 s_stat *first = NULL;
824 s_stat *last = NULL;
825 s_stat *s;
Denys Vlasenkoa6041862010-12-13 15:17:22 +0100826 char *opt_d;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000827 char *cur, *prev;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000828
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000829 INIT_G();
830
831 xchdir("/proc");
832
Denis Vlasenkocd785fb2008-08-14 21:57:43 +0000833 if (open_read_close("version", buf, sizeof(buf)-1) > 0) {
834 buf[sizeof(buf)-1] = '\0';
835 is26 = (strstr(buf, " 2.4.") == NULL);
836 }
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000837
Denys Vlasenko41b1e2c2016-03-15 16:13:23 +0100838 if (getopt32(argv, "d:", &opt_d)) {
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100839 G.delta = xatoi(opt_d) * 1000;
840 G.deltanz = G.delta > 0 ? G.delta : 1;
841 need_seconds = (1000000 % G.deltanz) != 0;
Denys Vlasenko41b1e2c2016-03-15 16:13:23 +0100842 }
Denys Vlasenkoa6041862010-12-13 15:17:22 +0100843 argv += optind;
844
845 if (!argv[0])
846 bb_show_usage();
847
848 // Can use argv[0] directly, but this will mess up
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000849 // parameters as seen by e.g. ps. Making a copy...
Denys Vlasenkoa6041862010-12-13 15:17:22 +0100850 cur = xstrdup(argv[0]);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000851 while (1) {
852 char *param, *p;
853 prev = cur;
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000854 again:
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000855 cur = strchr(cur, '%');
856 if (!cur)
857 break;
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000858 if (cur[1] == '%') { // %%
Denis Vlasenko0f293b92008-07-22 20:16:55 +0000859 overlapping_strcpy(cur, cur + 1);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000860 cur++;
861 goto again;
862 }
863 *cur++ = '\0'; // overwrite %
864 if (cur[0] == '[') {
865 // format: %[foptstring]
866 cur++;
867 p = strchr(options, cur[0]);
868 param = cur+1;
869 while (cur[0] != ']') {
870 if (!cur[0])
871 bb_show_usage();
872 cur++;
873 }
874 *cur++ = '\0'; // overwrite [
875 } else {
876 // format: %NNNNNNf
877 param = cur;
878 while (cur[0] >= '0' && cur[0] <= '9')
879 cur++;
880 if (!cur[0])
881 bb_show_usage();
882 p = strchr(options, cur[0]);
883 *cur++ = '\0'; // overwrite format char
884 }
885 if (!p)
886 bb_show_usage();
887 s = init_functions[p-options](param);
888 if (s) {
889 s->label = prev;
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000890 /*s->next = NULL; - all initXXX funcs use xzalloc */
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000891 if (!first)
892 first = s;
893 else
894 last->next = s;
895 last = s;
896 } else {
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100897 // %r option. remove it from string
898 overlapping_strcpy(prev + strlen(prev), cur);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000899 cur = prev;
900 }
901 }
902 if (prev[0]) {
903 s = init_literal();
904 s->label = prev;
Denis Vlasenko333aa0c2008-06-28 23:30:37 +0000905 /*s->next = NULL; - all initXXX funcs use xzalloc */
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000906 if (!first)
907 first = s;
908 else
909 last->next = s;
910 last = s;
911 }
912
913 // Generate first samples but do not print them, they're bogus
914 collect_info(first);
915 reset_outbuf();
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100916 if (G.delta >= 0) {
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000917 gettimeofday(&tv, NULL);
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100918 usleep(G.delta > 1000000 ? 1000000 : G.delta - tv.tv_usec % G.deltanz);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000919 }
920
921 while (1) {
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000922 gettimeofday(&tv, NULL);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000923 collect_info(first);
Denys Vlasenkoa63e2a82016-03-15 16:06:29 +0100924 put_c(G.final_char);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000925 print_outbuf();
926
927 // Negative delta -> no usleep at all
928 // This will hog the CPU but you can have REALLY GOOD
929 // time resolution ;)
930 // TODO: detect and avoid useless updates
931 // (like: nothing happens except time)
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100932 if (G.delta >= 0) {
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000933 int rem;
934 // can be commented out, will sacrifice sleep time precision a bit
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000935 gettimeofday(&tv, NULL);
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000936 if (need_seconds)
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100937 rem = G.delta - ((ullong)tv.tv_sec*1000000 + tv.tv_usec) % G.deltanz;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000938 else
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100939 rem = G.delta - (unsigned)tv.tv_usec % G.deltanz;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000940 // Sometimes kernel wakes us up just a tiny bit earlier than asked
941 // Do not go to very short sleep in this case
Denys Vlasenko0d1b71e2016-03-15 17:54:17 +0100942 if (rem < (unsigned)G.delta / 128) {
943 rem += G.delta;
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000944 }
945 usleep(rem);
946 }
947 }
948
Denis Vlasenko199c0d52007-05-30 14:48:38 +0000949 /*return 0;*/
Denis Vlasenko1db39b22006-10-11 20:59:02 +0000950}