aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
authorAlexey Fisher <bug-track@fisher-privat.net>2011-11-03 10:40:08 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-12-11 08:22:08 -0500
commit7bc5edb00bbd02449576289a50d2900f58e7187a (patch)
treefe0dc70fcceed75d72e10fc9869ecd90f7b8c057 /drivers/media/video/uvc
parentedbaa39842793fc4ac6603b277f2ad76f2057a45 (diff)
[media] uvcvideo: Extract video stream statistics
Export the statistics through debugfs. Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_debugfs.c63
-rw-r--r--drivers/media/video/uvc/uvc_video.c109
-rw-r--r--drivers/media/video/uvc/uvcvideo.h32
3 files changed, 199 insertions, 5 deletions
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c
index 39fd43b3e1d2..14561a5abb79 100644
--- a/drivers/media/video/uvc/uvc_debugfs.c
+++ b/drivers/media/video/uvc/uvc_debugfs.c
@@ -19,6 +19,57 @@
19#include "uvcvideo.h" 19#include "uvcvideo.h"
20 20
21/* ----------------------------------------------------------------------------- 21/* -----------------------------------------------------------------------------
22 * Statistics
23 */
24
25#define UVC_DEBUGFS_BUF_SIZE 1024
26
27struct uvc_debugfs_buffer {
28 size_t count;
29 char data[UVC_DEBUGFS_BUF_SIZE];
30};
31
32static int uvc_debugfs_stats_open(struct inode *inode, struct file *file)
33{
34 struct uvc_streaming *stream = inode->i_private;
35 struct uvc_debugfs_buffer *buf;
36
37 buf = kmalloc(sizeof(*buf), GFP_KERNEL);
38 if (buf == NULL)
39 return -ENOMEM;
40
41 buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data));
42
43 file->private_data = buf;
44 return 0;
45}
46
47static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf,
48 size_t nbytes, loff_t *ppos)
49{
50 struct uvc_debugfs_buffer *buf = file->private_data;
51
52 return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data,
53 buf->count);
54}
55
56static int uvc_debugfs_stats_release(struct inode *inode, struct file *file)
57{
58 kfree(file->private_data);
59 file->private_data = NULL;
60
61 return 0;
62}
63
64static const struct file_operations uvc_debugfs_stats_fops = {
65 .owner = THIS_MODULE,
66 .open = uvc_debugfs_stats_open,
67 .llseek = no_llseek,
68 .read = uvc_debugfs_stats_read,
69 .release = uvc_debugfs_stats_release,
70};
71
72/* -----------------------------------------------------------------------------
22 * Global and stream initialization/cleanup 73 * Global and stream initialization/cleanup
23 */ 74 */
24 75
@@ -37,13 +88,21 @@ int uvc_debugfs_init_stream(struct uvc_streaming *stream)
37 88
38 dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); 89 dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir);
39 if (IS_ERR_OR_NULL(dent)) { 90 if (IS_ERR_OR_NULL(dent)) {
40 uvc_printk(KERN_INFO, "Unable to create debugfs %s directory.\n", 91 uvc_printk(KERN_INFO, "Unable to create debugfs %s "
41 dir_name); 92 "directory.\n", dir_name);
42 return -ENODEV; 93 return -ENODEV;
43 } 94 }
44 95
45 stream->debugfs_dir = dent; 96 stream->debugfs_dir = dent;
46 97
98 dent = debugfs_create_file("stats", 0444, stream->debugfs_dir,
99 stream, &uvc_debugfs_stats_fops);
100 if (IS_ERR_OR_NULL(dent)) {
101 uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n");
102 uvc_debugfs_cleanup_stream(stream);
103 return -ENODEV;
104 }
105
47 return 0; 106 return 0;
48} 107}
49 108
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index a57f81341849..1908dd859433 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -358,6 +358,100 @@ static int uvc_commit_video(struct uvc_streaming *stream,
358} 358}
359 359
360/* ------------------------------------------------------------------------ 360/* ------------------------------------------------------------------------
361 * Stream statistics
362 */
363
364static void uvc_video_stats_decode(struct uvc_streaming *stream,
365 const __u8 *data, int len)
366{
367 unsigned int header_size;
368
369 if (stream->stats.stream.nb_frames == 0 &&
370 stream->stats.frame.nb_packets == 0)
371 ktime_get_ts(&stream->stats.stream.start_ts);
372
373 switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
374 case UVC_STREAM_PTS | UVC_STREAM_SCR:
375 header_size = 12;
376 break;
377 case UVC_STREAM_PTS:
378 header_size = 6;
379 break;
380 case UVC_STREAM_SCR:
381 header_size = 8;
382 break;
383 default:
384 header_size = 2;
385 break;
386 }
387
388 /* Check for invalid headers. */
389 if (len < header_size || data[0] < header_size) {
390 stream->stats.frame.nb_invalid++;
391 return;
392 }
393
394 /* Record the first non-empty packet number. */
395 if (stream->stats.frame.size == 0 && len > header_size)
396 stream->stats.frame.first_data = stream->stats.frame.nb_packets;
397
398 /* Update the frame size. */
399 stream->stats.frame.size += len - header_size;
400
401 /* Update the packets counters. */
402 stream->stats.frame.nb_packets++;
403 if (len > header_size)
404 stream->stats.frame.nb_empty++;
405
406 if (data[1] & UVC_STREAM_ERR)
407 stream->stats.frame.nb_errors++;
408}
409
410static void uvc_video_stats_update(struct uvc_streaming *stream)
411{
412 struct uvc_stats_frame *frame = &stream->stats.frame;
413
414 uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets\n",
415 stream->sequence, frame->first_data,
416 frame->nb_packets - frame->nb_empty, frame->nb_packets);
417
418 stream->stats.stream.nb_frames++;
419 stream->stats.stream.nb_packets += stream->stats.frame.nb_packets;
420 stream->stats.stream.nb_empty += stream->stats.frame.nb_empty;
421 stream->stats.stream.nb_errors += stream->stats.frame.nb_errors;
422 stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid;
423
424 memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
425}
426
427size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
428 size_t size)
429{
430 size_t count = 0;
431
432 count += scnprintf(buf + count, size - count,
433 "frames: %u\npackets: %u\nempty: %u\n"
434 "errors: %u\ninvalid: %u\n",
435 stream->stats.stream.nb_frames,
436 stream->stats.stream.nb_packets,
437 stream->stats.stream.nb_empty,
438 stream->stats.stream.nb_errors,
439 stream->stats.stream.nb_invalid);
440
441 return count;
442}
443
444static void uvc_video_stats_start(struct uvc_streaming *stream)
445{
446 memset(&stream->stats, 0, sizeof(stream->stats));
447}
448
449static void uvc_video_stats_stop(struct uvc_streaming *stream)
450{
451 ktime_get_ts(&stream->stats.stream.stop_ts);
452}
453
454/* ------------------------------------------------------------------------
361 * Video codecs 455 * Video codecs
362 */ 456 */
363 457
@@ -406,16 +500,23 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
406 * - bHeaderLength value must be at least 2 bytes (see above) 500 * - bHeaderLength value must be at least 2 bytes (see above)
407 * - bHeaderLength value can't be larger than the packet size. 501 * - bHeaderLength value can't be larger than the packet size.
408 */ 502 */
409 if (len < 2 || data[0] < 2 || data[0] > len) 503 if (len < 2 || data[0] < 2 || data[0] > len) {
504 stream->stats.frame.nb_invalid++;
410 return -EINVAL; 505 return -EINVAL;
506 }
411 507
412 fid = data[1] & UVC_STREAM_FID; 508 fid = data[1] & UVC_STREAM_FID;
413 509
414 /* Increase the sequence number regardless of any buffer states, so 510 /* Increase the sequence number regardless of any buffer states, so
415 * that discontinuous sequence numbers always indicate lost frames. 511 * that discontinuous sequence numbers always indicate lost frames.
416 */ 512 */
417 if (stream->last_fid != fid) 513 if (stream->last_fid != fid) {
418 stream->sequence++; 514 stream->sequence++;
515 if (stream->sequence)
516 uvc_video_stats_update(stream);
517 }
518
519 uvc_video_stats_decode(stream, data, len);
419 520
420 /* Store the payload FID bit and return immediately when the buffer is 521 /* Store the payload FID bit and return immediately when the buffer is
421 * NULL. 522 * NULL.
@@ -860,6 +961,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
860 struct urb *urb; 961 struct urb *urb;
861 unsigned int i; 962 unsigned int i;
862 963
964 uvc_video_stats_stop(stream);
965
863 for (i = 0; i < UVC_URBS; ++i) { 966 for (i = 0; i < UVC_URBS; ++i) {
864 urb = stream->urb[i]; 967 urb = stream->urb[i];
865 if (urb == NULL) 968 if (urb == NULL)
@@ -999,6 +1102,8 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
999 stream->bulk.skip_payload = 0; 1102 stream->bulk.skip_payload = 0;
1000 stream->bulk.payload_size = 0; 1103 stream->bulk.payload_size = 0;
1001 1104
1105 uvc_video_stats_start(stream);
1106
1002 if (intf->num_altsetting > 1) { 1107 if (intf->num_altsetting > 1) {
1003 struct usb_host_endpoint *best_ep = NULL; 1108 struct usb_host_endpoint *best_ep = NULL;
1004 unsigned int best_psize = 3 * 1024; 1109 unsigned int best_psize = 3 * 1024;
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index d975636cbb10..f9ee62ed0150 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -356,6 +356,28 @@ struct uvc_video_chain {
356 struct mutex ctrl_mutex; /* Protects ctrl.info */ 356 struct mutex ctrl_mutex; /* Protects ctrl.info */
357}; 357};
358 358
359struct uvc_stats_frame {
360 unsigned int size; /* Number of bytes captured */
361 unsigned int first_data; /* Index of the first non-empty packet */
362
363 unsigned int nb_packets; /* Number of packets */
364 unsigned int nb_empty; /* Number of empty packets */
365 unsigned int nb_invalid; /* Number of packets with an invalid header */
366 unsigned int nb_errors; /* Number of packets with the error bit set */
367};
368
369struct uvc_stats_stream {
370 struct timespec start_ts; /* Stream start timestamp */
371 struct timespec stop_ts; /* Stream stop timestamp */
372
373 unsigned int nb_frames; /* Number of frames */
374
375 unsigned int nb_packets; /* Number of packets */
376 unsigned int nb_empty; /* Number of empty packets */
377 unsigned int nb_invalid; /* Number of packets with an invalid header */
378 unsigned int nb_errors; /* Number of packets with the error bit set */
379};
380
359struct uvc_streaming { 381struct uvc_streaming {
360 struct list_head list; 382 struct list_head list;
361 struct uvc_device *dev; 383 struct uvc_device *dev;
@@ -406,6 +428,10 @@ struct uvc_streaming {
406 428
407 /* debugfs */ 429 /* debugfs */
408 struct dentry *debugfs_dir; 430 struct dentry *debugfs_dir;
431 struct {
432 struct uvc_stats_frame frame;
433 struct uvc_stats_stream stream;
434 } stats;
409}; 435};
410 436
411enum uvc_device_state { 437enum uvc_device_state {
@@ -477,6 +503,7 @@ struct uvc_driver {
477#define UVC_TRACE_SUSPEND (1 << 8) 503#define UVC_TRACE_SUSPEND (1 << 8)
478#define UVC_TRACE_STATUS (1 << 9) 504#define UVC_TRACE_STATUS (1 << 9)
479#define UVC_TRACE_VIDEO (1 << 10) 505#define UVC_TRACE_VIDEO (1 << 10)
506#define UVC_TRACE_STATS (1 << 11)
480 507
481#define UVC_WARN_MINMAX 0 508#define UVC_WARN_MINMAX 0
482#define UVC_WARN_PROBE_DEF 1 509#define UVC_WARN_PROBE_DEF 1
@@ -609,10 +636,13 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
609void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, 636void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
610 struct uvc_buffer *buf); 637 struct uvc_buffer *buf);
611 638
612/* debugfs */ 639/* debugfs and statistics */
613int uvc_debugfs_init(void); 640int uvc_debugfs_init(void);
614void uvc_debugfs_cleanup(void); 641void uvc_debugfs_cleanup(void);
615int uvc_debugfs_init_stream(struct uvc_streaming *stream); 642int uvc_debugfs_init_stream(struct uvc_streaming *stream);
616void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream); 643void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
617 644
645size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
646 size_t size);
647
618#endif 648#endif