1 /* This monitors a copy to a file, and prints nice stats */
2 
3 #define EX_UTILS_NO_USE_INPUT 1
4 #include "ex_utils.h"
5 
6 #include <sys/time.h>
7 #include <time.h>
8 
9 #define CUR_RATE_NUM_SECS 60
10 
main(int argc,char * argv[])11 int main(int argc, char *argv[])
12 {
13   Vstr_base *s1 = NULL;
14   Vstr_base *s2 = ex_init(&s1);
15   int fd = -1;
16   struct stat stat_buf;
17   time_t beg_time;
18   unsigned int beg_sz = 0;
19   unsigned int last_sz = 0;
20   unsigned int count = 0;
21   struct
22   {
23    time_t timestamp;
24    unsigned int sz;
25   } cur[CUR_RATE_NUM_SECS];
26 
27   if (argc != 2)
28   {
29     size_t pos = 0;
30 
31     VSTR_ADD_CSTR_PTR(s1, 0, argc ? argv[0] : "mon_cp");
32 
33     if ((pos = vstr_srch_chr_rev(s1, 1, s1->len, '/')))
34       vstr_del(s1, 1, pos);
35 
36     VSTR_ADD_CSTR_PTR(s1, 0, " Format: ");
37     VSTR_ADD_CSTR_PTR(s1, s1->len, " <filename>\n");
38 
39     io_put_all(s1, STDERR_FILENO);
40 
41     exit (EXIT_FAILURE);
42   }
43 
44   fd = io_open(argv[1]);
45 
46   if (fstat(fd, &stat_buf) == -1)
47     err(EXIT_FAILURE, "fstat");
48 
49   vstr_cntl_conf(s1->conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$');
50   vstr_cntl_conf(s2->conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$');
51   vstr_sc_fmt_add_bkmg_Byte_uint(s1->conf, "{BKMG:%u}");
52   vstr_sc_fmt_add_bkmg_Byte_uint(s2->conf, "{BKMG:%u}");
53   vstr_sc_fmt_add_bkmg_Bytes_uint(s2->conf, "{BKMG/s:%u}");
54 
55   if (s1->conf->malloc_bad || s2->conf->malloc_bad)
56     errno = ENOMEM, err(EXIT_FAILURE, "conf");
57 
58   beg_time = time(NULL); --beg_time;
59   beg_sz = last_sz = stat_buf.st_size;
60   while (count < CUR_RATE_NUM_SECS)
61   {
62     cur[count].timestamp = beg_time;
63     cur[count].sz = beg_sz;
64     ++count;
65   }
66 
67   vstr_add_fmt(s1, 0, "Start size = ${BKMG:%u}, current period = %u seconds.\n",
68                beg_sz, CUR_RATE_NUM_SECS);
69 
70   count = 0;
71   while (count < (5 * 60)) /* same for 5 minutes */
72   {
73     size_t prev_len = s2->len;
74     time_t now;
75 
76     if (fstat(fd, &stat_buf) == -1)
77       err(EXIT_FAILURE, "fstat:");
78 
79     ++count;
80     if (last_sz != (unsigned int)stat_buf.st_size)
81       count = 0;
82     if (last_sz > (unsigned int)stat_buf.st_size)
83       break;
84     last_sz = stat_buf.st_size;
85 
86     now = time(NULL);
87     memmove(cur, cur + 1, sizeof(cur[0]) * (CUR_RATE_NUM_SECS - 1));
88     cur[CUR_RATE_NUM_SECS - 1].timestamp = now;
89     cur[CUR_RATE_NUM_SECS - 1].sz = last_sz;
90 
91     vstr_del(s2, 1, s2->len);
92     vstr_add_fmt(s2, 0,
93                  "CP = $8{BKMG:%u} | "
94                  "Rate = $10{BKMG/s:%u} | "
95                  "CP(C) = $8{BKMG:%u} | "
96                  "Rate(C) = $10{BKMG/s:%u}",
97                  (last_sz - beg_sz),
98                  (unsigned int)((last_sz - beg_sz) /
99                                 (now - beg_time)),
100                  (last_sz - cur[0].sz),
101                  (unsigned int)((last_sz - cur[0].sz) /
102                                 (now - cur[0].timestamp)));
103 
104     if (s2->len < prev_len)
105     {
106       vstr_add_rep_chr(s1, s1->len, '\b', prev_len - s2->len);
107       vstr_add_rep_chr(s1, s1->len, ' ',  prev_len - s2->len);
108     }
109 
110     vstr_add_rep_chr(s1, s1->len, '\b', prev_len);
111     vstr_add_vstr(s1, s1->len, s2, 1, s2->len, 0);
112 
113     if (s1->conf->malloc_bad || s2->conf->malloc_bad)
114       errno = ENOMEM, err(EXIT_FAILURE, "data");
115 
116     io_put_all(s1, STDOUT_FILENO);
117 
118     sleep(1);
119   }
120 
121   close(fd);
122 
123   vstr_add_rep_chr(s1, s1->len, '\n', 1);
124 
125   io_put_all(s1, STDOUT_FILENO);
126 
127   exit (ex_exit(s1, s2));
128 }
129