Merge lp:~nelson-chu/opencompute/add-ocp-cpu-memory-job into lp:opencompute/checkbox

Proposed by Nelson Chu
Status: Superseded
Proposed branch: lp:~nelson-chu/opencompute/add-ocp-cpu-memory-job
Merge into: lp:opencompute/checkbox
Diff against target: 418 lines (+386/-0)
6 files modified
data/whitelists/opencompute-certify-local.whitelist (+44/-0)
jobs/TC-001-0001-CPU_Memory.txt.in (+31/-0)
jobs/local.txt.in (+7/-0)
scripts/cpu_info (+97/-0)
scripts/memory_info (+77/-0)
scripts/processor_topology (+130/-0)
To merge this branch: bzr merge lp:~nelson-chu/opencompute/add-ocp-cpu-memory-job
Reviewer Review Type Date Requested Status
Nelson Chu Needs Resubmitting
Jeff Lane  Needs Fixing
Review via email: mp+196651@code.launchpad.net

This proposal has been superseded by a proposal from 2014-02-12.

To post a comment you must log in.
Revision history for this message
Jeff Lane  (bladernr) wrote :
Download full text (4.6 KiB)

Hi Nelson,

Thank you for breaking this into smaller pieces... it makes review a LOT easier. Now, there are some things that need fixing.

I'll take them one file at a time:
data/whitelists/opencompute-certify-local.whitelist looks fine.

jobs/TC-001-0001-CPU_Memory.txt.in:
1: any job that calls a script that needs root permissions to run must include the 'user: root' definition. See the file 'jobs/cpu.txt.in' for some examples where this is necessary. When I run the script cpu_info without root, the cache data is not returned and the test will fail. So this job needs 'user:root'
2: TC-001-0001-003-Memory_Information also needs 'user: root' added to properly run.

jobs/local.txt.in
1: The word "Verified" should be "Verify" in the description field.

scripts/cpu_info:
1: When I manually run the cpu_info script for the test TC-001-0001-001-CPU_information with and without root permissions, I get the following different outputs:
bladernr@klaatu:~/development/ocp-nelson-memory-cpu-test$ ./scripts/cpu_infoIntel(R) Core(TM) i7 CPU Q 720 @ 1.60GHz
Can not found any CPU cache.
bladernr@klaatu:~/development/ocp-nelson-memory-cpu-test$ echo $?
30
bladernr@klaatu:~/development/ocp-nelson-memory-cpu-test$ sudo ./scripts/cpu_info
Intel(R) Core(TM) i7 CPU Q 720 @ 1.60GHz
L1 Cache 32 KB
L2 Cache 256 KB
L3 Cache 6 MB
L3 cache size less than 20MB.
bladernr@klaatu:~/development/ocp-nelson-memory-cpu-test$ echo $?
50

I don't have a system that meets the test criteria, so it will always fail for me. First, the explanation for failure should be more explicit. Example: 'FAIL: Can not find any CPU cache.' for the first example. This is more important in the second example where 'L3 cache size less than 20MB' looks like part of the lshw output. It would be better more explicitly stated as 'FAIL: L3 cache size less than 20MB.'

2: You don't need all those explicit error codes. Checkbox only knows and stores 0 and Not 0 exit codes. A 0 exit code indicates a test passed. A non-zero exit code indicates a failure. Checkbox does not store the actual exit codes. This is not necessarily something you need to change, but you DO need to be aware of the behaviour in case a script behaves differently than expected when you run it via checkbox.

3: The description and spec for this test says: "CPU model should belong to Intel Xeon processor E5-2600 family..." but your test does not fail on non-Xeon processors. For example, when I comment out the error code return for my cache limit on my laptop, I get this output:
bladernr@klaatu:~/development/ocp-nelson-memory-cpu-test$ sudo ./scripts/cpu_info; echo $?
Intel(R) Core(TM) i7 CPU Q 720 @ 1.60GHz
L1 Cache 32 KB
L2 Cache 256 KB
L3 Cache 6 MB
L3 cache size less than 20MB.
0

