diff mbox series

[1/2] pm-graph v5.12, fixes

Message ID 3d5c6c492cee09096f238bbf20514a305b174412.1717146154.git.todd.e.brandt@intel.com
State New
Headers show
Series [1/2] pm-graph v5.12, fixes | expand

Commit Message

Todd Brandt May 31, 2024, 9:13 a.m. UTC
- fix S3 suspend fail double run by using fp.flush to /sys/power/state
- when running turbostat print the return value
- handle case where html files have binary data
- max issues in summary-issues is now 100 (in case there are thousands)
- add backup to dmidecode, use /sys/class/dmi/id/ in case /dev/mem fails
- update summary page to use full mode (disk-platform instead of disk)

Signed-off-by: Todd Brandt <todd.e.brandt@intel.com>
---
 tools/power/pm-graph/sleepgraph.py | 102 ++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 37 deletions(-)
diff mbox series

Patch

diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py
index 40ad221e8881..b709c5f2b6f1 100755
--- a/tools/power/pm-graph/sleepgraph.py
+++ b/tools/power/pm-graph/sleepgraph.py
@@ -86,7 +86,7 @@  def ascii(text):
 #	 store system values and test parameters
 class SystemValues:
 	title = 'SleepGraph'
-	version = '5.11'
+	version = '5.12'
 	ansi = False
 	rs = 0
 	display = ''
@@ -1181,8 +1181,8 @@  class SystemValues:
 		cmd = self.getExec('turbostat')
 		rawout = keyline = valline = ''
 		fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile)
-		fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr
-		for line in fp:
+		fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE)
+		for line in fp.stderr:
 			line = ascii(line)
 			rawout += line
 			if keyline and valline:
@@ -1191,13 +1191,13 @@  class SystemValues:
 				keyline = line.strip().split()
 			elif keyline:
 				valline = line.strip().split()
-		fp.close()
+		fp.wait()
 		if not keyline or not valline or len(keyline) != len(valline):
 			errmsg = 'unrecognized turbostat output:\n'+rawout.strip()
 			self.vprint(errmsg)
 			if not self.verbose:
 				pprint(errmsg)
-			return ''
+			return (fp.returncode, '')
 		if self.verbose:
 			pprint(rawout.strip())
 		out = []
@@ -1207,7 +1207,7 @@  class SystemValues:
 			if key == 'SYS%LPI' and not s0ixready and re.match('^[0\.]*$', val):
 				continue
 			out.append('%s=%s' % (key, val))
-		return '|'.join(out)
+		return (fp.returncode, '|'.join(out))
 	def netfixon(self, net='both'):
 		cmd = self.getExec('netfix')
 		if not cmd:
@@ -4343,7 +4343,8 @@  def createHTMLSummarySimple(testruns, htmlfile, title):
 		list[mode]['data'].append([data['host'], data['kernel'],
 			data['time'], tVal[0], tVal[1], data['url'], res,
 			data['issues'], data['sus_worst'], data['sus_worsttime'],
-			data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi])
+			data['res_worst'], data['res_worsttime'], pkgpc10, syslpi, wifi,
+			(data['fullmode'] if 'fullmode' in data else mode)])
 		idx = len(list[mode]['data']) - 1
 		if res.startswith('fail in'):
 			res = 'fail'
@@ -4449,7 +4450,7 @@  def createHTMLSummarySimple(testruns, htmlfile, title):
 				elif idx == iMed[i]:
 					tHigh[i] = ' id="%smed" class=medval title="Median"' % tag
 			html += td.format("%d" % (list[mode]['data'].index(d) + 1)) # row
-			html += td.format(mode)										# mode
+			html += td.format(d[15])									# mode
 			html += td.format(d[0])										# host
 			html += td.format(d[1])										# kernel
 			html += td.format(d[2])										# time
@@ -5524,7 +5525,9 @@  def executeSuspend(quiet=False):
 			if ((mode == 'freeze') or (sv.memmode == 's2idle')) \
 				and sv.haveTurbostat():
 				# execution will pause here
-				turbo = sv.turbostat(s0ixready)
+				retval, turbo = sv.turbostat(s0ixready)
+				if retval != 0:
+					tdata['error'] ='turbostat returned %d' % retval
 				if turbo:
 					tdata['turbo'] = turbo
 			else:
@@ -5532,6 +5535,7 @@  def executeSuspend(quiet=False):
 				pf.write(mode)
 				# execution will pause here
 				try:
+					pf.flush()
 					pf.close()
 				except Exception as e:
 					tdata['error'] = str(e)
@@ -5702,6 +5706,40 @@  def getModes():
 		fp.close()
 	return modes
 
