]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
stats: Added more statistics fields (syscpu, page faults, context switches).
authorTimo Sirainen <tss@iki.fi>
Thu, 1 Sep 2011 03:02:23 +0000 (06:02 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 1 Sep 2011 03:02:23 +0000 (06:02 +0300)
src/plugins/stats/stats-plugin.c
src/plugins/stats/stats-plugin.h
src/stats/client-export.c
src/stats/mail-stats.c
src/stats/mail-stats.h

index 707f817938923f1de8c324df8fedd8a0b68efbbd..5ff5efca5937266ec7017a3573f20bb3ea96ca6d 100644 (file)
@@ -162,7 +162,12 @@ void mail_stats_get(struct stats_user *suser, struct mail_stats *stats_r)
        /* cputime */
        if (getrusage(RUSAGE_SELF, &usage) < 0)
                memset(&usage, 0, sizeof(usage));
-       stats_r->cpu_secs = usage.ru_utime;
+       stats_r->user_cpu = usage.ru_utime;
+       stats_r->sys_cpu = usage.ru_stime;
+       stats_r->min_faults = usage.ru_minflt;
+       stats_r->maj_faults = usage.ru_majflt;
+       stats_r->vol_cs = usage.ru_nvcsw;
+       stats_r->invol_cs = usage.ru_nivcsw;
        /* disk io */
        process_read_io_stats(&stats_r->disk_input, &stats_r->disk_output);
        user_trans_stats_get(suser, &stats_r->trans_stats);
@@ -247,24 +252,36 @@ static void stats_io_activate(void *context)
        mail_stats_get(suser, &suser->pre_io_stats);
 }
 
+static void timeval_add_diff(struct timeval *dest,
+                            const struct timeval *newsrc,
+                            const struct timeval *oldsrc)
+{
+       long long usecs;
+
+       usecs = timeval_diff_usecs(newsrc, oldsrc);
+       dest->tv_sec += usecs / USECS_PER_SEC;
+       dest->tv_usec += usecs % USECS_PER_SEC;
+       if (dest->tv_usec > USECS_PER_SEC) {
+               dest->tv_usec -= USECS_PER_SEC;
+               dest->tv_sec++;
+       }
+}
+
 void mail_stats_add_diff(struct mail_stats *dest,
                         const struct mail_stats *old_stats,
                         const struct mail_stats *new_stats)
 {
-       struct timeval *tv;
-       long long usecs;
-
        dest->disk_input += new_stats->disk_input - old_stats->disk_input;
        dest->disk_output += new_stats->disk_output - old_stats->disk_output;
-
-       usecs = timeval_diff_usecs(&new_stats->cpu_secs, &old_stats->cpu_secs);
-       tv = &dest->cpu_secs;
-       tv->tv_sec += usecs / USECS_PER_SEC;
-       tv->tv_usec += usecs % USECS_PER_SEC;
-       if (tv->tv_usec > USECS_PER_SEC) {
-               tv->tv_usec -= USECS_PER_SEC;
-               tv->tv_sec++;
-       }
+       dest->min_faults += new_stats->min_faults - old_stats->min_faults;
+       dest->maj_faults += new_stats->maj_faults - old_stats->maj_faults;
+       dest->vol_cs += new_stats->vol_cs - old_stats->vol_cs;
+       dest->invol_cs += new_stats->invol_cs - old_stats->invol_cs;
+
+       timeval_add_diff(&dest->user_cpu, &new_stats->user_cpu,
+                        &old_stats->user_cpu);
+       timeval_add_diff(&dest->sys_cpu, &new_stats->sys_cpu,
+                        &old_stats->sys_cpu);
        trans_stats_dec(&dest->trans_stats, &old_stats->trans_stats);
        trans_stats_add(&dest->trans_stats, &new_stats->trans_stats);
 }
