nodeinfo.c 5.6 KB
Newer Older
1 2 3
/*
 * nodeinfo.c: Helper routines for OS specific node information
 *
4
 * Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24
#include <config.h>
J
Jim Meyering 已提交
25

26 27 28 29
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
30
#include <c-ctype.h>
31

32 33 34 35
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif

36
#include "nodeinfo.h"
37
#include "physmem.h"
38
#include "util.h"
39 40 41 42 43

#ifdef __linux__
#define CPUINFO_PATH "/proc/cpuinfo"

/* NB, these are not static as we need to call them from testsuite */
44 45
int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo,
                             virNodeInfoPtr nodeinfo);
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo, virNodeInfoPtr nodeinfo) {
    char line[1024];

    nodeinfo->cpus = 0;
    nodeinfo->mhz = 0;
    nodeinfo->nodes = nodeinfo->sockets = nodeinfo->cores = nodeinfo->threads = 1;

    /* NB: It is impossible to fill our nodes, since cpuinfo
     * has not knowledge of NUMA nodes */

    /* XXX hyperthreads */
    while (fgets(line, sizeof(line), cpuinfo) != NULL) {
        char *buf = line;
        if (STREQLEN(buf, "processor", 9)) { /* aka a single logical CPU */
            buf += 9;
62
            while (*buf && c_isspace(*buf))
63 64 65 66 67 68 69 70 71
                buf++;
            if (*buf != ':') {
                __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                                VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                                "parsing cpuinfo processor");
                return -1;
            }
            nodeinfo->cpus++;
        } else if (STREQLEN(buf, "cpu MHz", 7)) {
72 73
            char *p;
            unsigned int ui;
74
            buf += 9;
75
            while (*buf && c_isspace(*buf))
76 77 78 79 80 81 82
                buf++;
            if (*buf != ':' || !buf[1]) {
                __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                                VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                                "parsing cpuinfo cpu MHz");
                return -1;
            }
83
            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
84
                /* Accept trailing fractional part.  */
85
                && (*p == '\0' || *p == '.' || c_isspace(*p)))
86
                nodeinfo->mhz = ui;
87
        } else if (STREQLEN(buf, "cpu cores", 9)) { /* aka cores */
88
            char *p;
89 90
            unsigned int id;
            buf += 9;
91
            while (*buf && c_isspace(*buf))
92 93 94 95 96 97 98
                buf++;
            if (*buf != ':' || !buf[1]) {
                __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                                VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                                "parsing cpuinfo cpu cores %c", *buf);
                return -1;
            }
99
            if (virStrToLong_ui(buf+1, &p, 10, &id) == 0
100
                && (*p == '\0' || c_isspace(*p))
101
                && id > nodeinfo->cores)
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
                nodeinfo->cores = id;
        }
    }

    if (!nodeinfo->cpus) {
        __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                        VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                        "no cpus found");
        return -1;
    }

    /*
     * Can't reliably count sockets from proc metadata, so
     * infer it based on total CPUs vs cores.
     * XXX hyperthreads
     */
    nodeinfo->sockets = nodeinfo->cpus / nodeinfo->cores;

    return 0;
}

#endif

int virNodeInfoPopulate(virConnectPtr conn,
                        virNodeInfoPtr nodeinfo) {
127
#ifdef HAVE_UNAME
128 129 130 131 132 133 134 135 136 137 138
    struct utsname info;

    if (uname(&info) < 0) {
        __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                        VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                        "cannot extract machine type %s", strerror(errno));
        return -1;
    }
    strncpy(nodeinfo->model, info.machine, sizeof(nodeinfo->model)-1);
    nodeinfo->model[sizeof(nodeinfo->model)-1] = '\0';

139 140 141 142 143 144
#else /* !HAVE_UNAME */

    nodeinfo->model[0] = '\0';

#endif /* !HAVE_UNAME */

145
#ifdef __linux__
146 147 148
    {
    int ret;
    FILE *cpuinfo = fopen(CPUINFO_PATH, "r");
149 150 151 152 153 154 155 156 157 158 159
    if (!cpuinfo) {
        __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                        VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                        "cannot open %s %s", CPUINFO_PATH, strerror(errno));
        return -1;
    }
    ret = linuxNodeInfoCPUPopulate(conn, cpuinfo, nodeinfo);
    fclose(cpuinfo);
    if (ret < 0)
        return -1;

160 161
    /* Convert to KB. */
    nodeinfo->memory = physmem_total () / 1024;
162 163

    return ret;
164
    }
165 166 167 168 169 170 171 172
#else
    /* XXX Solaris will need an impl later if they port QEMU driver */
    __virRaiseError(conn, NULL, NULL, 0, VIR_ERR_INTERNAL_ERROR,
                    VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                    "%s:%s not implemented on this platform\n", __FILE__, __FUNCTION__);
    return -1;
#endif
}