+def dmidecode_backup(out, fatal=False):
+	cpath, spath, info = '/proc/cpuinfo', '/sys/class/dmi/id', {
+		'bios-vendor': 'bios_vendor',
+		'bios-version': 'bios_version',
+		'bios-release-date': 'bios_date',
+		'system-manufacturer': 'sys_vendor',
+		'system-product-name': 'product_name',
+		'system-version': 'product_version',
+		'system-serial-number': 'product_serial',
+		'baseboard-manufacturer': 'board_vendor',
+		'baseboard-product-name': 'board_name',
+		'baseboard-version': 'board_version',
+		'baseboard-serial-number': 'board_serial',
+		'chassis-manufacturer': 'chassis_vendor',
+		'chassis-version': 'chassis_version',
+		'chassis-serial-number': 'chassis_serial',
+	}
+	for key in info:
+		if key not in out:
+			val = sysvals.getVal(os.path.join(spath, info[key])).strip()
+			if val and val.lower() != 'to be filled by o.e.m.':
+				out[key] = val
+	if 'processor-version' not in out and os.path.exists(cpath):
+		with open(cpath, 'r') as fp:
+			for line in fp:
+				m = re.match('^model\s*name\s*\:\s*(?P<c>.*)', line)
+				if m:
+					out['processor-version'] = m.group('c').strip()
+					break
+	if fatal and len(out) < 1:
+		doError('dmidecode failed to get info from %s or %s' % \
+			(sysvals.mempath, spath))
+	return out
+
 # Function: dmidecode
 # Description:
 #	 Read the bios tables and pull out system info
@@ -5712,6 +5750,8 @@  def getModes():
 #	 A dict object with all available key/values
 def dmidecode(mempath, fatal=False):
 	out = dict()
+	if(not (os.path.exists(mempath) and os.access(mempath, os.R_OK))):
+		return dmidecode_backup(out, fatal)
 
 	# the list of values to retrieve, with hardcoded (type, idx)
 	info = {
@@ -5727,24 +5767,14 @@  def dmidecode(mempath, fatal=False):
 		'baseboard-version': (2, 6),
 		'baseboard-serial-number': (2, 7),
 		'chassis-manufacturer': (3, 4),
-		'chassis-type': (3, 5),
 		'chassis-version': (3, 6),
 		'chassis-serial-number': (3, 7),
 		'processor-manufacturer': (4, 7),
 		'processor-version': (4, 16),
 	}
-	if(not os.path.exists(mempath)):
-		if(fatal):
-			doError('file does not exist: %s' % mempath)
-		return out
-	if(not os.access(mempath, os.R_OK)):
-		if(fatal):
-			doError('file is not readable: %s' % mempath)
-		return out
 
 	# by default use legacy scan, but try to use EFI first
-	memaddr = 0xf0000
-	memsize = 0x10000
+	memaddr, memsize = 0xf0000, 0x10000
 	for ep in ['/sys/firmware/efi/systab', '/proc/efi/systab']:
 		if not os.path.exists(ep) or not os.access(ep, os.R_OK):
 			continue
@@ -5765,11 +5795,7 @@  def dmidecode(mempath, fatal=False):
 		fp.seek(memaddr)
 		buf = fp.read(memsize)
 	except:
-		if(fatal):
-			doError('DMI table is unreachable, sorry')
-		else:
-			pprint('WARNING: /dev/mem is not readable, ignoring DMI data')
-			return out
+		return dmidecode_backup(out, fatal)
 	fp.close()
 
 	# search for either an SM table or DMI table
@@ -5785,10 +5811,7 @@  def dmidecode(mempath, fatal=False):
 			break
 		i += 16
 	if base == 0 and length == 0 and num == 0:
-		if(fatal):
-			doError('Neither SMBIOS nor DMI were found')
-		else:
-			return out
+		return dmidecode_backup(out, fatal)
 
 	# read in the SM or DMI table
 	try:
@@ -5796,11 +5819,7 @@  def dmidecode(mempath, fatal=False):
 		fp.seek(base)
 		buf = fp.read(length)
 	except:
-		if(fatal):
-			doError('DMI table is unreachable, sorry')
-		else:
-			pprint('WARNING: /dev/mem is not readable, ignoring DMI data')
-			return out
+		return dmidecode_backup(out, fatal)
 	fp.close()
 
 	# scan the table for the values we want
@@ -6272,7 +6291,10 @@  def find_in_html(html, start, end, firstonly=True):
 	return out
 
 def data_from_html(file, outpath, issues, fulldetail=False):
-	html = open(file, 'r').read()
+	try:
+		html = open(file, 'r').read()
+	except:
+		html = ascii(open(file, 'rb').read())
 	sysvals.htmlfile = os.path.relpath(file, outpath)
 	# extract general info
 	suspend = find_in_html(html, 'Kernel Suspend', 'ms')
@@ -6307,8 +6329,9 @@  def data_from_html(file, outpath, issues, fulldetail=False):
 		d.end = 999999999
 		d.dmesgtext = log.split('\n')
 		tp = d.extractErrorInfo()
-		for msg in tp.msglist:
-			sysvals.errorSummary(issues, msg)
+		if len(issues) < 100:
+			for msg in tp.msglist:
+				sysvals.errorSummary(issues, msg)
 		if stmp[2] == 'freeze':
 			extra = d.turbostatInfo()
 		elist = dict()
@@ -6325,6 +6348,11 @@  def data_from_html(file, outpath, issues, fulldetail=False):
 		line = find_in_html(log, '# netfix ', '\n')
 		if line:
 			extra['netfix'] = line
+		line = find_in_html(log, '# command ', '\n')
+		if line:
+			m = re.match('.* -m (?P<m>\S*).*', line)
+			if m:
+				extra['fullmode'] = m.group('m')
 	low = find_in_html(html, 'freeze time: <b>', ' ms</b>')
 	for lowstr in ['waking', '+']:
 		if not low: