Fix typo in stats_print_record
[framework/connectivity/connman.git] / tools / stats-ringbuffer-dump.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2010  BMW Car IT GmbH. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #define _GNU_SOURCE
26 #include <sys/mman.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/time.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <string.h>
33
34 #include <sys/time.h>
35 #include <time.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <errno.h>
39
40 #define MAGIC 0xFA00B915
41
42 struct connman_stats_data {
43         unsigned int rx_packets;
44         unsigned int tx_packets;
45         unsigned int rx_bytes;
46         unsigned int tx_bytes;
47         unsigned int rx_errors;
48         unsigned int tx_errors;
49         unsigned int rx_dropped;
50         unsigned int tx_dropped;
51         unsigned int time;
52 };
53
54 struct stats_file_header {
55         unsigned int magic;
56         unsigned int begin;
57         unsigned int end;
58 };
59
60 struct stats_record {
61         time_t ts;
62         struct connman_stats_data data;
63 };
64
65 struct stats_file {
66         int fd;
67         char *name;
68         char *addr;
69         size_t len;
70
71         /* cached values */
72         int max_nr;
73         int nr;
74         struct stats_record *first;
75         struct stats_record *last;
76 };
77
78 static struct stats_file_header *get_hdr(struct stats_file *file)
79 {
80         return (struct stats_file_header *)file->addr;
81 }
82
83 static struct stats_record *get_begin(struct stats_file *file)
84 {
85         unsigned int off = get_hdr(file)->begin;
86
87         return (struct stats_record *)(file->addr + off);
88 }
89
90 static struct stats_record *get_end(struct stats_file *file)
91 {
92         unsigned int off = get_hdr(file)->end;
93
94         return (struct stats_record *)(file->addr + off);
95 }
96
97 static struct stats_record *get_next(struct stats_file *file,
98                                         struct stats_record *cur)
99 {
100         cur++;
101
102         if (cur > file->last)
103                 cur = file->first;
104
105         return cur;
106 }
107
108 static int get_index(struct stats_file *file, struct stats_record *rec)
109 {
110         return rec - file->first;
111 }
112
113 static void stats_print_record(struct stats_record *rec)
114 {
115         char buffer[30];
116
117         strftime(buffer, 30, "%d-%m-%Y %T", localtime(&rec->ts));
118         printf("%p %s %d %d %d %d %d %d %d %d %d\n", rec, buffer,
119                 rec->data.rx_packets,
120                 rec->data.tx_packets,
121                 rec->data.rx_bytes,
122                 rec->data.tx_bytes,
123                 rec->data.rx_errors,
124                 rec->data.tx_errors,
125                 rec->data.rx_dropped,
126                 rec->data.tx_dropped,
127                 rec->data.time);
128 }
129
130 static void stats_hdr_info(struct stats_file *file)
131 {
132         struct stats_file_header *hdr;
133         struct stats_record *begin, *end;
134
135         hdr = get_hdr(file);
136         begin = get_begin(file);
137         end = get_end(file);
138
139         printf("Data Structure Sizes\n");
140         printf("  sizeof header   %zd/0x%02zx\n",
141                 sizeof(struct stats_file_header),
142                 sizeof(struct stats_file_header));
143         printf("  sizeof entry    %zd/0%02zx\n\n",
144                 sizeof(struct stats_record),
145                 sizeof(struct stats_record));
146
147         printf("File\n");
148         printf("  addr            %p\n",  file->addr);
149         printf("  len             %zd\n", file->len);
150
151         printf("  max nr entries  %d\n", file->max_nr);
152         printf("  nr entries      %d\n\n", file->nr);
153
154         printf("Header\n");
155         printf("  magic           0x%08x\n", hdr->magic);
156         printf("  begin           [%d] 0x%08x\n",
157                 get_index(file, begin), hdr->begin);
158         printf("  end             [%d] 0x%08x\n\n",
159                 get_index(file, end), hdr->end);
160
161         printf("Pointers\n");
162         printf("  hdr             %p\n", hdr);
163         printf("  begin           %p\n", begin);
164         printf("  end             %p\n", end);
165         printf("  first           %p\n", file->first);
166         printf("  last            %p\n\n", file->last);
167 }
168
169 static void stats_print_entries(struct stats_file *file)
170 {
171         struct stats_record *it;
172         int i;
173
174         printf("[ idx] ptr ts rx_packets tx_packets rx_bytes "
175                 "tx_bytes rx_errors tx_errors rx_dropped tx_dropped time\n\n");
176
177         for (i = 0, it = file->first; it <= file->last; it++, i++) {
178                 printf("[%04d] ", i);
179                 stats_print_record(it);
180         }
181 }
182
183 static void stats_print_diff(struct stats_file *file)
184 {
185         struct stats_record *begin, *end;
186
187         begin = get_begin(file);
188         begin = get_next(file, begin);
189         end = get_end(file);
190
191         printf("\n(begin + 1)\n");
192         printf("\t[%04d] ", get_index(file, begin));
193         stats_print_record(begin);
194         printf("end\n");
195         printf("\t[%04d] ", get_index(file, end));
196         stats_print_record(end);
197
198         printf("\nend - (begin + 1):\n");
199         printf("\trx_packets: %d\n",
200                 end->data.rx_packets - begin->data.rx_packets);
201         printf("\ttx_packets: %d\n",
202                 end->data.tx_packets - begin->data.tx_packets);
203         printf("\trx_bytes:   %d\n",
204                 end->data.rx_bytes - begin->data.rx_bytes);
205         printf("\ttx_bytes:   %d\n",
206                 end->data.tx_bytes - begin->data.tx_bytes);
207         printf("\trx_errors:  %d\n",
208                 end->data.rx_errors - begin->data.rx_errors);
209         printf("\ttx_errors:  %d\n",
210                 end->data.tx_errors - begin->data.tx_errors);
211         printf("\trx_dropped: %d\n",
212                 end->data.rx_dropped - begin->data.rx_dropped);
213         printf("\ttx_dropped: %d\n",
214                 end->data.tx_dropped - begin->data.tx_dropped);
215         printf("\ttime:       %d\n",
216                 end->data.time - begin->data.time);
217 }
218
219 static void update_max_nr_entries(struct stats_file *file)
220 {
221         file->max_nr = (file->len - sizeof(struct stats_file_header)) /
222                 sizeof(struct stats_record);
223 }
224
225 static void update_nr_entries(struct stats_file *file)
226 {
227         struct stats_record *begin, *end;
228         int nr;
229
230         begin = get_begin(file);
231         end = get_end(file);
232
233         nr = get_index(file, end) - get_index(file, begin);
234
235         if (nr < 0)
236                 nr += file->max_nr;
237
238         file->nr = nr;
239 }
240
241 static void update_first(struct stats_file *file)
242 {
243         file->first = (struct stats_record *)(file->addr +
244                                         sizeof(struct stats_file_header));
245 }
246
247 static void update_last(struct stats_file *file)
248 {
249         struct stats_record *last;
250
251         last = file->first;
252         last += file->max_nr - 1;
253
254         file->last = last;
255 }
256
257 static int stats_file_update_cache(struct stats_file *file)
258 {
259         update_max_nr_entries(file);
260         update_nr_entries(file);
261         update_first(file);
262         update_last(file);
263
264         return 0;
265 }
266
267 static int stats_file_mmap(struct stats_file *file, size_t size)
268 {
269         size_t page_size;
270
271         page_size = sysconf(_SC_PAGESIZE);
272         file->len = (size + page_size - 1) & ~(page_size - 1);
273
274         file->addr = mmap(NULL, file->len, PROT_READ,
275                         MAP_SHARED, file->fd, 0);
276
277         if (file->addr == MAP_FAILED) {
278                 fprintf(stderr, "mmap error %s for %s\n",
279                         strerror(errno), file->name);
280                 return -errno;
281         }
282
283         stats_file_update_cache(file);
284
285         return 0;
286 }
287
288 int main(int argc, char *argv[])
289 {
290         struct stats_file _file, *file;
291         struct stat stat;
292         int err;
293
294         if (argc < 2) {
295                 printf("Usage: %s [STATS_FILENAME]\n", argv[0]);
296                 exit(0);
297         }
298
299         file = &_file;
300         bzero(file, sizeof(struct stats_file));
301
302         file->name = argv[1];
303
304         file->fd = open(file->name, O_RDONLY, 0644);
305         if (file->fd == -1) {
306                 fprintf(stderr, "open error %s for %s\n",
307                         strerror(errno), file->name);
308                 exit(1);
309         }
310
311         err = fstat(file->fd, &stat);
312         if (err < 0) {
313                 fprintf(stderr, "fstat error %s for %s\n",
314                         strerror(errno), file->name);
315                 exit(1);
316         }
317
318         err = stats_file_mmap(file, stat.st_size);
319         if (err < 0)
320                 exit(1);
321
322         if (get_hdr(file)->magic != MAGIC) {
323                 /* not fatal */
324                 printf("No valid magic found\n");
325         }
326
327         stats_hdr_info(file);
328         stats_print_entries(file);
329         stats_print_diff(file);
330
331         munmap(file->addr, file->len);
332         close(file->fd);
333
334         return 0;
335 }