opencompute-developers team mailing list archive
-
opencompute-developers team
-
Mailing list archive
-
Message #00230
[Merge] lp:~nelson-chu/opencompute/add-ocp-cpu-memory-job into lp:opencompute/checkbox
Nelson Chu has proposed merging lp:~nelson-chu/opencompute/add-ocp-cpu-memory-job into lp:opencompute/checkbox.
Requested reviews:
Jeff Lane (bladernr)
Nelson Chu (nelson-chu)
For more details, see:
https://code.launchpad.net/~nelson-chu/opencompute/add-ocp-cpu-memory-job/+merge/205884
Scripts and annotations have been modified.
--
https://code.launchpad.net/~nelson-chu/opencompute/add-ocp-cpu-memory-job/+merge/205884
Your team Open Compute Developers is subscribed to branch lp:opencompute/checkbox.
=== added file 'data/whitelists/opencompute-certify-local.whitelist'
--- data/whitelists/opencompute-certify-local.whitelist 1970-01-01 00:00:00 +0000
+++ data/whitelists/opencompute-certify-local.whitelist 2014-02-12 02:56:04 +0000
@@ -0,0 +1,44 @@
+# Resource Jobs
+block_device
+cdimage
+cpuinfo
+device
+dmi
+dpkg
+efi
+environment
+gconf
+lsb
+meminfo
+module
+optical_drive
+package
+sleep
+uname
+#Info attachment jobs
+__info__
+cpuinfo_attachment
+dmesg_attachment
+dmi_attachment
+dmidecode_attachment
+efi_attachment
+lspci_attachment
+lshw_attachment
+mcelog_attachment
+meminfo_attachment
+modprobe_attachment
+modules_attachment
+sysctl_attachment
+sysfs_attachment
+udev_attachment
+lsmod_attachment
+acpi_sleep_attachment
+info/hdparm
+info/hdparm_.*.txt
+installer_debug.gz
+info/disk_partitions
+# Actual test cases
+__TC-001-0001-CPU_Memory__
+TC-001-0001-001-CPU_Information
+TC-001-0001-002-Processor_Topology
+TC-001-0001-003-Memory_Information
=== renamed file 'data/whitelists/opencompute-certify-local.whitelist' => 'data/whitelists/opencompute-certify-local.whitelist.moved'
=== added file 'jobs/TC-001-0001-CPU_Memory.txt.in'
--- jobs/TC-001-0001-CPU_Memory.txt.in 1970-01-01 00:00:00 +0000
+++ jobs/TC-001-0001-CPU_Memory.txt.in 2014-02-12 02:56:04 +0000
@@ -0,0 +1,31 @@
+plugin: shell
+name: TC-001-0001-001-CPU_Information
+requires: package.name == 'lshw'
+user: root
+command: cpu_info -p Xeon -f E5
+description:
+ 1. Use lshw command to gather CPU information.
+ 2. The program will output CPU model and L1, L2, L3 cache size.
+ 3. Criteria: CPU model must be Intel Xeon processor E5-2600 product family and L3 cache size must be up to 20MB.
+
+plugin: shell
+name: TC-001-0001-002-Processor_Topology
+command: processor_topology
+description:
+ 1. This test checks CPU topology for accuracy.
+ 2. Use lscpu command to gather CPU information.
+ 3. The program will output the total number of CPUs, the number of threads per core, the number of cores per socket, and the number of sockets.
+ 4. Criteria: It should be 8-12 cores per CPU and 2 threads per core.
+
+plugin: shell
+name: TC-001-0001-003-Memory_Information
+requires: package.name == 'lshw'
+user: root
+command: memory_info
+description:
+ 1. Use lshw command to gather memory information.
+ 2. Testing prerequisites:
+ 4 channels DDR3 registered memory interface on each processor 0 and processor 1.
+ 2 DDR3 slots per channel per processor. (total of 16 DIMMs on the motherboard)
+ 3. The program will output memory module, vendor, size and slot.
+ 4. Criteria: Total of 16 DIMMs on the motherboard.
=== modified file 'jobs/local.txt.in'
--- jobs/local.txt.in 2014-02-11 12:16:41 +0000
+++ jobs/local.txt.in 2014-02-12 02:56:04 +0000
@@ -109,6 +109,7 @@
command:
shopt -s extglob
cat $CHECKBOX_SHARE/jobs/sniff.txt?(.in)
+<<<<<<< TREE
name: __TC-001-0002-Platform_Controller_Hub__
plugin: local
@@ -116,3 +117,12 @@
command:
shopt -s extglob
cat $CHECKBOX_SHARE/jobs/TC-001-0002-Platform_Controller_Hub.txt?(.in)
+=======
+
+name: __TC-001-0001-CPU_Memory__
+plugin: local
+_description: Verify CPU and memory
+command:
+ shopt -s extglob
+ cat $CHECKBOX_SHARE/jobs/TC-001-0001-CPU_Memory.txt?(.in)
+>>>>>>> MERGE-SOURCE
=== added file 'scripts/cpu_info'
--- scripts/cpu_info 1970-01-01 00:00:00 +0000
+++ scripts/cpu_info 2014-02-12 02:56:04 +0000
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+"""
+Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications
+Industrial Technology Research Institute
+
+cpu_info
+ Use lshw command to gather CPU information.
+ The program will output CPU model and L1, L2, L3 cache size.
+ Criteria: CPU model and product family must match user's input
+ and L3 cache should be larger than 20MB.
+
+Authors
+ Nelson Chu <Nelson.Chu@xxxxxxxxxxx>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 3,
+as published by the Free Software Foundation.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import os
+import re
+import sys
+import xml.etree.ElementTree as ET
+from subprocess import check_output
+from argparse import ArgumentParser, RawTextHelpFormatter
+
+def run(product, family):
+ command = "lshw -xml"
+ with open(os.devnull, 'w') as NULL:
+ hwinfo_xml = check_output(command, stderr=NULL, shell=True)
+ root = ET.fromstring(hwinfo_xml)
+
+ # Parse lshw XML for gathering processor information.
+ processor = root.findall(".//product/..[@class='processor']")
+
+ if not processor:
+ print("Fail: Cannot parse any processor information.")
+ return 10
+
+ for cpu in processor:
+ if cpu.find('product') is None:
+ print("Fail: Cannot find processor product.")
+ return 20
+ print(cpu.find('product').text)
+ match = re.search(product + '.*' + family, cpu.find('product').text)
+ if not match:
+ print("Fail: Cannot match CPU %s %s family." %(product, family))
+ return 25
+
+ cache_list = cpu.findall(".//size/..[@class='memory']")
+ if not cache_list:
+ print("Fail: Cannot find any CPU cache.")
+ return 30
+
+ for cache in cache_list:
+ if cache.find('size') is None or cache.find('slot') is None:
+ print("Fail: Cannot access Last Level Cache (LLC).")
+ return 40
+
+ cache_size = int(cache.find('size').text) / 1024
+ if cache_size > 1024:
+ cache_size = cache_size / 1024
+ print(('%s %d MB') %(cache.find('slot').text, cache_size))
+ if re.search('L3', cache.find('slot').text):
+ if cache_size < 20:
+ print('Fail: L3 cache size less than 20MB.')
+ return 50
+ else:
+ print(('%s %d KB') %(cache.find('slot').text, cache_size))
+
+ return 0
+
+def main():
+ parser = ArgumentParser(formatter_class=RawTextHelpFormatter)
+
+ parser.add_argument('-p', '--product', type=str, required=True,
+ help=("The CPU product name. [Example: Xeon]"))
+ parser.add_argument('-f', '--family', type=str, required=True,
+ help=("Processor family. [Example: E5]"))
+
+ args = parser.parse_args()
+
+ product = args.product.title()
+ family = args.family.title()
+ return run(product, family)
+
+if __name__ == '__main__':
+ sys.exit(main())
=== added file 'scripts/memory_info'
--- scripts/memory_info 1970-01-01 00:00:00 +0000
+++ scripts/memory_info 2014-02-12 02:56:04 +0000
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+"""
+Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications
+Industrial Technology Research Institute
+
+memory_info
+ 1. Use lshw command to gather memory information.
+ 2. Testing prerequisites:
+ 4 channels DDR3 registered memory interface on each processor 0
+ and processor 1.
+ 2 DDR3 slots per channel per processor. (total of 16 DIMMs
+ on the motherboard)
+ 3. The program will output memory module, vendor, size and slot.
+ 4. Criteria: Total of 16 DIMMs on the motherboard.
+
+Authors
+ Nelson Chu <Nelson.Chu@xxxxxxxxxxx>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 3,
+as published by the Free Software Foundation.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import sys
+import xml.etree.ElementTree as ET
+from subprocess import Popen, PIPE
+
+def main():
+ attribute = ['description', 'vendor', 'slot', 'size']
+ command = 'lshw -xml'
+ hwinfo_xml = Popen(command, stdout=PIPE, stderr=PIPE,
+ shell=True).communicate()[0]
+ root = ET.fromstring(hwinfo_xml)
+
+ # Parse lshw XML for gathering memory information.
+ memory_list = root.findall(".//clock/..[@class='memory']")
+
+ if not memory_list:
+ print("Fail: Cannot parse any memory information.")
+ return 10
+
+ count = 0
+ for dimm in memory_list:
+ count = count +1
+ for attr in attribute:
+ if dimm.find(attr) is None:
+ print(("Fail: Cannot find memory %s") %attr)
+ return 20
+
+ memory_size = int(dimm.find('size').text) / (1024**3)
+ for attr in attribute:
+ if attr == 'description':
+ print('%s' %(dimm.find(attr).text), end=" ")
+ continue
+ elif attr == 'size':
+ print('%s=%dGB.' %(attr, memory_size))
+ continue
+ print('%s=%s' %(attr, dimm.find(attr).text), end=" ")
+
+ print("Total number of DIMMs is %s." %(count))
+ if count != 16:
+ print("Fail: Memory DIMM number is not meet the requirement.")
+ return 30
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
=== added file 'scripts/processor_topology'
--- scripts/processor_topology 1970-01-01 00:00:00 +0000
+++ scripts/processor_topology 2014-02-12 02:56:04 +0000
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+'''
+cpu_topology
+Written by Jeffrey Lane <jeffrey.lane@xxxxxxxxxxxxx>
+'''
+import sys
+import os
+from subprocess import check_output
+
+class proc_cpuinfo():
+ '''
+ Class to get and handle information from /proc/cpuinfo
+ Creates a dictionary of data gleaned from that file.
+ '''
+ def __init__(self):
+ self.cpuinfo = {}
+ cpu_fh = open('/proc/cpuinfo', 'r')
+ try:
+ temp = cpu_fh.readlines()
+ finally:
+ cpu_fh.close()
+
+ for i in temp:
+ if i.startswith('processor'):
+ key = 'cpu' + (i.split(':')[1].strip())
+ self.cpuinfo[key] = {'core_id':'', 'physical_package_id':''}
+ elif i.startswith('core id'):
+ self.cpuinfo[key].update({'core_id': i.split(':')[1].strip()})
+ elif i.startswith('physical id'):
+ self.cpuinfo[key].update({'physical_package_id':
+ i.split(':')[1].strip()})
+ else:
+ continue
+
+
+class sysfs_cpu():
+ '''
+ Class to get and handle information from sysfs as relates to CPU topology
+ Creates an informational class to present information on various CPUs
+ '''
+
+ def __init__(self, proc):
+ self.syscpu = {}
+ self.path = '/sys/devices/system/cpu/' + proc + '/topology'
+ items = ['core_id', 'physical_package_id']
+ for i in items:
+ syscpu_fh = open(os.path.join(self.path, i), 'r')
+ try:
+ self.syscpu[i] = syscpu_fh.readline().strip()
+ finally:
+ syscpu_fh.close()
+
+
+def compare(proc_cpu, sys_cpu):
+ cpu_map = {}
+ '''
+ If there is only 1 CPU the test don't look for core_id
+ and physical_package_id because those information are absent in
+ /proc/cpuinfo on singlecore system
+ '''
+ for key in proc_cpu.keys():
+ if 'cpu1' not in proc_cpu:
+ cpu_map[key] = True
+ else:
+ for subkey in proc_cpu[key].keys():
+ if proc_cpu[key][subkey] == sys_cpu[key][subkey]:
+ cpu_map[key] = True
+ else:
+ cpu_map[key] = False
+ return cpu_map
+
+
+def main():
+ cpuinfo = proc_cpuinfo()
+ sys_cpu = {}
+ keys = cpuinfo.cpuinfo.keys()
+ for k in keys:
+ sys_cpu[k] = sysfs_cpu(k).syscpu
+ cpu_map = compare(cpuinfo.cpuinfo, sys_cpu)
+ if False in cpu_map.values() or len(cpu_map) < 1:
+ print("FAIL: CPU Topology is incorrect", file=sys.stderr)
+ print("-" * 52, file=sys.stderr)
+ print("{0}{1}".format("/proc/cpuinfo".center(30), "sysfs".center(25)),
+ file=sys.stderr)
+ print("{0}{1}{2}{3}{1}{2}".format(
+ "CPU".center(6),
+ "Physical ID".center(13),
+ "Core ID".center(9),
+ "|".center(3)), file=sys.stderr)
+ for key in sorted(sys_cpu.keys()):
+ print("{0}{1}{2}{3}{4}{5}".format(
+ key.center(6),
+ cpuinfo.cpuinfo[key]['physical_package_id'].center(13),
+ cpuinfo.cpuinfo[key]['core_id'].center(9),
+ "|".center(3),
+ sys_cpu[key]['physical_package_id'].center(13),
+ sys_cpu[key]['core_id'].center(9)), file=sys.stderr)
+ return 1
+ else:
+ # Use lscpu command to gather CPU information.
+ # Output the total number of CPUs, the number of threads per core,
+ # the number of cores per socket, and the number of sockets.
+ # Criteria: It must be 8-12 cores per CPU and 2 threads per core.
+ # Revised by Nelson Chu <nelson.chu@xxxxxxxxxxx>
+ command = 'lscpu'
+ return_code = 0
+
+ with open(os.devnull, "w") as NULL:
+ cpu_info = check_output(command, stderr=NULL, shell=True)
+
+ cpu_info = cpu_info.decode('utf-8')
+
+ for cpu in cpu_info.split('\n'):
+ if cpu.startswith("CPU(s)"):
+ print(cpu)
+ if cpu.startswith("Thread(s) per core"):
+ print(cpu)
+ if cpu.startswith("Core(s) per socket"):
+ cores = int(cpu.split(":")[1])
+ print(cpu)
+ # It should be 8-12 cores per CPU.
+ if cores < 8 or cores > 12:
+ return_code = 1
+ if cpu.startswith("Socket(s)"):
+ print(cpu)
+
+ return return_code
+
+if __name__ == '__main__':
+ sys.exit(main())
Follow ups