Commit ad0992e9 authored by Mike Isely's avatar Mike Isely Committed by Mauro Carvalho Chehab

V4L/DVB (7699): pvrusb2: Implement statistics for USB I/O performance / tracking

Implement a mechanism in the pvrusb2 driver for gathering statistics
on the stream buffering, including bytes transferred, buffers handled,
buffers in flight, etc.  This is useful for debugging certain classes
of streaming issues and for determining if the buffer pool size is
generally correct for the driver.
Signed-off-by: default avatarMike Isely <isely@pobox.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent be9cbb7c
...@@ -164,6 +164,8 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, ...@@ -164,6 +164,8 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
int ccnt; int ccnt;
int ret; int ret;
u32 gpio_dir,gpio_in,gpio_out; u32 gpio_dir,gpio_in,gpio_out;
struct pvr2_stream_stats stats;
struct pvr2_stream *sp;
ret = pvr2_hdw_is_hsm(hdw); ret = pvr2_hdw_is_hsm(hdw);
ccnt = scnprintf(buf,acnt,"USB link speed: %s\n", ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
...@@ -182,6 +184,24 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, ...@@ -182,6 +184,24 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
pvr2_hdw_get_streaming(hdw) ? "on" : "off"); pvr2_hdw_get_streaming(hdw) ? "on" : "off");
bcnt += ccnt; acnt -= ccnt; buf += ccnt; bcnt += ccnt; acnt -= ccnt; buf += ccnt;
sp = pvr2_hdw_get_video_stream(hdw);
if (sp) {
pvr2_stream_get_stats(sp, &stats, 0);
ccnt = scnprintf(
buf,acnt,
"Bytes streamed=%u"
" URBs: queued=%u idle=%u ready=%u"
" processed=%u failed=%u\n",
stats.bytes_processed,
stats.buffers_in_queue,
stats.buffers_in_idle,
stats.buffers_in_ready,
stats.buffers_processed,
stats.buffers_failed);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
}
return bcnt; return bcnt;
} }
...@@ -220,6 +240,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, ...@@ -220,6 +240,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
return pvr2_hdw_cmd_decoder_reset(hdw); return pvr2_hdw_cmd_decoder_reset(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"worker")) { } else if (debugifc_match_keyword(wptr,wlen,"worker")) {
return pvr2_hdw_untrip(hdw); return pvr2_hdw_untrip(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"usbstats")) {
pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw),
NULL, !0);
return 0;
} }
return -EINVAL; return -EINVAL;
} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
......
...@@ -3806,6 +3806,24 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, ...@@ -3806,6 +3806,24 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
buf,acnt, buf,acnt,
"state: %s", "state: %s",
pvr2_get_state_name(hdw->master_state)); pvr2_get_state_name(hdw->master_state));
case 4: {
struct pvr2_stream_stats stats;
if (!hdw->vid_stream) break;
pvr2_stream_get_stats(hdw->vid_stream,
&stats,
0);
return scnprintf(
buf,acnt,
"Bytes streamed=%u"
" URBs: queued=%u idle=%u ready=%u"
" processed=%u failed=%u",
stats.bytes_processed,
stats.buffers_in_queue,
stats.buffers_in_idle,
stats.buffers_in_ready,
stats.buffers_processed,
stats.buffers_failed);
}
default: break; default: break;
} }
return 0; return 0;
......
...@@ -80,6 +80,10 @@ struct pvr2_stream { ...@@ -80,6 +80,10 @@ struct pvr2_stream {
/* Tracking state for tolerating errors */ /* Tracking state for tolerating errors */
unsigned int fail_count; unsigned int fail_count;
unsigned int fail_tolerance; unsigned int fail_tolerance;
unsigned int buffers_processed;
unsigned int buffers_failed;
unsigned int bytes_processed;
}; };
struct pvr2_buffer { struct pvr2_buffer {
...@@ -446,6 +450,8 @@ static void buffer_complete(struct urb *urb) ...@@ -446,6 +450,8 @@ static void buffer_complete(struct urb *urb)
(urb->status == -ENOENT) || (urb->status == -ENOENT) ||
(urb->status == -ECONNRESET) || (urb->status == -ECONNRESET) ||
(urb->status == -ESHUTDOWN)) { (urb->status == -ESHUTDOWN)) {
(sp->buffers_processed)++;
sp->bytes_processed += urb->actual_length;
bp->used_count = urb->actual_length; bp->used_count = urb->actual_length;
if (sp->fail_count) { if (sp->fail_count) {
pvr2_trace(PVR2_TRACE_TOLERANCE, pvr2_trace(PVR2_TRACE_TOLERANCE,
...@@ -457,11 +463,13 @@ static void buffer_complete(struct urb *urb) ...@@ -457,11 +463,13 @@ static void buffer_complete(struct urb *urb)
// We can tolerate this error, because we're below the // We can tolerate this error, because we're below the
// threshold... // threshold...
(sp->fail_count)++; (sp->fail_count)++;
(sp->buffers_failed)++;
pvr2_trace(PVR2_TRACE_TOLERANCE, pvr2_trace(PVR2_TRACE_TOLERANCE,
"stream %p ignoring error %d" "stream %p ignoring error %d"
" - fail count increased to %u", " - fail count increased to %u",
sp,urb->status,sp->fail_count); sp,urb->status,sp->fail_count);
} else { } else {
(sp->buffers_failed)++;
bp->status = urb->status; bp->status = urb->status;
} }
spin_unlock_irqrestore(&sp->list_lock,irq_flags); spin_unlock_irqrestore(&sp->list_lock,irq_flags);
...@@ -515,6 +523,28 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp, ...@@ -515,6 +523,28 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp,
} while(0); mutex_unlock(&sp->mutex); } while(0); mutex_unlock(&sp->mutex);
} }
void pvr2_stream_get_stats(struct pvr2_stream *sp,
struct pvr2_stream_stats *stats,
int zero_counts)
{
unsigned long irq_flags;
spin_lock_irqsave(&sp->list_lock,irq_flags);
if (stats) {
stats->buffers_in_queue = sp->q_count;
stats->buffers_in_idle = sp->i_count;
stats->buffers_in_ready = sp->r_count;
stats->buffers_processed = sp->buffers_processed;
stats->buffers_failed = sp->buffers_failed;
stats->bytes_processed = sp->bytes_processed;
}
if (zero_counts) {
sp->buffers_processed = 0;
sp->buffers_failed = 0;
sp->bytes_processed = 0;
}
spin_unlock_irqrestore(&sp->list_lock,irq_flags);
}
/* Query / set the nominal buffer count */ /* Query / set the nominal buffer count */
int pvr2_stream_get_buffer_count(struct pvr2_stream *sp) int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
{ {
......
...@@ -36,6 +36,15 @@ enum pvr2_buffer_state { ...@@ -36,6 +36,15 @@ enum pvr2_buffer_state {
struct pvr2_stream; struct pvr2_stream;
struct pvr2_buffer; struct pvr2_buffer;
struct pvr2_stream_stats {
unsigned int buffers_in_queue;
unsigned int buffers_in_idle;
unsigned int buffers_in_ready;
unsigned int buffers_processed;
unsigned int buffers_failed;
unsigned int bytes_processed;
};
/* Initialize / tear down stream structure */ /* Initialize / tear down stream structure */
struct pvr2_stream *pvr2_stream_create(void); struct pvr2_stream *pvr2_stream_create(void);
void pvr2_stream_destroy(struct pvr2_stream *); void pvr2_stream_destroy(struct pvr2_stream *);
...@@ -45,6 +54,9 @@ void pvr2_stream_setup(struct pvr2_stream *, ...@@ -45,6 +54,9 @@ void pvr2_stream_setup(struct pvr2_stream *,
void pvr2_stream_set_callback(struct pvr2_stream *, void pvr2_stream_set_callback(struct pvr2_stream *,
pvr2_stream_callback func, pvr2_stream_callback func,
void *data); void *data);
void pvr2_stream_get_stats(struct pvr2_stream *,
struct pvr2_stream_stats *,
int zero_counts);
/* Query / set the nominal buffer count */ /* Query / set the nominal buffer count */
int pvr2_stream_get_buffer_count(struct pvr2_stream *); int pvr2_stream_get_buffer_count(struct pvr2_stream *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment