linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and
@ 2010-02-15 14:46 Bernie Thompson
  2010-02-18 15:57 ` Greg KH
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Bernie Thompson @ 2010-02-15 14:46 UTC (permalink / raw)
  To: linux-fbdev

Add sysfs controls for edid and performance metrics

There are 8 new files exposed in /sys/class/graphics/fb*

edid - returns 128 byte edid blog, suitable for parsing with parse-edid
metrics_bytes_identical
metrics_bytes_rendered
metrics_bytes_sent
metrics_cpu_kcycles_used
metrics_misc
and metrics_reset, which resets all perf metrics to zero

The 6 perf metrics are of type atomic_t.
So these metrics return precise results for short benchmarks, but
any test approx a minute or longer runtime may roll over.

Signed-off-by: Bernie Thompson <bernie@plugable.com>

---
 drivers/staging/udlfb/udlfb.c |  251 ++++++++++++++++++++++++++++++++++++++++++
 drivers/staging/udlfb/udlfb.h |   18 +++
 2 files changed, 269 insertions(+)

Index: linux-next/drivers/staging/udlfb/udlfb.c
=================================--- linux-next.orig/drivers/staging/udlfb/udlfb.c	2010-02-14 20:26:54.000000000 -0800
+++ linux-next/drivers/staging/udlfb/udlfb.c	2010-02-14 20:26:56.000000000 -0800
@@ -818,6 +818,21 @@ static void dlfb_ops_fillrect(struct fb_
 
 }
 
+static void dlfb_get_edid(struct dlfb_data *dev)
+{
+	int i;
+	int ret;
+	char rbuf[2];
+
+	for (i = 0; i < sizeof(dev->edid); i++) {
+		ret = usb_control_msg(dev->udev,
+				    usb_rcvctrlpipe(dev->udev, 0), (0x02),
+				    (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+				    0);
+		dev->edid[i] = rbuf[1];
+	}
+}
+
 static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -924,6 +939,33 @@ static void dlfb_delete(struct kref *kre
 	kfree(dev);
 }
 
+/*
+ * Check whether a video mode is supported by the DisplayLink chip
+ * We start from monitor's modes, so don't need to filter that here
+ */
+static int dlfb_is_valid_mode(struct fb_videomode *mode,
+		struct fb_info *info)
+{
+	struct dlfb_data *dev = info->par;
+
+	if (mode->xres * mode->yres > dev->sku_pixel_limit)
+		return 0;
+
+	return 1;
+}
+
+static void dlfb_var_color_format(struct fb_var_screeninfo *var)
+{
+	const struct fb_bitfield red = { 11, 5, 0 };
+	const struct fb_bitfield green = { 5, 6, 0 };
+	const struct fb_bitfield blue = { 0, 5, 0 };
+
+	var->bits_per_pixel = 16;
+	var->red = red;
+	var->green = green;
+	var->blue = blue;
+}
+
 static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
 {
 	struct dlfb_data *dev_info = info->par;
@@ -954,6 +996,215 @@ static struct fb_ops dlfb_ops = {
 };
 
 /*
+ * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
+ * Then parses EDID into three places used by various parts of fbdev:
+ * fb_var_screeninfo contains the timing of the monitor's preferred mode
+ * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
+ * fb_info.modelist is a linked list of all monitor & VESA modes which work
+ *
+ * If EDID is not readable/valid, then modelist is all VESA modes,
+ * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
+ * Returns 0 if EDID parses successfully
+ */
+static int dlfb_parse_edid(struct dlfb_data *dev,
+			    struct fb_var_screeninfo *var,
+			    struct fb_info *info)
+{
+	int i;
+	const struct fb_videomode *default_vmode = NULL;
+	int result = 0;
+
+	fb_destroy_modelist(&info->modelist);
+	memset(&info->monspecs, 0, sizeof(info->monspecs));
+
+	dlfb_get_edid(dev);
+	fb_edid_to_monspecs(dev->edid, &info->monspecs);
+
+	if (info->monspecs.modedb_len > 0) {
+
+		for (i = 0; i < info->monspecs.modedb_len; i++) {
+			if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
+				fb_add_videomode(&info->monspecs.modedb[i],
+					&info->modelist);
+		}
+
+		default_vmode = fb_find_best_display(&info->monspecs,
+						     &info->modelist);
+	} else {
+		struct fb_videomode fb_vmode = {0};
+
+		dl_err("Unable to get valid EDID from device/display\n");
+		result = 1;
+
+		/*
+		 * Add the standard VESA modes to our modelist
+		 * Since we don't have EDID, there may be modes that
+		 * overspec monitor and/or are incorrect aspect ratio, etc.
+		 * But at least the user has a chance to choose
+		 */
+		for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+			if (dlfb_is_valid_mode((struct fb_videomode *)
+						&vesa_modes[i], info))
+				fb_add_videomode(&vesa_modes[i],
+						 &info->modelist);
+		}
+
+		/*
+		 * default to resolution safe for projectors
+		 * (since they are most common case without EDID)
+		 */
+		fb_vmode.xres = 800;
+		fb_vmode.yres = 600;
+		fb_vmode.refresh = 60;
+		default_vmode = fb_find_nearest_mode(&fb_vmode,
+						     &info->modelist);
+	}
+
+	fb_videomode_to_var(var, default_vmode);
+	dlfb_var_color_format(var);
+
+	return result;
+}
+
+static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
+				   struct device_attribute *a, char *buf) {
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			atomic_read(&dev->bytes_rendered));
+}
+
+static ssize_t metrics_bytes_identical_show(struct device *fbdev,
+				   struct device_attribute *a, char *buf) {
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			atomic_read(&dev->bytes_identical));
+}
+
+static ssize_t metrics_bytes_sent_show(struct device *fbdev,
+				   struct device_attribute *a, char *buf) {
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			atomic_read(&dev->bytes_sent));
+}
+
+static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
+				   struct device_attribute *a, char *buf) {
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			atomic_read(&dev->cpu_kcycles_used));
+}
+
+static ssize_t metrics_misc_show(struct device *fbdev,
+				   struct device_attribute *a, char *buf) {
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	return snprintf(buf, PAGE_SIZE,
+			"Calls to\ndamage: %u\nblit: %u\n"
+			"defio faults: %u\ncopy: %u\n"
+			"fill: %u\n\n"
+			"active framebuffer clients: %d\n"
+			"urbs available %d(%d)\n"
+			"Shadow framebuffer in use? %s\n"
+			"Any lost pixels? %s\n",
+			atomic_read(&dev->damage_count),
+			atomic_read(&dev->blit_count),
+			atomic_read(&dev->defio_fault_count),
+			atomic_read(&dev->copy_count),
+			atomic_read(&dev->fill_count),
+			dev->fb_count,
+			dev->urbs.available, dev->urbs.limit_sem.count,
+			(dev->backing_buffer) ? "yes" : "no",
+			atomic_read(&dev->lost_pixels) ? "yes" : "no");
+}
+
+static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
+			 char *buf, loff_t off, size_t count) {
+	struct device *fbdev = container_of(kobj, struct device, kobj);
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	char *edid = &dev->edid[0];
+	const size_t size = sizeof(dev->edid);
+
+	if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
+		return 0;
+
+	if (off >= size)
+		return 0;
+
+	if (off + count > size)
+		count = size - off;
+	memcpy(buf, edid + off, count);
+
+	return count;
+}
+
+
+static ssize_t metrics_reset_store(struct device *fbdev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+
+	atomic_set(&dev->bytes_rendered, 0);
+	atomic_set(&dev->bytes_identical, 0);
+	atomic_set(&dev->bytes_sent, 0);
+	atomic_set(&dev->cpu_kcycles_used, 0);
+	atomic_set(&dev->blit_count, 0);
+	atomic_set(&dev->copy_count, 0);
+	atomic_set(&dev->fill_count, 0);
+	atomic_set(&dev->defio_fault_count, 0);
+	atomic_set(&dev->damage_count, 0);
+
+	return count;
+}
+
+static ssize_t use_defio_show(struct device *fbdev,
+				   struct device_attribute *a, char *buf) {
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&dev->use_defio));
+}
+
+static ssize_t use_defio_store(struct device *fbdev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+	struct dlfb_data *dev = fb_info->par;
+
+	if (count > 0) {
+		if (buf[0] = '0')
+			atomic_set(&dev->use_defio, 0);
+		if (buf[0] = '1')
+			atomic_set(&dev->use_defio, 1);
+	}
+	return count;
+}
+
+static struct bin_attribute edid_attr = {
+	.attr.name = "edid",
+	.attr.mode = 0444,
+	.size = 128,
+	.read = edid_show,
+};
+
+static struct device_attribute fb_device_attrs[] = {
+	__ATTR_RO(metrics_bytes_rendered),
+	__ATTR_RO(metrics_bytes_identical),
+	__ATTR_RO(metrics_bytes_sent),
+	__ATTR_RO(metrics_cpu_kcycles_used),
+	__ATTR_RO(metrics_misc),
+	__ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+	__ATTR_RW(use_defio),
+};
+
+/*
  * This is necessary before we can communicate with the display controller.
  */
 static int dlfb_select_std_channel(struct dlfb_data *dev)
Index: linux-next/drivers/staging/udlfb/udlfb.h
=================================--- linux-next.orig/drivers/staging/udlfb/udlfb.h	2010-02-14 20:26:52.000000000 -0800
+++ linux-next/drivers/staging/udlfb/udlfb.h	2010-02-14 20:26:56.000000000 -0800
@@ -33,8 +33,12 @@ struct dlfb_data {
 	char *bufend;
 	char *backing_buffer;
 	struct mutex bulk_mutex;
+	int fb_count;
+	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
 	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+	atomic_t use_defio; /* 0 = rely on ioctls and blit/copy/fill rects */
 	char edid[128];
+	int sku_pixel_limit;
 	int screen_size;
 	int line_length;
 	struct completion done;
@@ -43,6 +47,17 @@ struct dlfb_data {
 	int base8;
 	int base8d;
 	u32 pseudo_palette[256];
+	/* blit-only rendering path metrics, exposed through sysfs */
+	atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
+	atomic_t bytes_identical; /* saved effort with backbuffer comparison */
+	atomic_t bytes_sent; /* to usb, after compression including overhead */
+	atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+	/* interface usage metrics. Clients can call driver via several */
+	atomic_t blit_count;
+	atomic_t copy_count;
+	atomic_t fill_count;
+	atomic_t damage_count;
+	atomic_t defio_fault_count;
 };
 
 #define NR_USB_REQUEST_I2C_SUB_IO 0x02
@@ -99,6 +114,9 @@ static int dlfb_bulk_msg(struct dlfb_dat
 
 #define dlfb_set_register insert_command
 
+/* remove once this gets added to sysfs.h */
+#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
+
 #define dl_err(format, arg...) \
 	dev_err(dev->gdev, "dlfb: " format, ## arg)
 #define dl_warn(format, arg...) \



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and
  2010-02-15 14:46 [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and Bernie Thompson
@ 2010-02-18 15:57 ` Greg KH
  2010-02-18 23:03 ` Bernie Thompson
  2010-02-19  0:31 ` Greg KH
  2 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2010-02-18 15:57 UTC (permalink / raw)
  To: linux-fbdev

On Mon, Feb 15, 2010 at 06:46:08AM -0800, Bernie Thompson wrote:
> Add sysfs controls for edid and performance metrics
> 
> There are 8 new files exposed in /sys/class/graphics/fb*

All new sysfs files will need a Documentation/ABI/ patch as well to
explain the files.

> 
> edid - returns 128 byte edid blog, suitable for parsing with parse-edid
> metrics_bytes_identical
> metrics_bytes_rendered
> metrics_bytes_sent
> metrics_cpu_kcycles_used

These are all single value files, which is fine.

> metrics_misc

This isn't.  sysfs files are "one value per file".  If you want to do
something else, like this file, I suggest using debugfs instead.

> and metrics_reset, which resets all perf metrics to zero

Actually, why not use debugfs for all of these files?  They aren't
really necessary for any user or tool, and are only a debugging thing.
That's what debugfs was created for :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and
  2010-02-15 14:46 [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and Bernie Thompson
  2010-02-18 15:57 ` Greg KH
@ 2010-02-18 23:03 ` Bernie Thompson
  2010-02-19  0:31 ` Greg KH
  2 siblings, 0 replies; 4+ messages in thread
From: Bernie Thompson @ 2010-02-18 23:03 UTC (permalink / raw)
  To: linux-fbdev

Hi Greg,

On Thu, Feb 18, 2010 at 7:57 AM, Greg KH <greg@kroah.com> wrote:

> All new sysfs files will need a Documentation/ABI/ patch as well to
> explain the files.

I'll construct an additional patch to document the edid file (this
aught to be a standardized thing for all framebuffers, anyway - and
others have done similar/same).

And I'll do a separate one for the individual metrics if they're kept
in sysfs in the future.

>> metrics_misc
>
> This isn't.  sysfs files are "one value per file".  If you want to do
> something else, like this file, I suggest using debugfs instead.

The metrics stuff is a good candidate for moving to debugfs, I guess,
in a future patch. For now, anything in that set which violates sysfs
guidelines (metrics_misc) aught to just be removed, I guess.

These metrics have already been very helpful for comparing different
rendering algorithms, for debugging, and it's very helpful for
gathering info from end-users that may not have anything other than
sysfs set up. There are so many different hardware/software scenarios
that there's often no way to have any sense of what's happening
without more detailed instrumentation like this.

Best wishes,
Bernie
http://plugable.com/

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and
  2010-02-15 14:46 [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and Bernie Thompson
  2010-02-18 15:57 ` Greg KH
  2010-02-18 23:03 ` Bernie Thompson
@ 2010-02-19  0:31 ` Greg KH
  2 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2010-02-19  0:31 UTC (permalink / raw)
  To: linux-fbdev

On Thu, Feb 18, 2010 at 03:03:37PM -0800, Bernie Thompson wrote:
> Hi Greg,
> 
> On Thu, Feb 18, 2010 at 7:57 AM, Greg KH <greg@kroah.com> wrote:
> 
> > All new sysfs files will need a Documentation/ABI/ patch as well to
> > explain the files.
> 
> I'll construct an additional patch to document the edid file (this
> aught to be a standardized thing for all framebuffers, anyway - and
> others have done similar/same).

If it's a standard framebuffer file, it should be documented already.
If not, that's a simple patch to get upstream :)

> And I'll do a separate one for the individual metrics if they're kept
> in sysfs in the future.

thanks, but I don't think they should be, and it looks like you don't
either.

> >> metrics_misc
> >
> > This isn't.  sysfs files are "one value per file".  If you want to do
> > something else, like this file, I suggest using debugfs instead.
> 
> The metrics stuff is a good candidate for moving to debugfs, I guess,
> in a future patch. For now, anything in that set which violates sysfs
> guidelines (metrics_misc) aught to just be removed, I guess.
> 
> These metrics have already been very helpful for comparing different
> rendering algorithms, for debugging, and it's very helpful for
> gathering info from end-users that may not have anything other than
> sysfs set up. There are so many different hardware/software scenarios
> that there's often no way to have any sense of what's happening
> without more detailed instrumentation like this.

Then use debugfs for this, that is what it is explicitly for.  All
distros mount the thing now, so you can easily get information from it
from people who do not build their own kernels.  It's quite powerful.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-02-19  0:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-15 14:46 [PATCH 5/10] udlfb: Add functions to expose sysfs metrics and Bernie Thompson
2010-02-18 15:57 ` Greg KH
2010-02-18 23:03 ` Bernie Thompson
2010-02-19  0:31 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).