DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] tools:new tool for system info CPU, memory and huge pages
@ 2016-05-13 15:43 Keith Wiles
  2016-05-19 12:20 ` Hunt, David
  0 siblings, 1 reply; 2+ messages in thread
From: Keith Wiles @ 2016-05-13 15:43 UTC (permalink / raw)
  To: dev

The new tool uses /sys/devices instead of /proc directory, which
does not exist on all systems. If the procfs is not available
then memory and huge page information is skipped.

The tool also can emit a json format in short or long form to
allow for machine readable information.

Here is the usage information:

Usage: sys_info.py [options]

Show the lcores layout with core id and socket(s).

Options:
    --help or -h:
        Display the usage information and quit

    --long or -l:
        Display the information in a machine readable long format.

    --short or -s:
        Display the information in a machine readable short format.

    --pci or -p:
        Display all of the Ethernet devices in the system using 'lspci'.

    --version or -v:
        Display the current version number of this script.

    --debug or -d:
        Output some debug information.

    default:
        Display the information in a human readable format.

Signed-off-by: Keith Wiles <keith.wiles@intel.com>
---
 tools/sys_info.py | 551 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 551 insertions(+)
 create mode 100755 tools/sys_info.py

diff --git a/tools/sys_info.py b/tools/sys_info.py
new file mode 100755
index 0000000..5e09d12
--- /dev/null
+++ b/tools/sys_info.py
@@ -0,0 +1,551 @@
+#! /usr/bin/python
+#
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import os, sys
+import getopt
+import json
+from os.path import exists, abspath, dirname, basename
+
+version = "0.1.3"
+
+# Global lists and flags
+machine_readable = 0
+show_pci = False
+debug_flag = False
+coremaps_flag = False
+
+sys_info = {}
+coremaps = {}
+
+def proc_cpuinfo_path():
+    '''Return the cpu information from /proc'''
+    return "/proc/cpuinfo"
+
+def proc_sysinfo_path():
+    '''Return the system path string from /proc'''
+    return "/proc/sysinfo"
+
+def proc_meminfo_path():
+    '''Return the memory information path from /proc'''
+    return "/proc/meminfo"
+
+def sys_system_path():
+    '''Return the system path string from /sys'''
+    return "/sys/devices/system"
+
+def read_file(path, whole_file=False):
+    '''Read the first line of a file'''
+
+    if os.access(path, os.F_OK) == False:
+        print "Path (%s) Not found" % path
+        return ""
+
+    fd = open(path)
+    if whole_file == True:
+        lines = fd.readlines()
+    else:
+        line = fd.readline()
+    fd.close()
+
+    if whole_file == True:
+        return lines
+
+    return line
+
+def get_range(line):
+    '''Split a line and convert to low/high values'''
+
+    line = line.strip()
+
+    if '-' in line:
+        low, high = line.split("-")
+    elif ',' in line:
+        low, high = line.split(",")
+    else:
+        return [int(line)]
+
+    return [int(low), int(high)]
+
+def get_ranges(line):
+    '''Split a set of ranges into first low/high, second low/high value'''
+
+    line = line.strip()
+
+    first, second = line.split(',')
+
+    f = get_range(first)
+    s = get_range(second)
+
+    return [f, s]
+
+def get_low(line):
+    '''Return the low value in a range'''
+    range = get_range(line)
+    return int(range[0])
+
+def get_high(line):
+    '''Return the high value in a range'''
+    range = get_range(line)
+
+    if len(range) > 1:
+        return range[1]
+
+    return range[0]
+
+def get_value(line):
+    '''Convert a number into a integer value'''
+    return int(line)
+
+def cpu_path(name):
+    '''Return the cpu path string to a given file name'''
+    return "%s/cpu/%s" % (sys_system_path(), name)
+
+def topology_path(id, name):
+    '''Return the topology path string to a given file cpu id and file name'''
+    return "%s/cpu/cpu%d/topology/%s" % (sys_system_path(), id, name)
+
+def get_cpu_info(filename):
+    ''' Read the file using cpu_base_path/name '''
+    return read_file(cpu_path(filename))
+
+def get_topology_info(id, filename):
+    ''' Read the cpu_base_path/cpu(id)/topology/(name) file '''
+    return read_file(topology_path(id, filename))
+
+def cpulist_parse(info):
+    ''' '''
+    cpuset = []
+    for c in range(0, 255):
+        cpuset.append(0)
+
+    ranges = info.split(',')
+    for r in ranges:
+        if not '-' in r:
+            cpuset[int(r)] = 1
+        else:
+            low, high = get_range(r)
+            for c in range(low, high + 1):
+                cpuset[c] = 1
+
+    return cpuset
+
+def path_read_cpuset(fn, num):
+    ''' '''
+    info = get_topology_info(num, fn)
+    return cpulist_parse(info.strip())
+
+def set_count(arr):
+    cnt = 0
+    for c in arr:
+        cnt = cnt + c
+    return cnt
+
+def read_topology(ncpus, cpu):
+    global sys_info
+
+    path = topology_path(cpu, "thread_siblings_list")
+    if os.access(path, os.F_OK) == False:
+        print "Path (%s) Not found" % path
+        return ""
+
+    thread_siblings = path_read_cpuset("thread_siblings_list", cpu)
+    core_siblings = path_read_cpuset("core_siblings_list", cpu)
+
+    path = topology_path(cpu, "book_siblings_list")
+    if os.access(path, os.F_OK):
+        book_siblings = path_read_cpuset("book_siblings_list", cpu)
+    else:
+        book_siblings = []
+
+    if not 'nthreads' in sys_info:
+        nthreads = set_count(thread_siblings)
+        if nthreads == 0:
+            nthreads = 1
+        ncores = set_count(core_siblings)/nthreads
+        if ncores == 0:
+            ncores = 1
+        nsockets = ncpus / nthreads / ncores
+        if nsockets == 0:
+            nsockets = 1
+        nbooks = ncpus / nthreads / ncores / nsockets
+        if nbooks == 0:
+            nbooks = 1
+        nlcores = nbooks * nsockets * ncores * nthreads
+        sys_info['nthreads'] = nthreads
+        sys_info['ncores'] = ncores
+        sys_info['nsockets'] = nsockets
+        sys_info['nbooks'] = nbooks
+        sys_info['nlcores'] = nlcores
+
+def get_core_ids():
+    ''' Return the core ids and the lcores for each socket assigned
+    to the core id '''
+
+    core_ids = []
+
+    # Create cpu id to lcore id list core_ids[lcore] == core_id
+    # if the core_id does not exist in the list already
+    for c in range(0, sys_value('nlcores')):
+        id = get_value(get_topology_info(c, "core_id"))
+        if id not in core_ids:
+            core_ids.append(id)
+
+    return core_ids
+
+def get_coremaps():
+    ''' Return the core ids and the lcores for each socket assigned
+    to the core id '''
+    global sys_info
+
+    coremaps = {}
+
+    for c in range(0, sys_value('nlcores')):
+        id      = int(get_topology_info(c, "core_id").strip())
+        socket  = int(get_topology_info(c, "physical_package_id").strip())
+        ranges  = get_range(get_topology_info(c, "thread_siblings_list"))
+
+        if coremaps.has_key(id):
+            if not socket in coremaps[id]:
+                coremaps[id].update({socket: ranges})
+        else:
+            coremaps[id] = {socket: ranges}
+
+    return coremaps
+
+def get_model_name():
+    '''Parse up the CPU information into tables. The information
+    is taken from /proc/cpuinfo file. '''
+    model = "Unknown"
+
+    if os.access(proc_cpuinfo_path(), os.F_OK) == False:
+        return details
+
+    lines = read_file(proc_cpuinfo_path(), True)
+
+    for line in lines:
+        line = line.strip()
+        if len(line) != 0:
+            name, value = line.split(":", 1)
+            name = name.strip()
+            value = value.strip()
+            if 'model name' == name:
+                return value
+        else:
+            break
+
+    return model
+
+def parse_meminfo():
+    ''' Parse up the /proc/meminfo if available and return a dictionary. '''
+    details = {}
+
+    if os.access(proc_meminfo_path(), os.F_OK) == False:
+        return details;
+
+    lines = read_file(proc_meminfo_path(), True)
+
+    for line in lines:
+        if len(line.strip()) != 0:
+            name, value = line.split(":", 1)
+            details[name.strip()] = value.strip()
+
+    return details
+
+def sys_value(key):
+    '''Get a value from the System Info dictionary if available. '''
+    global sys_info
+
+    if key in sys_info:
+        return sys_info[key];
+
+    for core in sys_info:
+        if key in core:
+            return core[key]
+
+    return "Not Found"
+
+def mem_value(key):
+    '''Get a value from the Memory Info dictionary if available. '''
+
+    info = sys_info['memory']
+
+    if key in info:
+        return info[key]
+
+    return "Not Found"
+
+def get_ether_devices():
+    ''' Read the PCI ethernet list into a table '''
+
+    fd = os.popen("lspci | grep Ether", 'r')
+    lines = fd.readlines()
+    fd.close()
+
+    dict = {}
+    for line in lines:
+        pci, desc = line.rsplit(':',1)
+        pci_id, _ = pci.split(' ', 1)
+        if not 'Null' in desc:
+            dict[pci_id] = desc.strip();
+
+    return dict
+
+def format_cores(val):
+    '''Format a list of lcores into '[%3d,%3d,...]' '''
+    s = "["
+    for r in val:
+        s = s + "%3d," % r
+    s = s[:-1]
+    s = s + "]"
+    return s
+
+def print_core_ids(ids):
+    '''Return the string of a set of lcores for each id'''
+    s = ""
+    for i in ids:
+        s = s + format_cores(ids[i]) + "   "
+
+    return s
+
+def print_lcore_pairs():
+    ''' Print out the header line for the socket/lcore data'''
+
+    nsockets = sys_value('nsockets')
+
+    print "\nShowing mapping of lcores to core_ids and sockets:"
+    print " Core ID ",
+    for id in range(0, nsockets):
+        print "  Socket %d " % id,
+    print ""
+
+    print " -------",
+    for id in range(0, nsockets):
+        print "  ---------",
+    print ""
+
+    for id in sys_info['core_ids']:
+        vals = sys_info['coremaps']
+        print "   %3d     %s" % (id, print_core_ids(vals[id]))
+
+def usage():
+    '''Print usage information for the program'''
+    print("""
+Usage: %s [options]
+
+Show the lcores layout with core id and socket(s).
+
+Options:
+    --help or -h:
+        Display the usage information and quit
+
+    --long or -l:
+        Display the information in a machine readable long format.
+
+    --short or -s:
+        Display the information in a machine readable short format.
+
+    --pci or -p:
+        Display all of the Ethernet devices in the system using 'lspci'.
+
+    --version or -v:
+        Display the current version number of this script.
+
+    --debug or -d:
+        Output some debug information.
+
+    default:
+        Display the information in a human readable format.
+
+    """ % basename(sys.argv[0]))
+
+def parse_args():
+    '''Parse the command line arguments'''
+    global machine_readable
+    global show_pci
+    global debug_flag
+    global coremaps_flag
+    global args
+
+    if len(sys.argv) == 1:
+        return
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "hslpvdc",
+                   ["help", "short", "long", "pci", "version", "debug", "coremaps"])
+
+    except getopt.GetoptError as error:
+        print "** Error ", str(error)
+        usage()
+        sys.exit(1)
+
+    machine_readable = 0
+    for opt, arg in opts:
+        if opt == "--help" or opt == "-h":
+            usage()
+            sys.exit(0)
+        if opt == "--short" or opt == "-s":
+            machine_readable = 1
+        if opt == "--long" or opt == "-l":
+            machine_readable = 2
+        if opt == "--pci" or opt == "-p":
+            show_pci = True
+        if opt == "--debug" or opt == "-d":
+            debug_flag = True
+        if opt == "--coremaps" or opt == "-c":
+            coremaps_flag = True
+        if opt == "--version" or opt == "-v":
+            print "%s version %s" % (sys.argv[0], version)
+            sys.exit(0)
+
+def gather_information():
+    global sys_info
+
+    sys_info['memory'] = parse_meminfo()
+
+    sys_info.update({'model name': get_model_name()})
+
+    ncpus = get_high(get_cpu_info("present")) + 1
+    for cpu in range(0, ncpus):
+        read_topology(ncpus, cpu)
+
+    uname = os.uname()
+    sys_info.update({'sysname': uname[0]})
+    sys_info.update({'release': uname[2]})
+    sys_info.update({'version': uname[3]})
+    sys_info.update({'machine': uname[4]})
+
+    sys_info['core_ids'] = get_core_ids()
+    sys_info['coremaps'] = get_coremaps()
+
+    if show_pci:
+        info = get_ether_devices()
+        sys_info['pci'] = info
+    else:
+        sys_info['pci'] = {}
+
+    if debug_flag == True:
+        print "sys_info = ", json.dumps(sys_info, indent=4)
+
+def main():
+    '''program main function'''
+    global machine_readable
+    global sys_info
+
+    parse_args()
+
+    gather_information()
+
+    if machine_readable > 0:
+        json_details = {'system': {
+            'sysname':          sys_info['sysname'],
+            'version':          sys_info['version'],
+            'release':          sys_info['release'],
+            'machine':          sys_info['machine'],
+            }}
+
+        cpu_info = {'cpu': {
+            'model_name':       sys_value('model name'),
+            'nthreads':         sys_value('nthreads'),
+            'ncores':           sys_value('ncores'),
+            'nsockets':         sys_value('nsockets'),
+            'nbooks':           sys_value('nbooks'),
+            'nlcores':          sys_value('nlcores'),
+            'cores_ids':        sys_value('core_ids')}}
+
+        memory = {'memory': {
+            'total':        mem_value('MemTotal'),
+            'free':         mem_value('MemFree'),
+            'available':    mem_value('MemAvailable')}}
+        hugepages = {'hugepages': {
+            'total':        mem_value('HugePages_Total'),
+            'free':         mem_value('HugePages_Free'),
+            'reserved':     mem_value('HugePages_Rsvd'),
+            'surp':         mem_value('HugePages_Surp'),
+            'page_size':    mem_value('Hugepagesize')}}
+
+        json_details.update(cpu_info)
+        json_details.update(memory)
+        json_details.update(hugepages)
+        json_details.update({'coremaps': sys_value('coremaps')})
+        if show_pci:
+            json_details.update({'pci': sys_value('pci')})
+
+        if machine_readable == 2:
+            print json.dumps(json_details, sort_keys=False, indent=4)
+        else:
+            print json.dumps(json_details, sort_keys=False, separators=(', ', ':'))
+    else:
+        if len(sys_info) > 0:
+            print "System Information:"
+            print "   Model Name : %s" % sys_value('model name')
+            print "   sysname    : %s" % sys_value('sysname')
+            print "   release    : %s" % sys_value('release')
+            print "   version    : %s" % sys_value('version')
+            print "   machine    : %s" % sys_value('machine')
+            print ""
+
+            print "CPU Information:"
+            print "   nthreads   : %3d" % sys_value('nthreads')
+            print "   ncores     : %3d" % sys_value('ncores')
+            print "   nsockets   : %3d" % sys_value('nsockets')
+            print "   nbooks     : %3d" % sys_value('nbooks')
+            print "   nlcores    : %3d" % sys_value('nlcores')
+
+            print ""
+        if len(sys_info['memory']) > 0:
+            print "Memory:"
+            print "   Total    : ", mem_value('MemTotal')
+            print "   Free     : ", mem_value('MemFree')
+            print "   Available: ", mem_value('MemAvailable')
+            print ""
+            print "Huge Pages:"
+            print "   Total    : ", mem_value('HugePages_Total')
+            print "   Free     : ", mem_value('HugePages_Free')
+            print "   Reserved : ", mem_value('HugePages_Rsvd')
+            print "   Surp     : ", mem_value('HugePages_Surp')
+            print "   Page Size: ", mem_value('Hugepagesize')
+
+        if show_pci:
+            print "\nList of devices labeled as Ethernet on the PCI bus"
+            print "   PCI ID   Description"
+            info = sys_value('pci')
+            for p in info:
+                print "  %s   %s" % (p, info[p])
+
+        print_lcore_pairs()
+
+        vals = (sys_value('nlcores'), sys_value('nsockets'), sys_value('ncores'), sys_value('nthreads'))
+        print "\n%d lcores, %d socket(s), %d cores per socket, %d hyper-thread(s) per core" % vals
+
+if __name__ == "__main__":
+    main()
-- 
2.8.0.GIT

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [dpdk-dev] [PATCH] tools:new tool for system info CPU, memory and huge pages
  2016-05-13 15:43 [dpdk-dev] [PATCH] tools:new tool for system info CPU, memory and huge pages Keith Wiles
@ 2016-05-19 12:20 ` Hunt, David
  0 siblings, 0 replies; 2+ messages in thread