@@ -273,8 +290,14 @@ void mail_stats_export(string_t *str, const struct mail_stats *stats)
 {
        const struct mailbox_transaction_stats *tstats = &stats->trans_stats;
 
-       str_printfa(str, "\tcpu=%ld.%ld", (long)stats->cpu_secs.tv_sec,
-                   (long)stats->cpu_secs.tv_usec);
+       str_printfa(str, "\tucpu=%ld.%ld", (long)stats->user_cpu.tv_sec,
+                   (long)stats->user_cpu.tv_usec);
+       str_printfa(str, "\tscpu=%ld.%ld", (long)stats->sys_cpu.tv_sec,
+                   (long)stats->sys_cpu.tv_usec);
+       str_printfa(str, "\tminflt=%u", stats->min_faults);
+       str_printfa(str, "\tmajflt=%u", stats->maj_faults);
+       str_printfa(str, "\tvolcs=%u", stats->vol_cs);
+       str_printfa(str, "\tinvolcs=%u", stats->invol_cs);
        str_printfa(str, "\tdiskin=%llu",
                    (unsigned long long)stats->disk_input);
        str_printfa(str, "\tdiskout=%llu",
index f3f3930a5679839014fa5b2e26f5bdf2b5190514..8f46977a716881dd43b5b08d92a8797b7434f40e 100644 (file)
        MODULE_CONTEXT(obj, stats_user_module)
 
 struct mail_stats {
-       struct timeval cpu_secs;
+       /* user/system CPU time used */
+       struct timeval user_cpu, sys_cpu;
+       /* minor / major page faults */
+       uint32_t min_faults, maj_faults;
+       /* voluntary / involuntary context switches */
+       uint32_t vol_cs, invol_cs;
+       /* disk input/output bytes */
        uint64_t disk_input, disk_output;
        struct mailbox_transaction_stats trans_stats;
 };
index 77260c6b3e979c58c87822ddf33ebcab524b8b3b..fc2255414010f548db49cd9152c1de7735d0dcb9 100644 (file)
@@ -97,11 +97,17 @@ mail_export_parse_filter(const char *const *args, pool_t pool,
 static void
 client_export_mail_stats(string_t *str, const struct mail_stats *stats)
 {
-#define MAIL_STATS_HEADER "\tcpu\tdisk_input\tdisk_output" \
+#define MAIL_STATS_HEADER "\tuser_cpu\tsys_cpu" \
+       "\tmin_faults\tmaj_faults\tvol_cs\tinvol_cs" \
+       "\tdisk_input\tdisk_output" \
        "\tlookup_path\tlookup_attr\tread_count\tread_bytes\tcache_hits\n"
 
-       str_printfa(str, "\t%ld.%u", (long)stats->cpu_secs.tv_sec,
-                   (unsigned int)stats->cpu_secs.tv_usec);
+       str_printfa(str, "\t%ld.%u", (long)stats->user_cpu.tv_sec,
+                   (unsigned int)stats->user_cpu.tv_usec);
+       str_printfa(str, "\t%ld.%u", (long)stats->sys_cpu.tv_sec,
+                   (unsigned int)stats->sys_cpu.tv_usec);
+       str_printfa(str, "\t%u\t%u", stats->min_faults, stats->maj_faults);
+       str_printfa(str, "\t%u\t%u", stats->vol_cs, stats->invol_cs);
        str_printfa(str, "\t%llu\t%llu",
                    (unsigned long long)stats->disk_input,
                    (unsigned long long)stats->disk_output);
index aa04ad19e6837cf48114fe587d1bca8889c56ad7..3e6f5ee8d43a7b9765f90a66a8cdad15b2c1837e 100644 (file)
@@ -4,22 +4,35 @@
 #include "time-util.h"
 #include "mail-stats.h"
 
+enum mail_stats_type {
+       TYPE_NUM,
+       TYPE_TIMEVAL
+};
+
 struct mail_stats_parse_map {
        const char *name;
        unsigned int offset;
        unsigned int size;
+       enum mail_stats_type type;
 } parse_map[] = {
-#define E(parsename, name) { parsename, offsetof(struct mail_stats, name), sizeof(((struct mail_stats *)0)->name) }
-       E("diskin", disk_input),
-       E("diskout", disk_output),
-       E("lpath", lookup_path),
-       E("lattr", lookup_attr),
-       E("rcount", read_count),
-       E("rbytes", read_bytes),
-       E("cache", cache_hits)
+#define E(parsename, name, type) { parsename, offsetof(struct mail_stats, name), sizeof(((struct mail_stats *)0)->name), type }
+#define EN(parsename, name) E(parsename, name, TYPE_NUM)
+       E("ucpu", user_cpu, TYPE_TIMEVAL),
+       E("scpu", sys_cpu, TYPE_TIMEVAL),
+       EN("minflt", min_faults),
+       EN("majflt", maj_faults),
+       EN("volcs", vol_cs),
+       EN("involcs", invol_cs),
+       EN("diskin", disk_input),
+       EN("diskout", disk_output),
+       EN("lpath", lookup_path),
+       EN("lattr", lookup_attr),
+       EN("rcount", read_count),
+       EN("rbytes", read_bytes),
+       EN("cache", cache_hits)
 };
 
-static int mail_stats_parse_cpu(const char *value, struct mail_stats *stats)
+static int mail_stats_parse_timeval(const char *value, struct timeval *tv)
 {
        const char *p, *secs_str;
        unsigned long secs, usecs;
@@ -34,8 +47,8 @@ static int mail_stats_parse_cpu(const char *value, struct mail_stats *stats)
            usecs > 1000000)
                return -1;
 
-       stats->cpu_secs.tv_sec = secs;
-       stats->cpu_secs.tv_usec = usecs;
+       tv->tv_sec = secs;
+       tv->tv_usec = usecs;
        return 0;
 }
 
@@ -63,21 +76,31 @@ mail_stats_parse_one(const char *key, const char *value,
                return 0;
 
        dest = PTR_OFFSET(stats, map->offset);
-       switch (map->size) {
-       case sizeof(uint32_t):
-               if (str_to_uint32(value, dest) < 0) {
-                       *error_r = "invalid number";
-                       return -1;
+       switch (map->type) {
+       case TYPE_NUM:
+               switch (map->size) {
+               case sizeof(uint32_t):
+                       if (str_to_uint32(value, dest) < 0) {
+                               *error_r = "invalid number";
+                               return -1;
+                       }
+                       break;
+               case sizeof(uint64_t):
+                       if (str_to_uint64(value, dest) < 0) {
+                               *error_r = "invalid number";
+                               return -1;
+                       }
+                       break;
+               default:
+                       i_unreached();
                }
                break;
-       case sizeof(uint64_t):
-               if (str_to_uint64(value, dest) < 0) {
-                       *error_r = "invalid number";
+       case TYPE_TIMEVAL:
+               if (mail_stats_parse_timeval(value, dest) < 0) {
+                       *error_r = "invalid cpu parameter";
                        return -1;
                }
                break;
-       default:
-               i_unreached();
        }
        return 0;
 }
@@ -97,74 +120,127 @@ int mail_stats_parse(const char *const *args, struct mail_stats *stats_r,
                }
                key = t_strdup_until(args[i], p);
                value = p + 1;
-               if (strcmp(key, "cpu") == 0) {
-                       if (mail_stats_parse_cpu(value, stats_r) < 0) {
-                               *error_r = "invalid cpu parameter";
-                               return -1;
-                       }
-               } else {
-                       if (mail_stats_parse_one(key, value,
-                                                stats_r, error_r) < 0)
-                               return -1;
-               }
+               if (mail_stats_parse_one(key, value, stats_r, error_r) < 0)
+                       return -1;
        }
        return 0;
 }
 
-bool mail_stats_diff(const struct mail_stats *stats1,
-                    const struct mail_stats *stats2,
-                    struct mail_stats *diff_stats_r)
+static bool mail_stats_diff_timeval(struct timeval *dest,
+                                   const struct timeval *src1,
+                                   const struct timeval *src2)
 {
        long long diff_usecs;
 
-       memset(diff_stats_r, 0, sizeof(*diff_stats_r));
-
-       diff_usecs = timeval_diff_usecs(&stats2->cpu_secs, &stats1->cpu_secs);
+       diff_usecs = timeval_diff_usecs(src2, src1);
        if (diff_usecs < 0)
                return FALSE;
-       diff_stats_r->cpu_secs.tv_sec = diff_usecs / 1000000;
-       diff_stats_r->cpu_secs.tv_usec = diff_usecs % 1000000;
+       dest->tv_sec = diff_usecs / 1000000;
+       dest->tv_usec = diff_usecs % 1000000;
+       return TRUE;
+}
 
-       if (stats1->disk_input > stats2->disk_input)
-               return FALSE;
-       diff_stats_r->disk_input = stats2->disk_input - stats1->disk_input;
-       if (stats1->disk_output > stats2->disk_output)
+static bool
+mail_stats_diff_uint32(uint32_t *dest, const uint32_t *src1,
+                      const uint32_t *src2)
+{
+       if (*src1 > *src2)
                return FALSE;
-       diff_stats_r->disk_output = stats2->disk_output - stats1->disk_output;
+       *dest = *src2 - *src1;
+       return TRUE;
+}
 
-       if (stats1->lookup_path > stats2->lookup_path)
-               return FALSE;
-       diff_stats_r->lookup_path = stats2->lookup_path - stats1->lookup_path;
-       if (stats1->lookup_attr > stats2->lookup_attr)
-               return FALSE;
-       diff_stats_r->lookup_attr = stats2->lookup_attr - stats1->lookup_attr;
-       if (stats1->read_count > stats2->read_count)
-               return FALSE;
-       diff_stats_r->read_count = stats2->read_count - stats1->read_count;
-       if (stats1->cache_hits > stats2->cache_hits)
-               return FALSE;
-       diff_stats_r->cache_hits = stats2->cache_hits - stats1->cache_hits;
-       if (stats1->read_bytes > stats2->read_bytes)
+static bool
+mail_stats_diff_uint64(uint64_t *dest, const uint64_t *src1,
+                      const uint64_t *src2)
+{
+       if (*src1 > *src2)
                return FALSE;
-       diff_stats_r->read_bytes = stats2->read_bytes - stats1->read_bytes;
+       *dest = *src2 - *src1;
+       return TRUE;
+}
+
+bool mail_stats_diff(const struct mail_stats *stats1,
+                    const struct mail_stats *stats2,
+                    struct mail_stats *diff_stats_r)
+{
+       unsigned int i;
+
+       memset(diff_stats_r, 0, sizeof(*diff_stats_r));
 
+       for (i = 0; i < N_ELEMENTS(parse_map); i++) {
+               unsigned int offset = parse_map[i].offset;
+               void *dest = PTR_OFFSET(diff_stats_r, offset);
+               const void *src1 = CONST_PTR_OFFSET(stats1, offset);
+               const void *src2 = CONST_PTR_OFFSET(stats2, offset);
+
+               switch (parse_map[i].type) {
+               case TYPE_NUM:
+                       switch (parse_map[i].size) {
+                       case sizeof(uint32_t):
+                               if (!mail_stats_diff_uint32(dest, src1, src2))
+                                       return FALSE;
+                               break;
+                       case sizeof(uint64_t):
+                               if (!mail_stats_diff_uint64(dest, src1, src2))
+                                       return FALSE;
+                               break;
+                       default:
+                               i_unreached();
+                       }
+                       break;
+               case TYPE_TIMEVAL:
+                       if (!mail_stats_diff_timeval(dest, src1, src2))
+                               return FALSE;
+                       break;
+               }
+       }
        return TRUE;
 }
 
+static void timeval_add(struct timeval *dest, const struct timeval *src)
+{
+       dest->tv_sec += src->tv_sec;
+       dest->tv_usec += src->tv_usec;
+       if (dest->tv_usec > 1000000) {
+               dest->tv_usec -= 1000000;
+               dest->tv_sec++;
+       }
+}
+
 void mail_stats_add(struct mail_stats *dest, const struct mail_stats *src)
 {
-       dest->cpu_secs.tv_sec += src->cpu_secs.tv_sec;
-       dest->cpu_secs.tv_usec += src->cpu_secs.tv_usec;
-       if (dest->cpu_secs.tv_usec > 1000000) {
-               dest->cpu_secs.tv_usec -= 1000000;
-               dest->cpu_secs.tv_sec++;
+       unsigned int i;
+
+       for (i = 0; i < N_ELEMENTS(parse_map); i++) {
+               unsigned int offset = parse_map[i].offset;
+               void *f_dest = PTR_OFFSET(dest, offset);
+               const void *f_src = CONST_PTR_OFFSET(src, offset);
+
+               switch (parse_map[i].type) {
+               case TYPE_NUM:
+                       switch (parse_map[i].size) {
+                       case sizeof(uint32_t): {
+                               uint32_t *n_dest = f_dest;
+                               const uint32_t *n_src = f_src;
+
+                               *n_dest += *n_src;
+                               break;
+                       }
+                       case sizeof(uint64_t): {
+                               uint64_t *n_dest = f_dest;
+                               const uint64_t *n_src = f_src;
+
+                               *n_dest += *n_src;
+                               break;
+                       }
+                       default:
+                               i_unreached();
+                       }
+                       break;
+               case TYPE_TIMEVAL:
+                       timeval_add(f_dest, f_src);
+                       break;
+               }
        }
-       dest->disk_input += src->disk_input;
-       dest->disk_output += src->disk_output;
-
-       dest->lookup_path += src->lookup_path;
-       dest->lookup_attr += src->lookup_attr;
-       dest->read_count += src->read_count;
-       dest->cache_hits += src->cache_hits;
-       dest->read_bytes += src->read_bytes;
 }
index 13b10c19aae614bfa812f8e32ef3a1f47b8605d4..419fa87718004bc2018e85848b372acc5c2c3d0f 100644 (file)
@@ -5,7 +5,9 @@
 #include "guid.h"
 
 struct mail_stats {
-       struct timeval cpu_secs;
+       struct timeval user_cpu, sys_cpu;
+       uint32_t min_faults, maj_faults;
+       uint32_t vol_cs, invol_cs;
        uint64_t disk_input, disk_output;
 
        uint32_t lookup_path, lookup_attr, read_count, cache_hits;