~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to vswitchd/system-stats.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2010, 2012 Nicira, Inc.
 
1
/* Copyright (c) 2010, 2012, 2013 Nicira, Inc.
2
2
 *
3
3
 * Licensed under the Apache License, Version 2.0 (the "License");
4
4
 * you may not use this file except in compliance with the License.
35
35
#include "dirs.h"
36
36
#include "dynamic-string.h"
37
37
#include "json.h"
 
38
#include "latch.h"
38
39
#include "ofpbuf.h"
 
40
#include "ovs-thread.h"
39
41
#include "poll-loop.h"
40
42
#include "shash.h"
41
43
#include "smap.h"
42
44
#include "timeval.h"
43
45
#include "vlog.h"
44
 
#include "worker.h"
45
46
 
46
47
VLOG_DEFINE_THIS_MODULE(system_stats);
47
48
 
97
98
{
98
99
    if (!LINUX_DATAPATH) {
99
100
        unsigned int pagesize = get_page_size();
 
101
#ifdef _SC_PHYS_PAGES
100
102
        long int phys_pages = sysconf(_SC_PHYS_PAGES);
 
103
#else
 
104
        long int phys_pages = 0;
 
105
#endif
101
106
#ifdef _SC_AVPHYS_PAGES
102
107
        long int avphys_pages = sysconf(_SC_AVPHYS_PAGES);
103
108
#else
127
132
 
128
133
        stream = fopen(file_name, "r");
129
134
        if (!stream) {
130
 
            VLOG_WARN_ONCE("%s: open failed (%s)", file_name, strerror(errno));
 
135
            VLOG_WARN_ONCE("%s: open failed (%s)",
 
136
                           file_name, ovs_strerror(errno));
131
137
            return;
132
138
        }
133
139
 
179
185
 
180
186
        stream = fopen(stat_file, "r");
181
187
        if (!stream) {
182
 
            VLOG_ERR_ONCE("%s: open failed (%s)", stat_file, strerror(errno));
 
188
            VLOG_ERR_ONCE("%s: open failed (%s)",
 
189
                          stat_file, ovs_strerror(errno));
183
190
            return boot_time;
184
191
        }
185
192
 
238
245
    sprintf(file_name, "/proc/%lu/stat", (unsigned long int) pid);
239
246
    stream = fopen(file_name, "r");
240
247
    if (!stream) {
241
 
        VLOG_ERR_ONCE("%s: open failed (%s)", file_name, strerror(errno));
 
248
        VLOG_ERR_ONCE("%s: open failed (%s)",
 
249
                      file_name, ovs_strerror(errno));
242
250
        return false;
243
251
    }
244
252
 
323
331
    sprintf(file_name, "/proc/%lu/cmdline", (unsigned long int) pid);
324
332
    stream = fopen(file_name, "r");
325
333
    if (!stream) {
326
 
        VLOG_WARN_ONCE("%s: open failed (%s)", file_name, strerror(errno));
 
334
        VLOG_WARN_ONCE("%s: open failed (%s)", file_name, ovs_strerror(errno));
327
335
        goto exit;
328
336
    }
329
337
 
330
338
    if (!fgets(line, sizeof line, stream)) {
331
339
        VLOG_WARN_ONCE("%s: read failed (%s)", file_name,
332
 
                       feof(stream) ? "end of file" : strerror(errno));
 
340
                       feof(stream) ? "end of file" : ovs_strerror(errno));
333
341
        goto exit_close;
334
342
    }
335
343
 
394
402
 
395
403
    dir = opendir(ovs_rundir());
396
404
    if (!dir) {
397
 
        VLOG_ERR_ONCE("%s: open failed (%s)", ovs_rundir(), strerror(errno));
 
405
        VLOG_ERR_ONCE("%s: open failed (%s)",
 
406
                      ovs_rundir(), ovs_strerror(errno));
398
407
        return;
399
408
    }
400
409
 
443
452
static void
444
453
get_filesys_stats(struct smap *stats OVS_UNUSED)
445
454
{
446
 
#if HAVE_SETMNTENT && HAVE_STATVFS
 
455
#if HAVE_GETMNTENT_R && HAVE_STATVFS
447
456
    static const char file_name[] = "/etc/mtab";
 
457
    struct mntent mntent;
448
458
    struct mntent *me;
 
459
    char buf[4096];
449
460
    FILE *stream;
450
461
    struct ds s;
451
462
 
452
463
    stream = setmntent(file_name, "r");
453
464
    if (!stream) {
454
 
        VLOG_ERR_ONCE("%s: open failed (%s)", file_name, strerror(errno));
 
465
        VLOG_ERR_ONCE("%s: open failed (%s)", file_name, ovs_strerror(errno));
455
466
        return;
456
467
    }
457
468
 
458
469
    ds_init(&s);
459
 
    while ((me = getmntent(stream)) != NULL) {
 
470
    while ((me = getmntent_r(stream, &mntent, buf, sizeof buf)) != NULL) {
460
471
        unsigned long long int total, free;
461
472
        struct statvfs vfs;
462
473
        char *p;
490
501
        smap_add(stats, "file_systems", ds_cstr(&s));
491
502
    }
492
503
    ds_destroy(&s);
493
 
#endif  /* HAVE_SETMNTENT && HAVE_STATVFS */
 
