[Intel-gfx] [PATCH] Seq_file, debugfs, and ring buffer dumping

Ben Gamari bgamari at gmail.com
Mon Jan 19 22:06:35 CET 2009


Hey all,

After the mail issues last time, hopefully you all will be receiving
this once and only once. This is the latest iteration of my patch set
porting the drm and i915 driver to the seq_file API, teaching them about
debugfs, and implementing ring buffer dumping on i915.

Things have changed a bit since this patch set was last sent out. In
particular, I reworked the debugfs/proc file (what I termed 'info file')
management. Things have been simplified a bit making the system much
more flexible. Now it is possible to use the same ``show'' function for
multiple info files. This is used in the exposing the batch buffers to
user-land in addition to the active, inactive, and flushing object
lists.

Moreover, the ring buffer dumping implementation has been entirely
overhauled, in response to the realization that too much logic was
formerly placed in the kernel. Now the driver exposes debugfs files from
which one can read the contents of the ring buffer and the last few
submitted batch buffers. I have a python script which decodes this data
which I have included below. Unfortunately, it seems that batch buffer
dumping is currently giving me jibberish. I haven't ruled out the
possibility that the batch buffers are being reused during dumping (I
don't make any attempt at keeping this from happening under the
assumption that if one is dumping the ring buffer, the GPU is probably
wedged). Nevertheless, this seems unlikely. If anyone can see an issue in
the patches that might cause this, I would love to know. 

Anyways, I hope this is an improvement over what I sent last time. I
worked pretty to consolidate and restructure the patches more logically.
Let me know what you all think. Thanks,

    - Ben



==============
Preliminary ring buffer parsing script:

#!/usr/bin/python

import glob
import re

root = "/sys/kernel/debug/dri/0/"


cmds_mi = {
       0x00: "MI_NOOP",
       0x01: "Reserved 01",
       0x02: "MI_USER_INTERRUPT",
       0x03: "MI_WAIT_FOR_EVENT",
       0x04: "MI_FLUSH",
       0x05: "MI_ARB_CHECK",
       0x06: "MI_REPORT_HEAD",
       0x09: "MI_BATCH_BUFFER_END",
       0x11: "MI_OVERLAY_FLIP",
       0x12: "MI_LOAD_SCAN_LINES_INCL",
       0x13: "MI_LOAD_SCAN_LINES_EXCL",
       0x14: "MI_DISPLAY_BUFFER_INFO",
       0x18: "MI_SET_CONTEXT",
       0x20: "MI_STORE_DATA_IMM",
       0x21: "MI_STORE_DATA_INDEX",
       0x22: "MI_LOAD_REGISTER_IMM",
       0x24: "MI_STORE_REGISTER_MEM",
       0x31: "MI_BATCH_BUFFER_START",
}

cmds_2d = {
       0x01: "XY_SETUP_BLT",
       0x03: "XY_SETUP_CLIP_BLT",
       0x11: "XY_SETUP_MONO_PATTERN_SL_BLT",
       0x24: "XY_PIXEL_BLT",
       0x25: "XY_SCANLINE_BLT",
       0x26: "XY_TEXT_BLT",
       0x31: "XY_TEXT_IMMEDIATE_BLT",
       0x40: "COLOR_BLT",
       0x43: "SRC_COPY_BLT",
       0x50: "XY_COLOR_BLT",
       0x51: "XY_PAT_BLT",
       0x52: "XY_MONO_PAT_BLT",
       0x53: "XY_SRC_COPY_BLT",
       0x54: "XY_MONO_SRC_COPY_BLT",
       0x55: "XY_FULL_BLT",
       0x56: "XY_FULL_MONO_SRC_BLT",
       0x57: "XY_FULL_MONO_PATTERN_BLT",
       0x58: "XY_FULL_MONO_PATTERN_MONO_SRC_BLT",
       0x59: "XY_MONO_PAT_FIXED_BLT",
       0x71: "XY_MONO_SRC_COPY_IMMEDIATE_BLT",
       0x72: "XY_PAT_BLT_IMMEDIATE",
       0x73: "XY_SRC_COPY_CHROMA_BLT",
       0x74: "XY_FULL_IMMEDIATE_PATTERN_BLT",
       0x75: "XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT",
       0x76: "XY_PAT_CHROMA_BLT",
       0x77: "XY_PAT_CHROMA_BLT_IMMEDIATE",
}

