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: 506 lines (+365/-43)
7 files modified
data/whitelists/opencompute-certify-local.whitelist (+0/-43)
debian/changelog (+19/-0)
jobs/TC-001-0001-CPU_Memory.txt.in (+31/-0)
jobs/local.txt.in (+7/-0)
scripts/cpu_info (+100/-0)
scripts/memory_info (+78/-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
Jeff Lane  Pending
Nelson Chu Pending
Review via email: mp+206489@code.launchpad.net

This proposal supersedes a proposal from 2014-02-13.

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

Description of the change

Scripts and annotations have been modified.

To post a comment you must log in.
Revision history for this message
Jeff Lane  (bladernr) wrote : Posted in a previous version of this proposal
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 : Posted in a previous version of this proposal

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

Revision history for this message
Nelson Chu (nelson-chu) wrote : Posted in a previous version of this proposal

Hi Jeff,

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

Thanks,
Nelson

review: Needs Resubmitting
Revision history for this message
Jeff Lane  (bladernr) wrote : Posted in a previous version of this proposal

Before I can go any further, you have a conflict in data/whitelists/opencompute-certify-local.whitelist

To see this, you should do the following:

bzr branch lp:opencompute/checkbox ocp-checkbox
cd ocp-checkbox
bzr merge lp:~nelson-chu/opencompute/add-ocp-cpu-memory-job

That MAY actually just clean it up... but there's a file conflict in there. so please resolve that and I'll review the rest at that time.

review: Needs Fixing
Revision history for this message
Jeff Lane  (bladernr) wrote : Posted in a previous version of this proposal

Hi Nelson.. Most everything looks good now. There are two remaining issues...

1: the changelog now seems to have duplicate entreies (see the diff below).

I am sorry if I wasn't clear, but you need to put your entries BETWEEN the version header and timestamp lines. For example:

checkbox (1.16.13~OCP) UNRELEASED; urgency=low

  [ Jeff Marcom ]
  * Updated scripts/network script from lp:checkbox

 -- Jeff Marcom <email address hidden> Tue, 5 Nov 2013 11:12:04 -0400

You entry should come after the "checkbox (1.16.13~OCP) line and above the first entry by Jeff Marcom like so:

checkbox (1.16.13~OCP) UNRELEASED; urgency=low

  [ Nelson Chu ]
  * data/whitelists/opencompute-certify-local.whitelist - Added new jobs to
    certification whitelist
  * jobs/TC-001-0002-Platform_Controller_Hub.txt - Added new jobs for PCH
    test cases
  * jobs/local.txt.in - Added job to parse new PCH job file
  * scripts/check_sata_port - new script to verify SATA port speed
  * scripts/check_usb_port - new script to verify USB version

  [ Jeff Marcom ]
  * Updated scripts/network script from lp:checkbox

 -- Jeff Marcom <email address hidden> Tue, 5 Nov 2013 11:12:04 -0400

2: the memory_info script doesn't seem to work... I keep getting this when I try to run it:
bladernr@mini-ubuntu:~/development/nelson-cpu-memory$ sudo ./scripts/memory_info
Fail: Cannot find memory slot

If I run lshw manually, I see memory class objects in the listing:
<node id="bank:0" claimed="true" class="memory" handle="DMI:001F">
       <description>DIMM</description>
       <product>None</product>
       <vendor>None</vendor>
       <physid>0</physid>
       <serial>None</serial>
       <slot>A0</slot>
       <size units="bytes">1073741824</size>
       <width units="bits">64</width>
      </node>

which does list all the required attributes (vendor, description, slot and size).

Can you show me an example of XML from lshw that is correct and works, and an example of passing script output

3: one other thing I just noticed... you do this a lot:

  print("some error message")
  return SOME_NON_ZERO_INTEGER

If you do it this way, your error message will not appear in the checkbox results. Checkbox will add stdout if a test passes and stderr if a test returns a non-zero exit code.

To correct this, ANY message that should be printed when a script exits in an error condition like this:

  print("FAIL: Some necessary criteria was not met")
  return 50

should be instead be printed to stderr like this:
  print("FAIL: Some necessary criteria was not met", file=sys.stderr)
  return 50

This will save your sanity in the long run if a test fails and you don't see any output in the results file.

review: Needs Fixing
Revision history for this message
Nelson Chu (nelson-chu) wrote : Posted in a previous version of this proposal

Hi Jeff,

I glad I am getting closer.

1.) I misunderstood what you meant. Sorry for that...

2.) This is a strange issue. When I run memory_info script on Winterfell is fine.

But, run on other server both good and bad.

I parse lshw XML from server that occur this issue. It appears this section as below:
      <node id="bank" class="memory" handle="DMI:0057">
       <description>FLASH Non-volatile 33 MHz (30.3 ns)</description>
       <product>25Q Series</product>
       <vendor>Micron/Numonyx</vendor>
       <physid>0</physid>
       <size units="bytes">16777216</size>
       <width units="bits">8</width>
       <clock units="Hz">33000000</clock>
      </node>

So XML parser cannot gather memory info correctly...

I think it work fine with Winterfell, the successful output is:
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelA_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelA_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelB_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelB_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelC_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelC_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelD_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelD_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelE_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelE_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelF_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelF_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelG_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelG_Dimm2 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelH_Dimm1 size=8GB.
DIMM DDR3 1333 MHz (0.8 ns) vendor=Samsung slot=ChannelH_Dimm2 size=8GB.
Total number of DIMMs is 16.

if you insist I will modify the script.

3.) I didn't notice that before. I have modified it correctly.

I am appreciated greatly your help.

Nelson

review: Needs Resubmitting
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
1=== added file 'data/whitelists/opencompute-certify-local.whitelist'
2--- data/whitelists/opencompute-certify-local.whitelist 1970-01-01 00:00:00 +0000
3+++ data/whitelists/opencompute-certify-local.whitelist 2014-02-14 13:33:04 +0000
4@@ -0,0 +1,47 @@
5+# Resource Jobs
6+block_device
7+cdimage
8+cpuinfo
9+device
10+dmi
11+dpkg
12+efi
13+environment
14+gconf
15+lsb
16+meminfo
17+module
18+optical_drive
19+package
20+sleep
21+uname
22+#Info attachment jobs
23+__info__
24+cpuinfo_attachment
25+dmesg_attachment
26+dmi_attachment
27+dmidecode_attachment
28+efi_attachment
29+lspci_attachment
30+lshw_attachment
31+mcelog_attachment
32+meminfo_attachment
33+modprobe_attachment
34+modules_attachment
35+sysctl_attachment
36+sysfs_attachment
37+udev_attachment
38+lsmod_attachment
39+acpi_sleep_attachment
40+info/hdparm
41+info/hdparm_.*.txt
42+installer_debug.gz
43+info/disk_partitions
44+# Actual test cases
45+__TC-001-0001-CPU_Memory__
46+TC-001-0001-001-CPU_Information
47+TC-001-0001-002-Processor_Topology
48+TC-001-0001-003-Memory_Information
49+__TC-001-0002-Platform_Controller_Hub__
50+TC-001-0002-001-SATA_port
51+TC-001-0002-002-USB_2.0
52
53=== removed file 'data/whitelists/opencompute-certify-local.whitelist'
54--- data/whitelists/opencompute-certify-local.whitelist 2014-02-11 12:16:41 +0000
55+++ data/whitelists/opencompute-certify-local.whitelist 1970-01-01 00:00:00 +0000
56@@ -1,43 +0,0 @@
57-# Resource Jobs
58-block_device
59-cdimage
60-cpuinfo
61-device
62-dmi
63-dpkg
64-efi
65-environment
66-gconf
67-lsb
68-meminfo
69-module
70-optical_drive
71-package
72-sleep
73-uname
74-#Info attachment jobs
75-__info__
76-cpuinfo_attachment
77-dmesg_attachment
78-dmi_attachment
79-dmidecode_attachment
80-efi_attachment
81-lspci_attachment
82-lshw_attachment
83-mcelog_attachment
84-meminfo_attachment
85-modprobe_attachment
86-modules_attachment
87-sysctl_attachment
88-sysfs_attachment
89-udev_attachment
90-lsmod_attachment
91-acpi_sleep_attachment
92-info/hdparm
93-info/hdparm_.*.txt
94-installer_debug.gz
95-info/disk_partitions
96-# Actual test cases
97-__TC-001-0002-Platform_Controller_Hub__
98-TC-001-0002-001-SATA_port
99-TC-001-0002-002-USB_2.0
100
101=== modified file 'debian/changelog'
102--- debian/changelog 2013-11-05 20:04:15 +0000
103+++ debian/changelog 2014-02-14 13:33:04 +0000
104@@ -1,5 +1,24 @@
105 checkbox (1.16.13~OCP) UNRELEASED; urgency=low
106
107+ [ Nelson Chu ]
108+ * data/whitelists/opencompute-certify-local.whitelist - Added new jobs to
109+ certification whitelist
110+ * jobs/TC-001-0002-Platform_Controller_Hub.txt - Added new jobs for PCH
111+ test cases
112+ * jobs/local.txt.in - Added job to parse new PCH job file
113+ * scripts/check_sata_port - new script to verify SATA port speed
114+ * scripts/check_usb_port - new script to verify USB version
115+
116+ [ Nelson Chu ]
117+ * data/whitelists/opencompute-certify-local.whitelist - Added new jobs to
118+ certification whitelist
119+ * jobs/TC-001-0001-CPU_Memory.txt.in - Added new jobs for CPU and Memory
120+ test cases
121+ * jobs/local.txt.in - Added job to parse new CPU and Memory job file
122+ * scripts/cpu_info - new script to gather CPU information
123+ * scripts/memory_info - new script to gather memory information
124+ * scripts/processor_topology - Revised script to match certification criteria
125+
126 [ Jeff Marcom ]
127 * Updated scripts/network script from lp:checkbox
128
129
130=== added file 'jobs/TC-001-0001-CPU_Memory.txt.in'
131--- jobs/TC-001-0001-CPU_Memory.txt.in 1970-01-01 00:00:00 +0000
132+++ jobs/TC-001-0001-CPU_Memory.txt.in 2014-02-14 13:33:04 +0000
133@@ -0,0 +1,31 @@
134+plugin: shell
135+name: TC-001-0001-001-CPU_Information
136+requires: package.name == 'lshw'
137+user: root
138+command: cpu_info -p Xeon -f E5
139+description:
140+ 1. Use lshw command to gather CPU information.
141+ 2. The program will output CPU model and L1, L2, L3 cache size.
142+ 3. Criteria: CPU model must be Intel Xeon processor E5-2600 product family and L3 cache size must be up to 20MB.
143+
144+plugin: shell
145+name: TC-001-0001-002-Processor_Topology
146+command: processor_topology
147+description:
148+ 1. This test checks CPU topology for accuracy.
149+ 2. Use lscpu command to gather CPU information.
150+ 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.
151+ 4. Criteria: It should be 8-12 cores per CPU and 2 threads per core.
152+
153+plugin: shell
154+name: TC-001-0001-003-Memory_Information
155+requires: package.name == 'lshw'
156+user: root
157+command: memory_info
158+description:
159+ 1. Use lshw command to gather memory information.
160+ 2. Testing prerequisites:
161+ 4 channels DDR3 registered memory interface on each processor 0 and processor 1.
162+ 2 DDR3 slots per channel per processor. (total of 16 DIMMs on the motherboard)
163+ 3. The program will output memory module, vendor, size and slot.
164+ 4. Criteria: Total of 16 DIMMs on the motherboard.
165
166=== renamed file 'jobs/TC-001-0002-Platform_Controller_Hub.txt' => 'jobs/TC-001-0002-Platform_Controller_Hub.txt.in'
167=== modified file 'jobs/local.txt.in'
168--- jobs/local.txt.in 2014-02-11 12:16:41 +0000
169+++ jobs/local.txt.in 2014-02-14 13:33:04 +0000
170@@ -110,6 +110,13 @@
171 shopt -s extglob
172 cat $CHECKBOX_SHARE/jobs/sniff.txt?(.in)
173
174+name: __TC-001-0001-CPU_Memory__
175+plugin: local
176+_description: Verify CPU and memory
177+command:
178+ shopt -s extglob
179+ cat $CHECKBOX_SHARE/jobs/TC-001-0001-CPU_Memory.txt?(.in)
180+
181 name: __TC-001-0002-Platform_Controller_Hub__
182 plugin: local
183 _description: Verify platform controller hub functionality
184
185=== added file 'scripts/cpu_info'
186--- scripts/cpu_info 1970-01-01 00:00:00 +0000
187+++ scripts/cpu_info 2014-02-14 13:33:04 +0000
188@@ -0,0 +1,100 @@
189+#!/usr/bin/env python3
190+"""
191+Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications
192+Industrial Technology Research Institute
193+
194+cpu_info
195+ Use lshw command to gather CPU information.
196+ The program will output CPU model and L1, L2, L3 cache size.
197+ Criteria: CPU model and product family must match user's input
198+ and L3 cache should be larger than 20MB.
199+
200+Authors
201+ Nelson Chu <Nelson.Chu@itri.org.tw>
202+
203+This program is free software: you can redistribute it and/or modify
204+it under the terms of the GNU General Public License version 3,
205+as published by the Free Software Foundation.
206+
207+This program is distributed in the hope that it will be useful,
208+but WITHOUT ANY WARRANTY; without even the implied warranty of
209+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
210+GNU General Public License for more details.
211+
212+You should have received a copy of the GNU General Public License
213+along with this program. If not, see <http://www.gnu.org/licenses/>.
214+
215+"""
216+
217+import os
218+import re
219+import sys
220+import xml.etree.ElementTree as ET
221+from subprocess import check_output
222+from argparse import ArgumentParser, RawTextHelpFormatter
223+
224+def run(product, family):
225+ command = "lshw -xml"
226+ with open(os.devnull, 'w') as NULL:
227+ hwinfo_xml = check_output(command, stderr=NULL, shell=True)
228+ root = ET.fromstring(hwinfo_xml)
229+
230+ # Parse lshw XML for gathering processor information.
231+ processor = root.findall(".//product/..[@class='processor']")
232+
233+ if not processor:
234+ print("Fail: Cannot parse any processor information.", file=sys.stderr)
235+ return 10
236+
237+ for cpu in processor:
238+ if cpu.find('product') is None:
239+ print("Fail: Cannot find processor product.", file=sys.stderr)
240+ return 20
241+ print(cpu.find('product').text)
242+ match = re.search(product + '.*' + family, cpu.find('product').text)
243+ if not match:
244+ print("Fail: Cannot match CPU %s %s family." %(product, family),
245+ file=sys.stderr)
246+ return 25
247+
248+ cache_list = cpu.findall(".//size/..[@class='memory']")
249+ if not cache_list:
250+ print("Fail: Cannot find any CPU cache.", file=sys.stderr)
251+ return 30
252+
253+ for cache in cache_list:
254+ if cache.find('size') is None or cache.find('slot') is None:
255+ print("Fail: Cannot access Last Level Cache (LLC).",
256+ file=sys.stderr)
257+ return 40
258+
259+ cache_size = int(cache.find('size').text) / 1024
260+ if cache_size > 1024:
261+ cache_size = cache_size / 1024
262+ print(('%s %d MB') %(cache.find('slot').text, cache_size))
263+ if re.search('L3', cache.find('slot').text):
264+ if cache_size < 20:
265+ print('Fail: L3 cache size less than 20MB.',
266+ file=sys.stderr)
267+ return 50
268+ else:
269+ print(('%s %d KB') %(cache.find('slot').text, cache_size))
270+
271+ return 0
272+
273+def main():
274+ parser = ArgumentParser(formatter_class=RawTextHelpFormatter)
275+
276+ parser.add_argument('-p', '--product', type=str, required=True,
277+ help=("The CPU product name. [Example: Xeon]"))
278+ parser.add_argument('-f', '--family', type=str, required=True,
279+ help=("Processor family. [Example: E5]"))
280+
281+ args = parser.parse_args()
282+
283+ product = args.product.title()
284+ family = args.family.title()
285+ return run(product, family)
286+
287+if __name__ == '__main__':
288+ sys.exit(main())
289
290=== added file 'scripts/memory_info'
291--- scripts/memory_info 1970-01-01 00:00:00 +0000
292+++ scripts/memory_info 2014-02-14 13:33:04 +0000
293@@ -0,0 +1,78 @@
294+#!/usr/bin/env python3
295+"""
296+Copyright (C) 2010-2013 by Cloud Computing Center for Mobile Applications
297+Industrial Technology Research Institute
298+
299+memory_info
300+ 1. Use lshw command to gather memory information.
301+ 2. Testing prerequisites:
302+ 4 channels DDR3 registered memory interface on each processor 0
303+ and processor 1.
304+ 2 DDR3 slots per channel per processor. (total of 16 DIMMs
305+ on the motherboard)
306+ 3. The program will output memory module, vendor, size and slot.
307+ 4. Criteria: Total of 16 DIMMs on the motherboard.
308+
309+Authors
310+ Nelson Chu <Nelson.Chu@itri.org.tw>
311+
312+This program is free software: you can redistribute it and/or modify
313+it under the terms of the GNU General Public License version 3,
314+as published by the Free Software Foundation.
315+
316+This program is distributed in the hope that it will be useful,
317+but WITHOUT ANY WARRANTY; without even the implied warranty of
318+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
319+GNU General Public License for more details.
320+
321+You should have received a copy of the GNU General Public License
322+along with this program. If not, see <http://www.gnu.org/licenses/>.
323+
324+"""
325+
326+import sys
327+import xml.etree.ElementTree as ET
328+from subprocess import Popen, PIPE
329+
330+def main():
331+ attribute = ['description', 'vendor', 'slot', 'size']
332+ command = 'lshw -xml'
333+ hwinfo_xml = Popen(command, stdout=PIPE, stderr=PIPE,
334+ shell=True).communicate()[0]
335+ root = ET.fromstring(hwinfo_xml)
336+
337+ # Parse lshw XML for gathering memory information.
338+ memory_list = root.findall(".//clock/..[@class='memory']")
339+
340+ if not memory_list:
341+ print("Fail: Cannot parse any memory information.", file=sys.stderr)
342+ return 10
343+
344+ count = 0
345+ for dimm in memory_list:
346+ count = count +1
347+ for attr in attribute:
348+ if dimm.find(attr) is None:
349+ print(("Fail: Cannot find memory %s") %attr, file=sys.stderr)
350+ return 20
351+
352+ memory_size = int(dimm.find('size').text) / (1024**3)
353+ for attr in attribute:
354+ if attr == 'description':
355+ print('%s' %(dimm.find(attr).text), end=" ")
356+ continue
357+ elif attr == 'size':
358+ print('%s=%dGB.' %(attr, memory_size))
359+ continue
360+ print('%s=%s' %(attr, dimm.find(attr).text), end=" ")
361+
362+ print("Total number of DIMMs is %s." %(count))
363+ if count != 16:
364+ print("Fail: Memory DIMM number is not meet the requirement.",
365+ file=sys.stderr)
366+ return 30
367+
368+ return 0
369+
370+if __name__ == '__main__':
371+ sys.exit(main())
372
373=== added file 'scripts/processor_topology'
374--- scripts/processor_topology 1970-01-01 00:00:00 +0000
375+++ scripts/processor_topology 2014-02-14 13:33:04 +0000
376@@ -0,0 +1,130 @@
377+#!/usr/bin/env python3
378+'''
379+cpu_topology
380+Written by Jeffrey Lane <jeffrey.lane@canonical.com>
381+'''
382+import sys
383+import os
384+from subprocess import check_output
385+
386+class proc_cpuinfo():
387+ '''
388+ Class to get and handle information from /proc/cpuinfo
389+ Creates a dictionary of data gleaned from that file.
390+ '''
391+ def __init__(self):
392+ self.cpuinfo = {}
393+ cpu_fh = open('/proc/cpuinfo', 'r')
394+ try:
395+ temp = cpu_fh.readlines()
396+ finally:
397+ cpu_fh.close()
398+
399+ for i in temp:
400+ if i.startswith('processor'):
401+ key = 'cpu' + (i.split(':')[1].strip())
402+ self.cpuinfo[key] = {'core_id':'', 'physical_package_id':''}
403+ elif i.startswith('core id'):
404+ self.cpuinfo[key].update({'core_id': i.split(':')[1].strip()})
405+ elif i.startswith('physical id'):
406+ self.cpuinfo[key].update({'physical_package_id':
407+ i.split(':')[1].strip()})
408+ else:
409+ continue
410+
411+
412+class sysfs_cpu():
413+ '''
414+ Class to get and handle information from sysfs as relates to CPU topology
415+ Creates an informational class to present information on various CPUs
416+ '''
417+
418+ def __init__(self, proc):
419+ self.syscpu = {}
420+ self.path = '/sys/devices/system/cpu/' + proc + '/topology'
421+ items = ['core_id', 'physical_package_id']
422+ for i in items:
423+ syscpu_fh = open(os.path.join(self.path, i), 'r')
424+ try:
425+ self.syscpu[i] = syscpu_fh.readline().strip()
426+ finally:
427+ syscpu_fh.close()
428+
429+
430+def compare(proc_cpu, sys_cpu):
431+ cpu_map = {}
432+ '''
433+ If there is only 1 CPU the test don't look for core_id
434+ and physical_package_id because those information are absent in
435+ /proc/cpuinfo on singlecore system
436+ '''
437+ for key in proc_cpu.keys():
438+ if 'cpu1' not in proc_cpu:
439+ cpu_map[key] = True
440+ else:
441+ for subkey in proc_cpu[key].keys():
442+ if proc_cpu[key][subkey] == sys_cpu[key][subkey]:
443+ cpu_map[key] = True
444+ else:
445+ cpu_map[key] = False
446+ return cpu_map
447+
448+
449+def main():
450+ cpuinfo = proc_cpuinfo()
451+ sys_cpu = {}
452+ keys = cpuinfo.cpuinfo.keys()
453+ for k in keys:
454+ sys_cpu[k] = sysfs_cpu(k).syscpu
455+ cpu_map = compare(cpuinfo.cpuinfo, sys_cpu)
456+ if False in cpu_map.values() or len(cpu_map) < 1:
457+ print("FAIL: CPU Topology is incorrect", file=sys.stderr)
458+ print("-" * 52, file=sys.stderr)
459+ print("{0}{1}".format("/proc/cpuinfo".center(30), "sysfs".center(25)),
460+ file=sys.stderr)
461+ print("{0}{1}{2}{3}{1}{2}".format(
462+ "CPU".center(6),
463+ "Physical ID".center(13),
464+ "Core ID".center(9),
465+ "|".center(3)), file=sys.stderr)
466+ for key in sorted(sys_cpu.keys()):
467+ print("{0}{1}{2}{3}{4}{5}".format(
468+ key.center(6),
469+ cpuinfo.cpuinfo[key]['physical_package_id'].center(13),
470+ cpuinfo.cpuinfo[key]['core_id'].center(9),
471+ "|".center(3),
472+ sys_cpu[key]['physical_package_id'].center(13),
473+ sys_cpu[key]['core_id'].center(9)), file=sys.stderr)
474+ return 1
475+ else:
476+ # Use lscpu command to gather CPU information.
477+ # Output the total number of CPUs, the number of threads per core,
478+ # the number of cores per socket, and the number of sockets.
479+ # Criteria: It must be 8-12 cores per CPU and 2 threads per core.
480+ # Revised by Nelson Chu <nelson.chu@itri.org.tw>
481+ command = 'lscpu'
482+ return_code = 0
483+
484+ with open(os.devnull, "w") as NULL:
485+ cpu_info = check_output(command, stderr=NULL, shell=True)
486+
487+ cpu_info = cpu_info.decode('utf-8')
488+
489+ for cpu in cpu_info.split('\n'):
490+ if cpu.startswith("CPU(s)"):
491+ print(cpu)
492+ if cpu.startswith("Thread(s) per core"):
493+ print(cpu)
494+ if cpu.startswith("Core(s) per socket"):
495+ cores = int(cpu.split(":")[1])
496+ print(cpu)
497+ # It should be 8-12 cores per CPU.
498+ if cores < 8 or cores > 12:
499+ return_code = 1
500+ if cpu.startswith("Socket(s)"):
501+ print(cpu)
502+
503+ return return_code
504+
505+if __name__ == '__main__':
506+ sys.exit(main())

Subscribers

People subscribed via source and target branches