504
#endif  /* HAVE_GETMNTENT_R && HAVE_STATVFS */
494
505
}
495
506
 
496
507
#define SYSTEM_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
497
508
 
498
 
/* Whether the client wants us to report system stats. */
 
509
static struct ovs_mutex mutex = OVS_ADAPTIVE_MUTEX_INITIALIZER;
 
510
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 
511
static struct latch latch OVS_GUARDED_BY(mutex);
499
512
static bool enabled;
500
 
 
501
 
static enum {
502
 
    S_DISABLED,                 /* Not enabled, nothing going on. */
503
 
    S_WAITING,                  /* Sleeping for SYSTEM_STATS_INTERVAL ms. */
504
 
    S_REQUEST_SENT,             /* Sent a request to worker. */
505
 
    S_REPLY_RECEIVED            /* Received a reply from worker. */
506
 
} state;
507
 
 
508
 
/* In S_WAITING state: the next time to wake up.
509
 
 * In other states: not meaningful. */
510
 
static long long int next_refresh;
511
 
 
512
 
/* In S_REPLY_RECEIVED: the stats that have just been received.
513
 
 * In other states: not meaningful. */
514
 
static struct smap *received_stats;
515
 
 
516
 
static worker_request_func system_stats_request_cb;
517
 
static worker_reply_func system_stats_reply_cb;
518
 
 
519
 
/* Enables or disables system stats collection, according to 'new_enable'.
520
 
 *
521
 
 * Even if system stats are disabled, the caller should still periodically call
522
 
 * system_stats_run(). */
 
513
static bool started OVS_GUARDED_BY(mutex);
 
514
static struct smap *system_stats OVS_GUARDED_BY(mutex);
 
515
 
 
516
static void *system_stats_thread_func(void *);
 
517
static void discard_stats(void);
 
518
 
 
519
/* Enables or disables system stats collection, according to 'enable'. */
523
520
void
524
 
system_stats_enable(bool new_enable)
 
