[Spice-devel] [PATCH spice-server 26/28] collect and print video stream statistics
Yonit Halperin
yhalperi at redhat.com
Tue Feb 26 10:04:12 PST 2013
---
server/mjpeg_encoder.c | 7 +++++
server/red_worker.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
index 7825955..b5faed6 100644
--- a/server/mjpeg_encoder.c
+++ b/server/mjpeg_encoder.c
@@ -167,6 +167,10 @@ struct MJpegEncoder {
MJpegEncoderRateControl rate_control;
MJpegEncoderRateControlCbs cbs;
void *cbs_opaque;
+
+ /* stats */
+ uint64_t avg_quality;
+ uint32_t num_frames;
};
static inline void mjpeg_encoder_reset_quality(MJpegEncoder *encoder,
@@ -214,6 +218,7 @@ MJpegEncoder *mjpeg_encoder_new(int bit_rate_control, uint64_t starting_bit_rate
void mjpeg_encoder_destroy(MJpegEncoder *encoder)
{
+ spice_debug("avg-quality %.2f", (double)encoder->avg_quality / encoder->num_frames);
jpeg_destroy_compress(&encoder->cinfo);
free(encoder->row);
free(encoder);
@@ -805,6 +810,8 @@ int mjpeg_encoder_start_frame(MJpegEncoder *encoder, SpiceBitmapFmt format,
jpeg_set_quality(&encoder->cinfo, quality, TRUE);
jpeg_start_compress(&encoder->cinfo, encoder->first_frame);
+ encoder->num_frames++;
+ encoder->avg_quality += quality;
return MJPEG_ENCODER_FRAME_ENCODE_START;
}
diff --git a/server/red_worker.c b/server/red_worker.c
index deb375c..2cb9f62 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -449,6 +449,20 @@ struct Stream {
uint32_t input_fps;
};
+#define STREAM_STATS
+#ifdef STREAM_STATS
+typedef struct StreamStats {
+ uint64_t num_drops_pipe;
+ uint64_t num_drops_fps;
+ uint64_t num_frames_sent;
+ uint64_t num_input_frames;
+ uint64_t size_sent;
+
+ uint64_t start;
+ uint64_t end;
+} StreamStats;
+#endif
+
typedef struct StreamAgent {
QRegion vis_region; /* the part of the surface area that is currently occupied by video
fragments */
@@ -472,6 +486,9 @@ typedef struct StreamAgent {
uint32_t report_id;
uint32_t client_required_latency;
+#ifdef STREAM_STATS
+ StreamStats stats;
+#endif
} StreamAgent;
typedef struct StreamClipItem {
@@ -2599,9 +2616,38 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
region_or(&agent->clip, &drawable->tree_item.base.rgn);
push_stream_clip(dcc, agent);
}
+#ifdef STREAM_STATS
+ agent->stats.num_input_frames++;
+#endif
}
}
+static void red_print_stream_stats(DisplayChannelClient *dcc, StreamAgent *agent)
+{
+#ifdef STREAM_STATS
+ StreamStats *stats = &agent->stats;
+ double passed_mm_time = (stats->end - stats->start) / 1000.0;
+
+ spice_debug("stream %ld (%dx%d): #frames-sent %lu, #drops %lu (pipe %lu, fps %lu), avg_fps %.2f,"
+ "passed mm-time %.2f (sec), size %.2f (KB) %.2f (Mbps) %.2f (KBpf)",
+ agent - dcc->stream_agents, agent->stream->width, agent->stream->height,
+ stats->num_frames_sent,
+ stats->num_drops_pipe +
+ stats->num_drops_fps,
+ stats->num_drops_pipe,
+ stats->num_drops_fps,
+ stats->num_frames_sent / passed_mm_time,
+ passed_mm_time,
+ stats->size_sent / 1024.0,
+ ((stats->size_sent * 8.0) / (1024.0 * 1024)) / passed_mm_time,
+ stats->size_sent / 1000.0 / stats->num_frames_sent);
+ spice_debug("num-input-frames %lu, per-sec %.2f, prec-frames-sent %.2f (out/in)",
+ stats->num_input_frames,
+ stats->num_input_frames / passed_mm_time,
+ (stats->num_frames_sent + 0.0) / stats->num_input_frames);
+#endif
+}
+
static void red_stop_stream(RedWorker *worker, Stream *stream)
{
DisplayChannelClient *dcc;
@@ -2629,6 +2675,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream)
}
stream->refs++;
red_channel_client_pipe_add(&dcc->common.base, &stream_agent->destroy_item);
+ red_print_stream_stats(dcc, stream_agent);
}
worker->streams_size_total -= stream->width * stream->height;
ring_remove(&stream->link);
@@ -3024,7 +3071,12 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
report_pipe_item->stream_id = get_stream_id(dcc->common.worker, stream);
red_channel_client_pipe_add(&dcc->common.base, &report_pipe_item->pipe_item);
}
-
+#ifdef STREAM_STATS
+ memset(&agent->stats, 0, sizeof(StreamStats));
+ if (stream->current) {
+ agent->stats.start = stream->current->red_drawable->mm_time;
+ }
+#endif
}
static void red_stream_input_fps_timer_cb(void *opaque)
@@ -3268,6 +3320,9 @@ static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream, Drawa
}
if (pipe_item_is_linked(&dpi->dpi_pipe_item)) {
+#ifdef STREAM_STATS
+ agent->stats.num_drops_pipe++;
+#endif
if (dcc->use_mjpeg_encoder_rate_control) {
mjpeg_encoder_notify_server_frame_drop(agent->mjpeg_encoder);
} else {
@@ -8548,6 +8603,9 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
if (!dcc->use_mjpeg_encoder_rate_control) {
if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) {
agent->frames--;
+#ifdef STREAM_STATS
+ agent->stats.num_drops_fps++;
+#endif
return TRUE;
}
}
@@ -8561,6 +8619,9 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
switch (ret) {
case MJPEG_ENCODER_FRAME_DROP:
spice_assert(dcc->use_mjpeg_encoder_rate_control);
+#ifdef STREAM_STATS
+ agent->stats.num_drops_fps++;
+#endif
return TRUE;
case MJPEG_ENCODER_FRAME_UNSUPPORTED:
return FALSE;
@@ -8606,6 +8667,12 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
spice_marshaller_add_ref(base_marshaller,
dcc->send_data.stream_outbuf, n);
agent->last_send_time = time_now;
+#ifdef STREAM_STATS
+ agent->stats.num_frames_sent++;
+ agent->stats.size_sent += n;
+ agent->stats.end = drawable->red_drawable->mm_time;
+#endif
+
return TRUE;
}
--
1.8.1
More information about the Spice-devel
mailing list