but my laptop should clearly fail the test case since it's not up to OCP spec.

4: The output needs to be cleaned up a bit. Sorry, I know English is a second language for you, so I'll try to help as much as I can.
    "Can not parser" should be "Can not parse"
    "Can not found" should be "Can not find"
    "# Parser lshw XML for gather" should be "# Parse lshw XML for gathering"

scripts/memory_info:
1: Needs to be run as ...

Read more...

review: Needs Fixing
Revision history for this message
Nelson Chu (nelson-chu) wrote :

OK, Thank you for your suggestion.
I will revise it accordingly.

Revision history for this message
Nelson Chu (nelson-chu) wrote :

Hi Jeff,

I have modified scripts. Please help me review them.
Any suggestion will be appreciated.

Thanks,
Nelson

review: Needs Resubmitting
2169. By Nelson Chu

Merges Nelson Chu's PCH tests with a couple minor typo corrections in the scripts.

2170. By Nelson Chu

Merge add-ocp-cpu-memory-job to lp:opencompute/checkbox and fixed some conflicts

2171. By Nelson Chu

Modify cpu_info and memory_info scripts. Revise debian/changelog file.

2172. By Nelson Chu

debian/changelog file and memory_info script

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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-07 09:50:29 +0000
@@ -0,0 +1,44 @@
1# Resource Jobs
2block_device
3cdimage
4cpuinfo
5device
6dmi
7dpkg
8efi
9environment
10gconf
11lsb
12meminfo
13module
14optical_drive
15package
16sleep
17uname
18#Info attachment jobs
19__info__
20cpuinfo_attachment
21dmesg_attachment
22dmi_attachment
23dmidecode_attachment
24efi_attachment
25lspci_attachment
26lshw_attachment
27mcelog_attachment
28meminfo_attachment
29modprobe_attachment
30modules_attachment
31sysctl_attachment
32sysfs_attachment
33udev_attachment
34lsmod_attachment
35acpi_sleep_attachment
36info/hdparm
37info/hdparm_.*.txt
38installer_debug.gz
39info/disk_partitions
40# Actual test cases
41__TC-001-0001-CPU_Memory__
42TC-001-0001-001-CPU_Information
43TC-001-0001-002-Processor_Topology
44TC-001-0001-003-Memory_Information
045
=== 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-07 09:50:29 +0000
@@ -0,0 +1,31 @@
1plugin: shell
2name: TC-001-0001-001-CPU_Information
3requires: package.name == 'lshw'
4user: root
5command: cpu_info -p Xeon -f E5
6description:
7 1. Use lshw command to gather CPU information.
8 2. The program will output CPU model and L1, L2, L3 cache size.
9 3. Criteria: CPU model must be Intel Xeon processor E5-2600 product family and L3 cache size must be up to 20MB.
10
11plugin: shell
12name: TC-001-0001-002-Processor_Topology
13command: processor_topology
14description:
15 1. This test checks CPU topology for accuracy.
16 2. Use lscpu command to gather CPU information.
17 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.
18 4. Criteria: It should be 8-12 cores per CPU and 2 threads per core.
19
20plugin: shell
21name: TC-001-0001-003-Memory_Information
22requires: package.name == 'lshw'
23user: root
24command: memory_info
25description:
26 1. Use lshw command to gather memory information.
27 2. Testing prerequisites:
28 4 channels DDR3 registered memory interface on each processor 0 and processor 1.
29 2 DDR3 slots per channel per processor. (total of 16 DIMMs on the motherboard)
30 3. The program will output memory module, vendor, size and slot.
31 4. Criteria: Total of 16 DIMMs on the motherboard.
032
=== modified file 'jobs/local.txt.in'
--- jobs/local.txt.in 2013-10-01 00:55:26 +0000
+++ jobs/local.txt.in 2014-02-07 09:50:29 +0000
@@ -109,3 +109,10 @@
109command:109command:
110 shopt -s extglob110 shopt -s extglob
111 cat $CHECKBOX_SHARE/jobs/sniff.txt?(.in)111 cat $CHECKBOX_SHARE/jobs/sniff.txt?(.in)
112
113name: __TC-001-0001-CPU_Memory__
114plugin: local
115_description: Verify CPU and memory
116command:
117 shopt -s extglob
118 cat $CHECKBOX_SHARE/jobs/TC-001-0001-CPU_Memory.txt?(.in)
112119
=== added file 'scripts/cpu_info'
--- scripts/cpu_info 1970-01-01 00:00:00 +0000
+++ scripts/cpu_info 2014-02-07 09:50:29 +0000
@@ -0,0 +1,97 @@
1#!/usr/bin/env python3
2"""
3Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications
4Industrial Technology Research Institute
5
6cpu_info
7 Use lshw command to gather CPU information.
8 The program will output CPU model and L1, L2, L3 cache size.
9 Criteria: CPU model and product family must match user's input
10 and L3 cache should be larger than 20MB.
11
12Authors
13 Nelson Chu <Nelson.Chu@itri.org.tw>
14
15This program is free software: you can redistribute it and/or modify
16it under the terms of the GNU General Public License version 3,
17as published by the Free Software Foundation.
18
19This program is distributed in the hope that it will be useful,
20but WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22GNU General Public License for more details.
23
24You should have received a copy of the GNU General Public License
25along with this program. If not, see <http://www.gnu.org/licenses/>.
26
27"""
28
29import os
30import re
31import sys
32import xml.etree.ElementTree as ET
33from subprocess import check_output
34from argparse import ArgumentParser, RawTextHelpFormatter
35
36def run(product, family):
37 command = "lshw -xml"
38 with open(os.devnull, 'w') as NULL:
39 hwinfo_xml = check_output(command, stderr=NULL, shell=True)
40 root = ET.fromstring(hwinfo_xml)
41
42 # Parse lshw XML for gathering processor information.
43 processor = root.findall(".//product/..[@class='processor']")
44
45 if not processor:
46 print("Fail: Cannot parse any processor information.")
47 return 10
48
49 for cpu in processor:
50 if cpu.find('product') is None:
51 print("Fail: Cannot find processor product.")
52 return 20
53 print(cpu.find('product').text)
54 match = re.search(product + '.*' + family, cpu.find('product').text)
55 if not match:
56 print("Fail: Cannot match CPU %s %s family." %(product, family))
57 return 25
58
59 cache_list = cpu.findall(".//size/..[@class='memory']")
60 if not cache_list:
61 print("Fail: Cannot find any CPU cache.")
62 return 30
63
64 for cache in cache_list:
65 if cache.find('size') is None or cache.find('slot') is None:
66 print("Fail: Cannot access Last Level Cache (LLC).")
67 return 40
68
69 cache_size = int(cache.find('size').text) / 1024
70 if cache_size > 1024:
71 cache_size = cache_size / 1024
72 print(('%s %d MB') %(cache.find('slot').text, cache_size))
73 if re.search('L3', cache.find('slot').text):
74 if cache_size < 20:
75 print('Fail: L3 cache size less than 20MB.')
76 return 50
77 else:
78 print(('%s %d KB') %(cache.find('slot').text, cache_size))
79
80 return 0
81
82def main():
83 parser = ArgumentParser(formatter_class=RawTextHelpFormatter)
84
85 parser.add_argument('-p', '--product', type=str, required=True,
86 help=("The CPU product name. [Example: Xeon]"))
87 parser.add_argument('-f', '--family', type=str, required=True,
88 help=("Processor family. [Example: E5]"))
89
90 args = parser.parse_args()
91
92 product = args.product.title()
93 family = args.family.title()
94 return run(product, family)
95
96if __name__ == '__main__':
97 sys.exit(main())
098
=== added file 'scripts/memory_info'
--- scripts/memory_info 1970-01-01 00:00:00 +0000
+++ scripts/memory_info 2014-02-07 09:50:29 +0000
@@ -0,0 +1,77 @@
1#!/usr/bin/env python3
2"""
3Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications
4Industrial Technology Research Institute
5
6memory_info
7 1. Use lshw command to gather memory information.
8 2. Testing prerequisites:
9 4 channels DDR3 registered memory interface on each processor 0
10 and processor 1.
11 2 DDR3 slots per channel per processor. (total of 16 DIMMs
12 on the motherboard)
13 3. The program will output memory module, vendor, size and slot.
14 4. Criteria: Total of 16 DIMMs on the motherboard.
15
16Authors
17 Nelson Chu <Nelson.Chu@itri.org.tw>
18
19This program is free software: you can redistribute it and/or modify
20it under the terms of the GNU General Public License version 3,
21as published by the Free Software Foundation.
22
23This program is distributed in the hope that it will be useful,
24but WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with this program. If not, see <http://www.gnu.org/licenses/>.
30
31"""
32
33import sys
34import xml.etree.ElementTree as ET
35from subprocess import Popen, PIPE
36
37def main():
38 attribute = ['description', 'vendor', 'slot', 'size']
39 command = 'lshw -xml'
40 hwinfo_xml = Popen(command, stdout=PIPE, stderr=PIPE,
41 shell=True).communicate()[0]
42 root = ET.fromstring(hwinfo_xml)
43
44 # Parse lshw XML for gathering memory information.
45 memory_list = root.findall(".//clock/..[@class='memory']")
46
47 if not memory_list:
48 print("Fail: Cannot parse any memory information.")
49 return 10
50
51 count = 0
52 for dimm in memory_list:
53 count = count +1
54 for attr in attribute:
55 if dimm.find(attr) is None:
56 print(("Fail: Cannot find memory %s") %attr)
57 return 20
58
59 memory_size = int(dimm.find('size').text) / (1024**3)
60 for attr in attribute:
61 if attr == 'description':
62 print('%s' %(dimm.find(attr).text), end=" ")
63 continue
64 elif attr == 'size':
65 print('%s=%dGB.' %(attr, memory_size))
66 continue
67 print('%s=%s' %(attr, dimm.find(attr).text), end=" ")
68
69 print("Total number of DIMMs is %s." %(count))
70 if count != 16:
71 print("Fail: Memory DIMM number is not meet the requirement.")
72 return 30
73
74 return 0
75
76if __name__ == '__main__':
77 sys.exit(main())
078
=== added file 'scripts/processor_topology'
--- scripts/processor_topology 1970-01-01 00:00:00 +0000
+++ scripts/processor_topology 2014-02-07 09:50:29 +0000
@@ -0,0 +1,130 @@
1#!/usr/bin/env python3
2'''
3cpu_topology
4Written by Jeffrey Lane <jeffrey.lane@canonical.com>
5'''
6import sys
7import os
8from subprocess import check_output
9
10class proc_cpuinfo():
11 '''
12 Class to get and handle information from /proc/cpuinfo
13 Creates a dictionary of data gleaned from that file.
14 '''
15 def __init__(self):
16 self.cpuinfo = {}
17 cpu_fh = open('/proc/cpuinfo', 'r')
18 try:
19 temp = cpu_fh.readlines()
20 finally:
21 cpu_fh.close()
22
23 for i in temp:
24 if i.startswith('processor'):
25 key = 'cpu' + (i.split(':')[1].strip())
26 self.cpuinfo[key] = {'core_id':'', 'physical_package_id':''}
27 elif i.startswith('core id'):
28 self.cpuinfo[key].update({'core_id': i.split(':')[1].strip()})
29 elif i.startswith('physical id'):
30 self.cpuinfo[key].update({'physical_package_id':
31 i.split(':')[1].strip()})
32 else:
33 continue
34
35
36class sysfs_cpu():
37 '''
38 Class to get and handle information from sysfs as relates to CPU topology
39 Creates an informational class to present information on various CPUs
40 '''
41
42 def __init__(self, proc):
43 self.syscpu = {}
44 self.path = '/sys/devices/system/cpu/' + proc + '/topology'
45 items = ['core_id', 'physical_package_id']
46 for i in items:
47 syscpu_fh = open(os.path.join(self.path, i), 'r')
48 try:
49 self.syscpu[i] = syscpu_fh.readline().strip()
50 finally:
51 syscpu_fh.close()
52
53
54def compare(proc_cpu, sys_cpu):
55 cpu_map = {}
56 '''
57 If there is only 1 CPU the test don't look for core_id
58 and physical_package_id because those information are absent in
59 /proc/cpuinfo on singlecore system
60 '''
61 for key in proc_cpu.keys():
62 if 'cpu1' not in proc_cpu:
63 cpu_map[key] = True
64 else:
65 for subkey in proc_cpu[key].keys():
66 if proc_cpu[key][subkey] == sys_cpu[key][subkey]:
67 cpu_map[key] = True
68 else:
69 cpu_map[key] = False
70 return cpu_map
71
72
73def main():
74 cpuinfo = proc_cpuinfo()
75 sys_cpu = {}
76 keys = cpuinfo.cpuinfo.keys()
77 for k in keys:
78 sys_cpu[k] = sysfs_cpu(k).syscpu
79 cpu_map = compare(cpuinfo.cpuinfo, sys_cpu)
80 if False in cpu_map.values() or len(cpu_map) < 1:
81 print("FAIL: CPU Topology is incorrect", file=sys.stderr)
82 print("-" * 52, file=sys.stderr)
83 print("{0}{1}".format("/proc/cpuinfo".center(30), "sysfs".center(25)),
84 file=sys.stderr)
85 print("{0}{1}{2}{3}{1}{2}".format(
86 "CPU".center(6),
87 "Physical ID".center(13),
88 "Core ID".center(9),
89 "|".center(3)), file=sys.stderr)
90 for key in sorted(sys_cpu.keys()):
91 print("{0}{1}{2}{3}{4}{5}".format(
92 key.center(6),
93 cpuinfo.cpuinfo[key]['physical_package_id'].center(13),
94 cpuinfo.cpuinfo[key]['core_id'].center(9),
95 "|".center(3),
96 sys_cpu[key]['physical_package_id'].center(13),
97 sys_cpu[key]['core_id'].center(9)), file=sys.stderr)
98 return 1
99 else:
100 # Use lscpu command to gather CPU information.
101 # Output the total number of CPUs, the number of threads per core,
102 # the number of cores per socket, and the number of sockets.
103 # Criteria: It must be 8-12 cores per CPU and 2 threads per core.
104 # Revised by Nelson Chu <nelson.chu@itri.org.tw>
105 command = 'lscpu'
106 return_code = 0
107
108 with open(os.devnull, "w") as NULL:
109 cpu_info = check_output(command, stderr=NULL, shell=True)
110
111 cpu_info = cpu_info.decode('utf-8')
112
113 for cpu in cpu_info.split('\n'):
114 if cpu.startswith("CPU(s)"):
115 print(cpu)
116 if cpu.startswith("Thread(s) per core"):
117 print(cpu)
118 if cpu.startswith("Core(s) per socket"):
119 cores = int(cpu.split(":")[1])
120 print(cpu)
121 # It should be 8-12 cores per CPU.
122 if cores < 8 or cores > 12:
123 return_code = 1
124 if cpu.startswith("Socket(s)"):
125 print(cpu)
126
127 return return_code
128
129if __name__ == '__main__':
130 sys.exit(main())

Subscribers

People subscribed via source and target branches