521
system_stats_enable(bool enable)
525
522
{
526
 
    if (new_enable != enabled) {
527
 
        if (new_enable) {
528
 
            if (state == S_DISABLED) {
529
 
                state = S_WAITING;
530
 
                next_refresh = time_msec();
531
 
            }
532
 
        } else {
533
 
            if (state == S_WAITING) {
534
 
                state = S_DISABLED;
535
 
            }
 
523
    if (enabled != enable) {
 
524
        ovs_mutex_lock(&mutex);
 
525
        if (enable) {
 
526
            if (!started) {
 
527
                xpthread_create(NULL, NULL, system_stats_thread_func, NULL);
 
528
                latch_init(&latch);
 
529
                started = true;
 
530
            }
 
531
            discard_stats();
 
532
            xpthread_cond_signal(&cond);
536
533
        }
537
 
        enabled = new_enable;
 
534
        enabled = enable;
 
535
        ovs_mutex_unlock(&mutex);
538
536
    }
539
537
}
540
538
 
543
541
 *
544
542
 * When a new snapshot is available (which only occurs if system stats are
545
543
 * enabled), returns it as an smap owned by the caller.  The caller must use
546
 
 * both smap_destroy() and free() to complete free the returned data.
 
544
 * both smap_destroy() and free() to completely free the returned data.
547
545
 *
548
546
 * When no new snapshot is available, returns NULL. */
549
547
struct smap *
550
548
system_stats_run(void)
551
549
{
552
 
    switch (state) {
553
 
    case S_DISABLED:
554
 
        break;
555
 
 
556
 
    case S_WAITING:
557
 
        if (time_msec() >= next_refresh) {
558
 
            worker_request(NULL, 0, NULL, 0, system_stats_request_cb,
559
 
                           system_stats_reply_cb, NULL);
560
 
            state = S_REQUEST_SENT;
561
 
        }
562
 
        break;
563
 
 
564
 
    case S_REQUEST_SENT:
565
 
        break;
566
 
 
567
 
    case S_REPLY_RECEIVED:
 
550
    struct smap *stats = NULL;
 
551
 
 
552
    ovs_mutex_lock(&mutex);
 
553
    if (system_stats) {
 
554
        latch_poll(&latch);
 
555
 
568
556
        if (enabled) {
569
 
            state = S_WAITING;
570
 
            next_refresh = time_msec() + SYSTEM_STATS_INTERVAL;
571
 
            return received_stats;
 
557
            stats = system_stats;
 
558
            system_stats = NULL;
572
559
        } else {
573
 
            smap_destroy(received_stats);
574
 
            free(received_stats);
575
 
            state = S_DISABLED;
 
560
            discard_stats();
576
561
        }
577
 
        break;
578
562
    }
 
563
    ovs_mutex_unlock(&mutex);
579
564
 
580
 
    return NULL;
 
565
    return stats;
581
566
}
582
567
 
583
568
/* Causes poll_block() to wake up when system_stats_run() needs to be
585
570
void
586
571
system_stats_wait(void)
587
572
{
588
 
    switch (state) {
589
 
    case S_DISABLED:
590
 
        break;
591
 
 
592
 
    case S_WAITING:
593
 
        poll_timer_wait_until(next_refresh);
594
 
        break;
595
 
 
596
 
    case S_REQUEST_SENT:
597
 
        /* Someone else should be calling worker_wait() to wake up when the
598
 
         * reply arrives, otherwise there's a bug. */
599
 
        break;
600
 
 
601
 
    case S_REPLY_RECEIVED:
602
 
        poll_immediate_wake();
603
 
        break;
604
 
    }
605
 
}
606
 
 
607
 
static void
608
 
system_stats_request_cb(struct ofpbuf *request OVS_UNUSED,
609
 
                        const int fds[] OVS_UNUSED, size_t n_fds OVS_UNUSED)
610
 
{
611
 
    struct smap stats;
612
 
    struct json *json;
613
 
    char *s;
614
 
 
615
 
    smap_init(&stats);
616
 
    get_cpu_cores(&stats);
617
 
    get_load_average(&stats);
618
 
    get_memory_stats(&stats);
619
 
    get_process_stats(&stats);
620
 
    get_filesys_stats(&stats);
621
 
 
622
 
    json = smap_to_json(&stats);
623
 
    s = json_to_string(json, 0);
624
 
    worker_reply(s, strlen(s) + 1, NULL, 0);
625
 
 
626
 
    free(s);
627
 
    json_destroy(json);
628
 
    smap_destroy(&stats);
629
 
}
630
 
 
631
 
static void
632
 
system_stats_reply_cb(struct ofpbuf *reply,
633
 
                      const int fds[] OVS_UNUSED, size_t n_fds OVS_UNUSED,
634
 
                      void *aux OVS_UNUSED)
635
 
{
636
 
    struct json *json = json_from_string(reply->data);
637
 
 
638
 
    received_stats = xmalloc(sizeof *received_stats);
639
 
    smap_init(received_stats);
640
 
    smap_from_json(received_stats, json);
641
 
 
642
 
    ovs_assert(state == S_REQUEST_SENT);
643
 
    state = S_REPLY_RECEIVED;
644
 
 
645
 
    json_destroy(json);
 
573
    if (enabled) {
 
574
        latch_wait(&latch);
 
575
    }
 
576
}
 
577
 
 
578
static void
 
579
discard_stats(void) OVS_REQUIRES(&mutex)
 
580
{
 
581
    if (system_stats) {
 
582
        smap_destroy(system_stats);
 
583
        free(system_stats);
 
584
        system_stats = NULL;
 
585
    }
 
586
}
 
587
 
 
588
static void * NO_RETURN
 
589
system_stats_thread_func(void *arg OVS_UNUSED)
 
590
{
 
591
    pthread_detach(pthread_self());
 
592
 
 
593
    for (;;) {
 
594
        long long int next_refresh;
 
595
        struct smap *stats;
 
596
 
 
597
        ovs_mutex_lock(&mutex);
 
598
        while (!enabled) {
 
599
            ovs_mutex_cond_wait(&cond, &mutex);
 
600
        }
 
601
        ovs_mutex_unlock(&mutex);
 
602
 
 
603
        stats = xmalloc(sizeof *stats);
 
604
        smap_init(stats);
 
605
        get_cpu_cores(stats);
 
606
        get_load_average(stats);
 
607
        get_memory_stats(stats);
 
608
        get_process_stats(stats);
 
609
        get_filesys_stats(stats);
 
610
 
 
611
        ovs_mutex_lock(&mutex);
 
612
        discard_stats();
 
613
        system_stats = stats;
 
614
        latch_set(&latch);
 
615
        ovs_mutex_unlock(&mutex);
 
616
 
 
617
        next_refresh = time_msec() + SYSTEM_STATS_INTERVAL;
 
618
        do {
 
619
            poll_timer_wait_until(next_refresh);
 
620
            poll_block();
 
621
        } while (time_msec() < next_refresh);
 
622
    }
646
623
}