summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDaniel Wagner <daniel.wagner@bmw-carit.de>2010-09-22 12:11:06 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2010-09-22 12:11:06 +0200
commitb0a9340453754a2485afe9c3696866b0276bb647 (patch)
treeb3cdd547157cf251cd7f6f0e380e23dc97eac692 /tools
parent14c3f6e51b2830f7bcaa595f9ce1838d1b963826 (diff)
downloadconnman-b0a9340453754a2485afe9c3696866b0276bb647.tar.gz
connman-b0a9340453754a2485afe9c3696866b0276bb647.tar.bz2
connman-b0a9340453754a2485afe9c3696866b0276bb647.zip
Add statistics ring buffer analyze tool
This tool prints the statistic ring buffer.
Diffstat (limited to 'tools')
-rw-r--r--tools/stats-ringbuffer-dump.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/tools/stats-ringbuffer-dump.c b/tools/stats-ringbuffer-dump.c
new file mode 100644
index 00000000..b1bd7134
--- /dev/null
+++ b/tools/stats-ringbuffer-dump.c
@@ -0,0 +1,335 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2010 BMW Car IT GmbH. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define MAGIC 0xFA00B915
+
+struct connman_stats_data {
+ unsigned int rx_packets;
+ unsigned int tx_packets;
+ unsigned int rx_bytes;
+ unsigned int tx_bytes;
+ unsigned int rx_errors;
+ unsigned int tx_errors;
+ unsigned int rx_dropped;
+ unsigned int tx_dropped;
+ unsigned int time;
+};
+
+struct stats_file_header {
+ unsigned int magic;
+ unsigned int begin;
+ unsigned int end;
+};
+
+struct stats_record {
+ time_t ts;
+ struct connman_stats_data data;
+};
+
+struct stats_file {
+ int fd;
+ char *name;
+ char *addr;
+ size_t len;
+
+ /* cached values */
+ int max_nr;
+ int nr;
+ struct stats_record *first;
+ struct stats_record *last;
+};
+
+static struct stats_file_header *get_hdr(struct stats_file *file)
+{
+ return (struct stats_file_header *)file->addr;
+}
+
+static struct stats_record *get_begin(struct stats_file *file)
+{
+ unsigned int off = get_hdr(file)->begin;
+
+ return (struct stats_record *)(file->addr + off);
+}
+
+static struct stats_record *get_end(struct stats_file *file)
+{
+ unsigned int off = get_hdr(file)->end;
+
+ return (struct stats_record *)(file->addr + off);
+}
+
+static struct stats_record *get_next(struct stats_file *file,
+ struct stats_record *cur)
+{
+ cur++;
+
+ if (cur > file->last)
+ cur = file->first;
+
+ return cur;
+}
+
+static int get_index(struct stats_file *file, struct stats_record *rec)
+{
+ return rec - file->first;
+}
+
+static void stats_print_record(struct stats_record *rec)
+{
+ char buffer[30];
+
+ strftime(buffer, 30, "%d-%m-%Y %T", localtime(&rec->ts));
+ printf("%p %s %d %d %d %d %d %d %d %d %d\n", rec, buffer,
+ rec->data.rx_packets,
+ rec->data.tx_packets,
+ rec->data.tx_bytes,
+ rec->data.tx_bytes,
+ rec->data.rx_errors,
+ rec->data.tx_errors,
+ rec->data.rx_dropped,
+ rec->data.tx_dropped,
+ rec->data.time);
+}
+
+static void stats_hdr_info(struct stats_file *file)
+{
+ struct stats_file_header *hdr;
+ struct stats_record *begin, *end;
+
+ hdr = get_hdr(file);
+ begin = get_begin(file);
+ end = get_end(file);
+
+ printf("Data Structure Sizes\n");
+ printf(" sizeof header %zd/0x%02zx\n",
+ sizeof(struct stats_file_header),
+ sizeof(struct stats_file_header));
+ printf(" sizeof entry %zd/0%02zx\n\n",
+ sizeof(struct stats_record),
+ sizeof(struct stats_record));
+
+ printf("File\n");
+ printf(" addr %p\n", file->addr);
+ printf(" len %zd\n", file->len);
+
+ printf(" max nr entries %d\n", file->max_nr);
+ printf(" nr entries %d\n\n", file->nr);
+
+ printf("Header\n");
+ printf(" magic 0x%08x\n", hdr->magic);
+ printf(" begin [%d] 0x%08x\n",
+ get_index(file, begin), hdr->begin);
+ printf(" end [%d] 0x%08x\n\n",
+ get_index(file, end), hdr->end);
+
+ printf("Pointers\n");
+ printf(" hdr %p\n", hdr);
+ printf(" begin %p\n", begin);
+ printf(" end %p\n", end);
+ printf(" first %p\n", file->first);
+ printf(" last %p\n\n", file->last);
+}
+
+static void stats_print_entries(struct stats_file *file)
+{
+ struct stats_record *it;
+ int i;
+
+ printf("[ idx] ptr ts rx_packets tx_packets rx_bytes "
+ "tx_bytes rx_errors tx_errors rx_dropped tx_dropped time\n\n");
+
+ for (i = 0, it = file->first; it <= file->last; it++, i++) {
+ printf("[%04d] ", i);
+ stats_print_record(it);
+ }
+}
+
+static void stats_print_diff(struct stats_file *file)
+{
+ struct stats_record *begin, *end;
+
+ begin = get_begin(file);
+ begin = get_next(file, begin);
+ end = get_end(file);
+
+ printf("\n(begin + 1)\n");
+ printf("\t[%04d] ", get_index(file, begin));
+ stats_print_record(begin);
+ printf("end\n");
+ printf("\t[%04d] ", get_index(file, end));
+ stats_print_record(end);
+
+ printf("\nend - (begin + 1):\n");
+ printf("\trx_packets: %d\n",
+ end->data.rx_packets - begin->data.rx_packets);
+ printf("\ttx_packets: %d\n",
+ end->data.tx_packets - begin->data.tx_packets);
+ printf("\trx_bytes: %d\n",
+ end->data.rx_bytes - begin->data.rx_bytes);
+ printf("\ttx_bytes: %d\n",
+ end->data.tx_bytes - begin->data.tx_bytes);
+ printf("\trx_errors: %d\n",
+ end->data.rx_errors - begin->data.rx_errors);
+ printf("\ttx_errors: %d\n",
+ end->data.tx_errors - begin->data.tx_errors);
+ printf("\trx_dropped: %d\n",
+ end->data.rx_dropped - begin->data.rx_dropped);
+ printf("\ttx_dropped: %d\n",
+ end->data.tx_dropped - begin->data.tx_dropped);
+ printf("\ttime: %d\n",
+ end->data.time - begin->data.time);
+}
+
+static void update_max_nr_entries(struct stats_file *file)
+{
+ file->max_nr = (file->len - sizeof(struct stats_file_header)) /
+ sizeof(struct stats_record);
+}
+
+static void update_nr_entries(struct stats_file *file)
+{
+ struct stats_record *begin, *end;
+ int nr;
+
+ begin = get_begin(file);
+ end = get_end(file);
+
+ nr = get_index(file, end) - get_index(file, begin);
+
+ if (nr < 0)
+ nr += file->max_nr;
+
+ file->nr = nr;
+}
+
+static void update_first(struct stats_file *file)
+{
+ file->first = (struct stats_record *)(file->addr +
+ sizeof(struct stats_file_header));
+}
+
+static void update_last(struct stats_file *file)
+{
+ struct stats_record *last;
+
+ last = file->first;
+ last += file->max_nr - 1;
+
+ file->last = last;
+}
+
+static int stats_file_update_cache(struct stats_file *file)
+{
+ update_max_nr_entries(file);
+ update_nr_entries(file);
+ update_first(file);
+ update_last(file);
+
+ return 0;
+}
+
+static int stats_file_mmap(struct stats_file *file, size_t size)
+{
+ size_t page_size;
+
+ page_size = sysconf(_SC_PAGESIZE);
+ file->len = (size + page_size - 1) & ~(page_size - 1);
+
+ file->addr = mmap(NULL, file->len, PROT_READ,
+ MAP_SHARED, file->fd, 0);
+
+ if (file->addr == MAP_FAILED) {
+ fprintf(stderr, "mmap error %s for %s\n",
+ strerror(errno), file->name);
+ return -errno;
+ }
+
+ stats_file_update_cache(file);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct stats_file _file, *file;
+ struct stat stat;
+ int err;
+
+ if (argc < 2) {
+ printf("Usage: %s [STATS_FILENAME]\n", argv[0]);
+ exit(0);
+ }
+
+ file = &_file;
+ bzero(file, sizeof(struct stats_file));
+
+ file->name = argv[1];
+
+ file->fd = open(file->name, O_RDONLY, 0644);
+ if (file->fd == -1) {
+ fprintf(stderr, "open error %s for %s\n",
+ strerror(errno), file->name);
+ exit(1);
+ }
+
+ err = fstat(file->fd, &stat);
+ if (err < 0) {
+ fprintf(stderr, "fstat error %s for %s\n",
+ strerror(errno), file->name);
+ exit(1);
+ }
+
+ err = stats_file_mmap(file, stat.st_size);
+ if (err < 0)
+ exit(1);
+
+ if (get_hdr(file)->magic != MAGIC) {
+ /* not fatal */
+ printf("No valid magic found\n");
+ }
+
+ stats_hdr_info(file);
+ stats_print_entries(file);
+ stats_print_diff(file);
+
+ munmap(file->addr, file->len);
+ close(file->fd);
+
+ return 0;
+}