# cmds_3d[Pipeline Type][Opcode][Sub-opcode]
cmds_3d = {
	# Pipeline Type 00 (Common)
	00: {
		0: {
			0x00: "URB_FENCE",
			0x01: "CS_URB_STATE",
			0x02: "CONSTANT_BUFFER",
			0x03: "STATE_PREFETCH",
		},
		1: {
			0x01: "STATE_BASE_ADDRESS",
			0x02: "STATE_SIP", 
			0x04: "PIPELINE_SELECT",
		},
	},

	# Pipeline Type 01 (Single DW)
	01: {
		1: {
			0x04: "PIPELINE_SELECT",
		},
	},

	# Pipeline Type 02 (Media)
	02: {
		0: {
			0x00: "MEDIA_STATE_POINTERS",
		},
		1: {
			0x00: "MEDIA_OBJECT",
			0x01: "MEDIA_OBJECT_EX",
			0x02: "MEDIA_OBJECT_PTR",
		},
	},

	# Pipeline Type 03 (3D
	03: {
		0: {
			0x00: "3DSTATE_PIPELINED_POINTERS",
			0x01: "3DSTATE_BINDING_TABLE_POINTERS",
			0x05: "3DSTATE_URB",

			0x08: "3DSTATE_VERTEX_BUFFERS",
			0x09: "3DSTATE_VERTEX_ELEMENTS",
			0x10: "3DSTATE_INDEX_BUFFER",
			0x11: "3DSTATE_VF_STATISTICS",
			0x0d: "3DSTATE_VIEWPORT_STATE_POINTERS",
		},
		1: {
			0x00: "3DSTATE_DRAWING_RECTANGLE",
			0x01: "3DSTATE_CONSTANT_COLOR",
			0x02: "3DSTATE_SAMPLER_PALETTE_LOAD0",
			0x04: "3DSTATE_CHROMA_KEY",
			0x05: "3DSTATE_DEPTH_BUFFER",
			0x06: "3DSTATE_POLY_STIPPLE_OFFSET",
			0x07: "3DSTATE_POLY_STIPPLE_PATTERN",

			0x08: "3DSTATE_LINE_STIPPLE",
			0x09: "3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP",
		},
		2: {
			0x00: "PIPE_CONTROL",
		},
		3: {
			0x00: "3DPRIMITIVE",
		},
	}
}

one_word_cmds = [
	(03, 0, 0x11), # 3DSTATE_VF_STATISTICS
	(00, 1, 0x04), # PIPELINE_SELECT
]




def read_dump(file):
	data = []
	for l in file:
		v = l.split()[2]
		v = int(v, 16)
		data.append(v)
	return data

def parse_instruction(stream):
	cmd = stream[0]
	type = (cmd >> 29) & 0x7
	if type == 0:		# MI
		opcode = (cmd >> 23) & 0x3f

		if opcode < 0x10:
			count = 1
		else:
			count = (cmd & 0x3f) + 2
		#if opcode == 0x00 and cmd != 0x00000000:
	#		count = -1

	elif type == 2:		# 2D
		opcode = (cmd >> 22) & 0x78f
		count = (cmd & 0x1f) + 2

	elif type == 3:		# 3D
		pipeline_type = (cmd >> 27) & 0x3
		opcode = (cmd >> 24) & 0x7
		subopcode = (cmd >> 16) & 0xff
		combined = (pipeline_type, opcode, subopcode)
		if combined in one_word_cmds:
			count = 1
		else:
			count = (cmd & 0xff) + 2

		return (count, type, combined)
	
	else:
		return (1, type, 1)
		#raise "Invalid instruction type %d" % type
	
	return (count, type, opcode)

def get_cmd_name(type, opcode):
	if type == 3:
		(pipeline, opcode, subop) = opcode
		if cmds_3d.has_key(pipeline) and cmds_3d[pipeline].has_key(opcode) and cmds_3d[pipeline][opcode].has_key(subop):
			name = cmds_3d[pipeline][opcode][subop]
		else:
			name = "3D Reserved"
	elif type == 0:
		if cmds_mi.has_key(opcode):
			name = cmds_mi[opcode]
		else:
			name = "MI Reserved"
	elif type == 2:
		if cmds_2d.has_key(opcode):
			name = cmds_2d[opcode]
		else:
			name = "2D Reserved"
	else:
		name = "Unknown"
	return name

def dump_stream(stream, markers={}):
	stop = False
	i = 0
	while i < len(stream)-1 and not stop:
		(count, type, opcode) = parse_instruction(stream[i:-1])
		print "%08x\t%s\t" % (4*i, get_cmd_name(type, opcode).ljust(25)),

		print '[ ',
		for n in range(count):
			print " %08x" % stream[(i+n) % len(stream)],
		print ' ] ',

		if markers.has_key(i):
			print markers[i],

		if type == 0 and opcode == 0x09:	# End batch buffer
			stop = True

		if type == 0 and opcode == 0x31:	# Start batch buffer
			addr_type = stream[i] & (1 << 7)
			addr = stream[i+1] & ~0x3	
			print "batch  (%08x)" % addr
			if addr_type and batches.has_key(addr):
				print "{"
				batch = read_dump(batches[addr])
				dump_stream(batch, markers)
				print "}"

		print 
		i += count


ringbuf = open(root + 'i915_gem_ringbuf', 'r')
data = read_dump(ringbuf)
ringbuf.close()

execinfo = open(root + 'i915_execinfo', 'r')
for l in execinfo:
	s = l.split()
	if re.match('RingHead', l):
		ring_head = int(s[2], 16)
	elif re.match('RingTail', l):
		ring_tail = int(s[2], 16)
	elif re.match('RingSize', l):
		ring_size = int(s[2], 16)
	elif re.match('Acthd', l):
		acthd = int(s[2], 16)
execinfo.close()

batches = { }
for file in glob.glob(root + 'i915_batchbuffer*'):
	f = open(file, 'r')
	l = f.readline()
	m = re.match('GttOffset=([0-9a-f]+)', l)
	gtt_offset = int(m.group(1), 16)
	batches[gtt_offset] = f
	print "Batch buffer %08x" % gtt_offset


markers = {
	ring_tail: 'TAIL',
	ring_head: 'HEAD',
	acthd: 'ACTHD'
}
print 'head: %08x' % ring_head
dump_stream(data, markers)




More information about the Intel-gfx mailing list