From: Hunt, David @ 2016-05-19 12:20 UTC (permalink / raw)
  To: Keith Wiles; +Cc: dev

Hi Keith.
    Works nicely on the few different machines I tried it on.
Regards,
Dave.

On 5/13/2016 4:43 PM, Keith Wiles wrote:
> The new tool uses /sys/devices instead of /proc directory, which
> does not exist on all systems. If the procfs is not available
> then memory and huge page information is skipped.
>
> The tool also can emit a json format in short or long form to
> allow for machine readable information.
>
> Here is the usage information:
>
> Usage: sys_info.py [options]
>
> Show the lcores layout with core id and socket(s).
>
> Options:
>      --help or -h:
>          Display the usage information and quit
>
>      --long or -l:
>          Display the information in a machine readable long format.
>
>      --short or -s:
>          Display the information in a machine readable short format.
>
>      --pci or -p:
>          Display all of the Ethernet devices in the system using 'lspci'.
>
>      --version or -v:
>          Display the current version number of this script.
>
>      --debug or -d:
>          Output some debug information.
>
>      default:
>          Display the information in a human readable format.
>
> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
> ---
>   tools/sys_info.py | 551 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 551 insertions(+)
>   create mode 100755 tools/sys_info.py
>
> diff --git a/tools/sys_info.py b/tools/sys_info.py
> new file mode 100755
> index 0000000..5e09d12
> --- /dev/null
> +++ b/tools/sys_info.py
> @@ -0,0 +1,551 @@
> +#! /usr/bin/python
> +#
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2016 Intel Corporation. All rights reserved.
> +#   All rights reserved.
> +#
> +#   Redistribution and use in source and binary forms, with or without
> +#   modification, are permitted provided that the following conditions
> +#   are met:
> +#
> +#     * Redistributions of source code must retain the above copyright
> +#       notice, this list of conditions and the following disclaimer.
> +#     * Redistributions in binary form must reproduce the above copyright
> +#       notice, this list of conditions and the following disclaimer in
> +#       the documentation and/or other materials provided with the
> +#       distribution.
> +#     * Neither the name of Intel Corporation nor the names of its
> +#       contributors may be used to endorse or promote products derived
> +#       from this software without specific prior written permission.
> +#
> +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +#
> +
> +import os, sys
> +import getopt
> +import json
> +from os.path import exists, abspath, dirname, basename
> +
> +version = "0.1.3"
> +
> +# Global lists and flags
> +machine_readable = 0
> +show_pci = False
> +debug_flag = False
> +coremaps_flag = False
> +
> +sys_info = {}
> +coremaps = {}
> +
> +def proc_cpuinfo_path():
> +    '''Return the cpu information from /proc'''
> +    return "/proc/cpuinfo"
> +
> +def proc_sysinfo_path():
> +    '''Return the system path string from /proc'''
> +    return "/proc/sysinfo"
> +
> +def proc_meminfo_path():
> +    '''Return the memory information path from /proc'''
> +    return "/proc/meminfo"
> +
> +def sys_system_path():
> +    '''Return the system path string from /sys'''
> +    return "/sys/devices/system"
> +
> +def read_file(path, whole_file=False):
> +    '''Read the first line of a file'''
> +
> +    if os.access(path, os.F_OK) == False:
> +        print "Path (%s) Not found" % path
> +        return ""
> +
> +    fd = open(path)
> +    if whole_file == True:
> +        lines = fd.readlines()
> +    else:
> +        line = fd.readline()
> +    fd.close()
> +
> +    if whole_file == True:
> +        return lines
> +
> +    return line
> +
> +def get_range(line):
> +    '''Split a line and convert to low/high values'''
> +
> +    line = line.strip()
> +
> +    if '-' in line:
> +        low, high = line.split("-")
> +    elif ',' in line:
> +        low, high = line.split(",")
> +    else:
> +        return [int(line)]
> +
> +    return [int(low), int(high)]
> +
> +def get_ranges(line):
> +    '''Split a set of ranges into first low/high, second low/high value'''
> +
> +    line = line.strip()
> +
> +    first, second = line.split(',')
> +
> +    f = get_range(first)
> +    s = get_range(second)
> +
> +    return [f, s]
> +
> +def get_low(line):
> +    '''Return the low value in a range'''
> +    range = get_range(line)
> +    return int(range[0])
> +
> +def get_high(line):
> +    '''Return the high value in a range'''
> +    range = get_range(line)
> +
> +    if len(range) > 1:
> +        return range[1]
> +
> +    return range[0]
> +
> +def get_value(line):
> +    '''Convert a number into a integer value'''
> +    return int(line)
> +
> +def cpu_path(name):
> +    '''Return the cpu path string to a given file name'''
> +    return "%s/cpu/%s" % (sys_system_path(), name)
> +
> +def topology_path(id, name):
> +    '''Return the topology path string to a given file cpu id and file name'''
> +    return "%s/cpu/cpu%d/topology/%s" % (sys_system_path(), id, name)
> +
> +def get_cpu_info(filename):
> +    ''' Read the file using cpu_base_path/name '''
> +    return read_file(cpu_path(filename))
> +
> +def get_topology_info(id, filename):
> +    ''' Read the cpu_base_path/cpu(id)/topology/(name) file '''
> +    return read_file(topology_path(id, filename))
> +
> +def cpulist_parse(info):
> +    ''' '''
> +    cpuset = []
> +    for c in range(0, 255):
> +        cpuset.append(0)
> +
> +    ranges = info.split(',')
> +    for r in ranges:
> +        if not '-' in r:
> +            cpuset[int(r)] = 1
> +        else:
> +            low, high = get_range(r)
> +            for c in range(low, high + 1):
> +                cpuset[c] = 1
> +
> +    return cpuset
> +
> +def path_read_cpuset(fn, num):
> +    ''' '''
> +    info = get_topology_info(num, fn)
> +    return cpulist_parse(info.strip())
> +
> +def set_count(arr):
> +    cnt = 0
> +    for c in arr:
> +        cnt = cnt + c
> +    return cnt
> +
> +def read_topology(ncpus, cpu):
> +    global sys_info
> +
> +    path = topology_path(cpu, "thread_siblings_list")
> +    if os.access(path, os.F_OK) == False:
> +        print "Path (%s) Not found" % path
> +        return ""
> +
> +    thread_siblings = path_read_cpuset("thread_siblings_list", cpu)
> +    core_siblings = path_read_cpuset("core_siblings_list", cpu)
> +
> +    path = topology_path(cpu, "book_siblings_list")
> +    if os.access(path, os.F_OK):
> +        book_siblings = path_read_cpuset("book_siblings_list", cpu)
> +    else:
> +        book_siblings = []
> +
> +    if not 'nthreads' in sys_info:
> +        nthreads = set_count(thread_siblings)
> +        if nthreads == 0:
> +            nthreads = 1
> +        ncores = set_count(core_siblings)/nthreads
> +        if ncores == 0:
> +            ncores = 1
> +        nsockets = ncpus / nthreads / ncores
> +        if nsockets == 0:
> +            nsockets = 1
> +        nbooks = ncpus / nthreads / ncores / nsockets
> +        if nbooks == 0:
> +            nbooks = 1
> +        nlcores = nbooks * nsockets * ncores * nthreads
> +        sys_info['nthreads'] = nthreads
> +        sys_info['ncores'] = ncores
> +        sys_info['nsockets'] = nsockets
> +        sys_info['nbooks'] = nbooks
> +        sys_info['nlcores'] = nlcores
> +
> +def get_core_ids():
> +    ''' Return the core ids and the lcores for each socket assigned
> +    to the core id '''
> +
> +    core_ids = []
> +
> +    # Create cpu id to lcore id list core_ids[lcore] == core_id
> +    # if the core_id does not exist in the list already
> +    for c in range(0, sys_value('nlcores')):
> +        id = get_value(get_topology_info(c, "core_id"))
> +        if id not in core_ids:
> +            core_ids.append(id)
> +
> +    return core_ids
> +
> +def get_coremaps():
> +    ''' Return the core ids and the lcores for each socket assigned
> +    to the core id '''
> +    global sys_info
> +
> +    coremaps = {}
> +
> +    for c in range(0, sys_value('nlcores')):
> +        id      = int(get_topology_info(c, "core_id").strip())
> +        socket  = int(get_topology_info(c, "physical_package_id").strip())
> +        ranges  = get_range(get_topology_info(c, "thread_siblings_list"))
> +
> +        if coremaps.has_key(id):
> +            if not socket in coremaps[id]:
> +                coremaps[id].update({socket: ranges})
> +        else:
> +            coremaps[id] = {socket: ranges}
> +
> +    return coremaps
> +
> +def get_model_name():
> +    '''Parse up the CPU information into tables. The information
> +    is taken from /proc/cpuinfo file. '''
> +    model = "Unknown"
> +
> +    if os.access(proc_cpuinfo_path(), os.F_OK) == False:
> +        return details
> +
> +    lines = read_file(proc_cpuinfo_path(), True)
> +
> +    for line in lines:
> +        line = line.strip()
> +        if len(line) != 0:
> +            name, value = line.split(":", 1)
> +            name = name.strip()
> +            value = value.strip()
> +            if 'model name' == name:
> +                return value
> +        else:
> +            break
> +
> +    return model
> +
> +def parse_meminfo():
> +    ''' Parse up the /proc/meminfo if available and return a dictionary. '''
> +    details = {}
> +
> +    if os.access(proc_meminfo_path(), os.F_OK) == False:
> +        return details;
> +
> +    lines = read_file(proc_meminfo_path(), True)
> +
> +    for line in lines:
> +        if len(line.strip()) != 0:
> +            name, value = line.split(":", 1)
> +            details[name.strip()] = value.strip()
> +
> +    return details
> +
> +def sys_value(key):
> +    '''Get a value from the System Info dictionary if available. '''
> +    global sys_info
> +
> +    if key in sys_info:
> +        return sys_info[key];
> +
> +    for core in sys_info:
> +        if key in core:
> +            return core[key]
> +
> +    return "Not Found"
> +
> +def mem_value(key):
> +    '''Get a value from the Memory Info dictionary if available. '''
> +
> +    info = sys_info['memory']
> +
> +    if key in info:
> +        return info[key]
> +
> +    return "Not Found"
> +
> +def get_ether_devices():
> +    ''' Read the PCI ethernet list into a table '''
> +
> +    fd = os.popen("lspci | grep Ether", 'r')
> +    lines = fd.readlines()
> +    fd.close()
> +
> +    dict = {}
> +    for line in lines:
> +        pci, desc = line.rsplit(':',1)
> +        pci_id, _ = pci.split(' ', 1)
> +        if not 'Null' in desc:
> +            dict[pci_id] = desc.strip();
> +
> +    return dict
> +
> +def format_cores(val):
> +    '''Format a list of lcores into '[%3d,%3d,...]' '''
> +    s = "["
> +    for r in val:
> +        s = s + "%3d," % r
> +    s = s[:-1]
> +    s = s + "]"
> +    return s
> +
> +def print_core_ids(ids):
> +    '''Return the string of a set of lcores for each id'''
> +    s = ""
> +    for i in ids:
> +        s = s + format_cores(ids[i]) + "   "
> +
> +    return s
> +
> +def print_lcore_pairs():
> +    ''' Print out the header line for the socket/lcore data'''
> +
> +    nsockets = sys_value('nsockets')
> +
> +    print "\nShowing mapping of lcores to core_ids and sockets:"
> +    print " Core ID ",
> +    for id in range(0, nsockets):
> +        print "  Socket %d " % id,
> +    print ""
> +
> +    print " -------",
> +    for id in range(0, nsockets):
> +        print "  ---------",
> +    print ""
> +
> +    for id in sys_info['core_ids']:
> +        vals = sys_info['coremaps']
> +        print "   %3d     %s" % (id, print_core_ids(vals[id]))
> +
> +def usage():
> +    '''Print usage information for the program'''
> +    print("""
> +Usage: %s [options]
> +
> +Show the lcores layout with core id and socket(s).
> +
> +Options:
> +    --help or -h:
> +        Display the usage information and quit
> +
> +    --long or -l:
> +        Display the information in a machine readable long format.
> +
> +    --short or -s:
> +        Display the information in a machine readable short format.
> +
> +    --pci or -p:
> +        Display all of the Ethernet devices in the system using 'lspci'.
> +
> +    --version or -v:
> +        Display the current version number of this script.
> +
> +    --debug or -d:
> +        Output some debug information.
> +
> +    default:
> +        Display the information in a human readable format.
> +
> +    """ % basename(sys.argv[0]))
> +
> +def parse_args():
> +    '''Parse the command line arguments'''
> +    global machine_readable
> +    global show_pci
> +    global debug_flag
> +    global coremaps_flag
> +    global args
> +
> +    if len(sys.argv) == 1:
> +        return
> +    try:
> +        opts, args = getopt.getopt(sys.argv[1:], "hslpvdc",
> +                   ["help", "short", "long", "pci", "version", "debug", "coremaps"])
> +
> +    except getopt.GetoptError as error:
> +        print "** Error ", str(error)
> +        usage()
> +        sys.exit(1)
> +
> +    machine_readable = 0
> +    for opt, arg in opts:
> +        if opt == "--help" or opt == "-h":
> +            usage()
> +            sys.exit(0)
> +        if opt == "--short" or opt == "-s":
> +            machine_readable = 1
> +        if opt == "--long" or opt == "-l":
> +            machine_readable = 2
> +        if opt == "--pci" or opt == "-p":
> +            show_pci = True
> +        if opt == "--debug" or opt == "-d":
> +            debug_flag = True
> +        if opt == "--coremaps" or opt == "-c":
> +            coremaps_flag = True
> +        if opt == "--version" or opt == "-v":
> +            print "%s version %s" % (sys.argv[0], version)
> +            sys.exit(0)
> +
> +def gather_information():
> +    global sys_info
> +
> +    sys_info['memory'] = parse_meminfo()
> +
> +    sys_info.update({'model name': get_model_name()})
> +
> +    ncpus = get_high(get_cpu_info("present")) + 1
> +    for cpu in range(0, ncpus):
> +        read_topology(ncpus, cpu)
> +
> +    uname = os.uname()
> +    sys_info.update({'sysname': uname[0]})
> +    sys_info.update({'release': uname[2]})
> +    sys_info.update({'version': uname[3]})
> +    sys_info.update({'machine': uname[4]})
> +
> +    sys_info['core_ids'] = get_core_ids()
> +    sys_info['coremaps'] = get_coremaps()
> +
> +    if show_pci:
> +        info = get_ether_devices()
> +        sys_info['pci'] = info
> +    else:
> +        sys_info['pci'] = {}
> +
> +    if debug_flag == True:
> +        print "sys_info = ", json.dumps(sys_info, indent=4)
> +
> +def main():
> +    '''program main function'''
> +    global machine_readable
> +    global sys_info
> +
> +    parse_args()
> +
> +    gather_information()
> +
> +    if machine_readable > 0:
> +        json_details = {'system': {
> +            'sysname':          sys_info['sysname'],
> +            'version':          sys_info['version'],
> +            'release':          sys_info['release'],
> +            'machine':          sys_info['machine'],
> +            }}
> +
> +        cpu_info = {'cpu': {
> +            'model_name':       sys_value('model name'),
> +            'nthreads':         sys_value('nthreads'),
> +            'ncores':           sys_value('ncores'),
> +            'nsockets':         sys_value('nsockets'),
> +            'nbooks':           sys_value('nbooks'),
> +            'nlcores':          sys_value('nlcores'),
> +            'cores_ids':        sys_value('core_ids')}}
> +
> +        memory = {'memory': {
> +            'total':        mem_value('MemTotal'),
> +            'free':         mem_value('MemFree'),
> +            'available':    mem_value('MemAvailable')}}
> +        hugepages = {'hugepages': {
> +            'total':        mem_value('HugePages_Total'),
> +            'free':         mem_value('HugePages_Free'),
> +            'reserved':     mem_value('HugePages_Rsvd'),
> +            'surp':         mem_value('HugePages_Surp'),
> +            'page_size':    mem_value('Hugepagesize')}}
> +
> +        json_details.update(cpu_info)
> +        json_details.update(memory)
> +        json_details.update(hugepages)
> +        json_details.update({'coremaps': sys_value('coremaps')})
> +        if show_pci:
> +            json_details.update({'pci': sys_value('pci')})
> +
> +        if machine_readable == 2:
> +            print json.dumps(json_details, sort_keys=False, indent=4)
> +        else:
> +            print json.dumps(json_details, sort_keys=False, separators=(', ', ':'))
> +    else:
> +        if len(sys_info) > 0:
> +            print "System Information:"
> +            print "   Model Name : %s" % sys_value('model name')
> +            print "   sysname    : %s" % sys_value('sysname')
> +            print "   release    : %s" % sys_value('release')
> +            print "   version    : %s" % sys_value('version')
> +            print "   machine    : %s" % sys_value('machine')
> +            print ""
> +
> +            print "CPU Information:"
> +            print "   nthreads   : %3d" % sys_value('nthreads')
> +            print "   ncores     : %3d" % sys_value('ncores')
> +            print "   nsockets   : %3d" % sys_value('nsockets')
> +            print "   nbooks     : %3d" % sys_value('nbooks')
> +            print "   nlcores    : %3d" % sys_value('nlcores')
> +
> +            print ""
> +        if len(sys_info['memory']) > 0:
> +            print "Memory:"
> +            print "   Total    : ", mem_value('MemTotal')
> +            print "   Free     : ", mem_value('MemFree')
> +            print "   Available: ", mem_value('MemAvailable')
> +            print ""
> +            print "Huge Pages:"
> +            print "   Total    : ", mem_value('HugePages_Total')
> +            print "   Free     : ", mem_value('HugePages_Free')
> +            print "   Reserved : ", mem_value('HugePages_Rsvd')
> +            print "   Surp     : ", mem_value('HugePages_Surp')
> +            print "   Page Size: ", mem_value('Hugepagesize')
> +
> +        if show_pci:
> +            print "\nList of devices labeled as Ethernet on the PCI bus"
> +            print "   PCI ID   Description"
> +            info = sys_value('pci')
> +            for p in info:
> +                print "  %s   %s" % (p, info[p])
> +
> +        print_lcore_pairs()
> +
> +        vals = (sys_value('nlcores'), sys_value('nsockets'), sys_value('ncores'), sys_value('nthreads'))
> +        print "\n%d lcores, %d socket(s), %d cores per socket, %d hyper-thread(s) per core" % vals
> +
> +if __name__ == "__main__":
> +    main()

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-05-19 12:20 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-13 15:43 [dpdk-dev] [PATCH] tools:new tool for system info CPU, memory and huge pages Keith Wiles
2016-05-19 12:20 ` Hunt, David

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).