]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
stats: Track [rw]char and sysc[rw] fields in /proc/self/io (with Linux).
authorTimo Sirainen <tss@iki.fi>
Mon, 12 Sep 2011 15:29:17 +0000 (18:29 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 12 Sep 2011 15:29:17 +0000 (18:29 +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 d74a9a7663f7a09daa97d38f4e1866832a1effd4..83a9bbc981fae9f6a4a49ac61826c12ef18dfedc 100644 (file)
@@ -81,6 +81,70 @@ static void user_trans_stats_get(struct stats_user *suser,
                trans_stats_add(dest_r, &strans->trans->stats);
 }
 
+static int
+process_io_buffer_parse(const char *buf, struct mail_stats *stats)
+{
+       const char *const *tmp;
+
+       tmp = t_strsplit(buf, "\n");
+       for (; *tmp != NULL; tmp++) {
+               if (strncmp(*tmp, "rchar: ", 7) == 0) {
+                       if (str_to_uint64(*tmp + 7, &stats->read_bytes) < 0)
+                               return -1;
+               } else if (strncmp(*tmp, "wchar: ", 7) == 0) {
+                       if (str_to_uint64(*tmp + 7, &stats->write_bytes) < 0)
+                               return -1;
+               } else if (strncmp(*tmp, "syscr: ", 7) == 0) {
+                       if (str_to_uint32(*tmp + 7, &stats->read_count) < 0)
+                               return -1;
+               } else if (strncmp(*tmp, "syscw: ", 7) == 0) {
+                       if (str_to_uint32(*tmp + 7, &stats->write_count) < 0)
+                               return -1;
+               }
+       }
+       return 0;
+}
+
+static void process_read_io_stats(struct mail_stats *stats)
+{
+       const char *path = "/proc/self/io";
+       static bool io_disabled = FALSE;
+       char buf[1024];
+       int fd, ret;
+
+       if (io_disabled)
+               return;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               if (errno != ENOENT)
+                       i_error("open(%s) failed: %m", path);
+               io_disabled = TRUE;
+               return;
+       }
+       ret = read(fd, buf, sizeof(buf));
+       if (ret <= 0) {
+               if (ret == -1)
+                       i_error("read(%s) failed: %m", path);
+               else
+                       i_error("read(%s) returned EOF", path);
+       } else if (ret == sizeof(buf)) {
+               /* just shouldn't happen.. */
+               i_error("%s is larger than expected", path);
+               io_disabled = TRUE;
+       } else {
+               buf[ret] = '\0';
+               T_BEGIN {
+                       if (process_io_buffer_parse(buf, stats) < 0) {
+                               i_error("Invalid input in file %s", path);
+                               io_disabled = TRUE;
+                       }
+               } T_END;
+       }
+       if (close(fd) < 0)
+               i_error("close(%s) failed: %m", path);
+}
+
 void mail_stats_get(struct stats_user *suser, struct mail_stats *stats_r)
 {
        struct rusage usage;
@@ -97,6 +161,7 @@ void mail_stats_get(struct stats_user *suser, struct mail_stats *stats_r)
        stats_r->invol_cs = usage.ru_nivcsw;
        stats_r->disk_input = (unsigned long long)usage.ru_inblock * 512ULL;
        stats_r->disk_output = (unsigned long long)usage.ru_oublock * 512ULL;
+       process_read_io_stats(stats_r);
        user_trans_stats_get(suser, &stats_r->trans_stats);
 }
 
@@ -213,6 +278,10 @@ void mail_stats_add_diff(struct mail_stats *dest,
        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;
+       dest->read_count += new_stats->read_count - old_stats->read_count;
+       dest->write_count += new_stats->write_count - old_stats->write_count;
+       dest->read_bytes += new_stats->read_bytes - old_stats->read_bytes;
+       dest->write_bytes += new_stats->write_bytes - old_stats->write_bytes;
 
        timeval_add_diff(&dest->user_cpu, &new_stats->user_cpu,
                         &old_stats->user_cpu);
@@ -238,6 +307,12 @@ void mail_stats_export(string_t *str, const struct mail_stats *stats)
                    (unsigned long long)stats->disk_input);
        str_printfa(str, "\tdiskout=%llu",
                    (unsigned long long)stats->disk_output);
+       str_printfa(str, "\trchar=%llu",
+                   (unsigned long long)stats->read_bytes);
+       str_printfa(str, "\twchar=%llu",
+                   (unsigned long long)stats->write_bytes);
+       str_printfa(str, "\tsyscr=%u", stats->read_count);
+       str_printfa(str, "\tsyscw=%u", stats->write_count);
        str_printfa(str, "\tmlpath=%lu",
                    tstats->open_lookup_count + tstats->stat_lookup_count);
        str_printfa(str, "\tmlattr=%lu",
@@ -278,6 +353,8 @@ static bool session_has_changed(const struct mail_stats *prev,
                return TRUE;
        if (cur->invol_cs > prev->invol_cs+10)
                return TRUE;
+       /* don't check for read/write count/bytes changes, since they get
+          changed by stats checking itself */
        return FALSE;
 }
 
index ce476a666550288452107e1d8d83405ba48ccdee..5f25e5535a200a018a5b2b91e07e57413cd43e61 100644 (file)
@@ -18,6 +18,9 @@ struct mail_stats {
        uint32_t vol_cs, invol_cs;
        /* disk input/output bytes */
        uint64_t disk_input, disk_output;
+       /* read()/write() syscall count and number of bytes */
+       uint32_t read_count, write_count;
+       uint64_t read_bytes, write_bytes;
        struct mailbox_transaction_stats trans_stats;
 };
 
index 2f324ff3d933f2492719cc0dac5709b4a454248d..f8e554e2a3ed69dc3ee61c4ac38bedf5d607cf0f 100644 (file)
@@ -100,6 +100,7 @@ client_export_mail_stats(string_t *str, const struct mail_stats *stats)
 #define MAIL_STATS_HEADER "\tuser_cpu\tsys_cpu" \
        "\tmin_faults\tmaj_faults\tvol_cs\tinvol_cs" \
        "\tdisk_input\tdisk_output" \
+       "\tread_count\tread_bytes\twrite_count\twrite_bytes" \
        "\tmail_lookup_path\tmail_lookup_attr" \
        "\tmail_read_count\tmail_read_bytes\tmail_cache_hits\n"
 
@@ -112,6 +113,9 @@ client_export_mail_stats(string_t *str, const struct mail_stats *stats)
        str_printfa(str, "\t%llu\t%llu",
                    (unsigned long long)stats->disk_input,
                    (unsigned long long)stats->disk_output);
+       str_printfa(str, "\t%u\t%llu\t%u\t%llu",
+                   stats->read_count, (unsigned long long)stats->read_bytes,
+                   stats->write_count, (unsigned long long)stats->write_bytes);
        str_printfa(str, "\t%u\t%u\t%u\t%llu\t%u",
                    stats->mail_lookup_path, stats->mail_lookup_attr,
                    stats->mail_read_count,
index 605f0ad0bf2b37158cec42ea4b323e4118049c63..e86e825c2dface214649a19466ca9c609d1ad686 100644 (file)
@@ -26,6 +26,11 @@ struct mail_stats_parse_map {
        EN("diskin", disk_input),
        EN("diskout", disk_output),
 
+       EN("rchar", read_bytes),
+       EN("wchar", write_bytes),
+       EN("syscr", read_count),
+       EN("syscw", write_count),
+
        EN("mlpath", mail_lookup_path),
        EN("mlattr", mail_lookup_attr),
        EN("mrcount", mail_read_count),
index c99d8813aa6219b9b7e227f36bb19c395ced91cb..807521020dd17c3f2559f158b647026b4a83434b 100644 (file)
@@ -10,6 +10,9 @@ struct mail_stats {
        uint32_t vol_cs, invol_cs;
        uint64_t disk_input, disk_output;
 
+       uint32_t read_count, write_count;
+       uint64_t read_bytes, write_bytes;
+
        uint32_t mail_lookup_path, mail_lookup_attr, mail_read_count;
        uint32_t mail_cache_hits;
        uint64_t mail_read_bytes;