summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authoryuweih <yuweih@chromium.org>2016-03-23 15:41:05 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-23 22:43:12 +0000
commitd2a0c5cb1217570e7b3da52415f7326f48928053 (patch)
tree5e09f3caa5a6e6824e0b1ae9ec5b320532422b39 /remoting
parent7d9e04b799588c9cce868eae6ab7570514600895 (diff)
downloadchromium_src-d2a0c5cb1217570e7b3da52415f7326f48928053.zip
chromium_src-d2a0c5cb1217570e7b3da52415f7326f48928053.tar.gz
chromium_src-d2a0c5cb1217570e7b3da52415f7326f48928053.tar.bz2
Show max latency on client's status bar
Will later also consider storing max latency data in server BUG=560950 Committed: https://crrev.com/e37a467453f3814a9ecb0eb6769bd7c58b61cbae Cr-Commit-Position: refs/heads/master@{#382663} Review URL: https://codereview.chromium.org/1811833002 Cr-Commit-Position: refs/heads/master@{#382957}
Diffstat (limited to 'remoting')
-rw-r--r--remoting/base/BUILD.gn2
-rw-r--r--remoting/base/running_average_unittest.cc60
-rw-r--r--remoting/base/running_samples.cc (renamed from remoting/base/running_average.cc)26
-rw-r--r--remoting/base/running_samples.h (renamed from remoting/base/running_average.h)30
-rw-r--r--remoting/base/running_samples_unittest.cc92
-rw-r--r--remoting/client/jni/chromoting_jni_instance.cc19
-rw-r--r--remoting/client/plugin/chromoting_instance.cc15
-rw-r--r--remoting/client/server_log_entry_client.cc10
-rw-r--r--remoting/protocol/capture_scheduler.h6
-rw-r--r--remoting/protocol/performance_tracker.h22
-rw-r--r--remoting/remoting_srcs.gypi4
-rw-r--r--remoting/remoting_test.gypi2
-rw-r--r--remoting/webapp/base/js/chromoting_event.js10
-rw-r--r--remoting/webapp/base/js/connection_stats.js31
-rw-r--r--remoting/webapp/base/js/session_logger.js5
-rw-r--r--remoting/webapp/base/js/stats_accumulator.js25
16 files changed, 237 insertions, 122 deletions
diff --git a/remoting/base/BUILD.gn b/remoting/base/BUILD.gn
index 8a039e1..b8577c1 100644
--- a/remoting/base/BUILD.gn
+++ b/remoting/base/BUILD.gn
@@ -65,7 +65,7 @@ source_set("unit_tests") {
"rate_counter_unittest.cc",
"rsa_key_pair_unittest.cc",
"run_all_unittests.cc",
- "running_average_unittest.cc",
+ "running_samples_unittest.cc",
"test_rsa_key_pair.h",
"typed_buffer_unittest.cc",
"util_unittest.cc",
diff --git a/remoting/base/running_average_unittest.cc b/remoting/base/running_average_unittest.cc
deleted file mode 100644
index e731573..0000000
--- a/remoting/base/running_average_unittest.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "remoting/base/running_average.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace remoting {
-
-static const int64_t kTestValues[] = { 10, 20, 30, 10, 25, 16, 15 };
-
-// Average across a single element, i.e. just return the most recent.
-TEST(RunningAverageTest, OneElementWindow) {
- RunningAverage running_average(1);
- EXPECT_EQ(0, running_average.Average());
-
- for (size_t i = 0; i < arraysize(kTestValues); ++i) {
- running_average.Record(kTestValues[i]);
- EXPECT_EQ(static_cast<double>(kTestValues[i]), running_average.Average());
- }
-}
-
-// Average the two most recent elements.
-TEST(RunningAverageTest, TwoElementWindow) {
- RunningAverage running_average(2);
- EXPECT_EQ(0, running_average.Average());
-
- for (size_t i = 0; i < arraysize(kTestValues); ++i) {
- running_average.Record(kTestValues[i]);
-
- double expected = kTestValues[i];
- if (i > 0)
- expected = (expected + kTestValues[i-1]) / 2;
-
- EXPECT_EQ(expected, running_average.Average());
- }
-}
-
-// Average across all the elements if the window size exceeds the element count.
-TEST(RunningAverageTest, LongWindow) {
- RunningAverage running_average(arraysize(kTestValues) + 1);
- EXPECT_EQ(0, running_average.Average());
-
- for (size_t i = 0; i < arraysize(kTestValues); ++i) {
- running_average.Record(kTestValues[i]);
-
- double expected = 0.0;
- for (size_t j = 0; j <= i; ++j)
- expected += kTestValues[j];
- expected /= i + 1;
-
- EXPECT_EQ(expected, running_average.Average());
- }
-}
-
-} // namespace remoting
diff --git a/remoting/base/running_average.cc b/remoting/base/running_samples.cc
index 5e24c0d..d76a1a6 100644
--- a/remoting/base/running_average.cc
+++ b/remoting/base/running_samples.cc
@@ -1,22 +1,23 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/base/running_average.h"
+#include "remoting/base/running_samples.h"
+
+#include <algorithm>
#include "base/logging.h"
namespace remoting {
-RunningAverage::RunningAverage(int window_size)
- : window_size_(window_size),
- sum_(0) {
+RunningSamples::RunningSamples(int window_size)
+ : window_size_(window_size) {
DCHECK_GT(window_size, 0);
}
-RunningAverage::~RunningAverage() {}
+RunningSamples::~RunningSamples() {}
-void RunningAverage::Record(int64_t value) {
+void RunningSamples::Record(int64_t value) {
DCHECK(thread_checker_.CalledOnValidThread());
data_points_.push_back(value);
@@ -28,7 +29,7 @@ void RunningAverage::Record(int64_t value) {
}
}
-double RunningAverage::Average() {
+double RunningSamples::Average() const {
DCHECK(thread_checker_.CalledOnValidThread());
if (data_points_.empty())
@@ -36,4 +37,13 @@ double RunningAverage::Average() {
return static_cast<double>(sum_) / data_points_.size();
}
+int64_t RunningSamples::Max() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (data_points_.empty())
+ return 0;
+
+ return *std::max_element(data_points_.begin(), data_points_.end());
+}
+
} // namespace remoting
diff --git a/remoting/base/running_average.h b/remoting/base/running_samples.h
index e41234e..3f5078d 100644
--- a/remoting/base/running_average.h
+++ b/remoting/base/running_samples.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef REMOTING_BASE_RUNNING_AVERAGE_H_
-#define REMOTING_BASE_RUNNING_AVERAGE_H_
+#ifndef REMOTING_BASE_RUNNING_SAMPLES_H_
+#define REMOTING_BASE_RUNNING_SAMPLES_H_
#include <stddef.h>
#include <stdint.h>
@@ -15,20 +15,26 @@
namespace remoting {
-// Calculates the average of the most recent N recorded samples.
+// Calculates the maximum or average of the most recent N recorded samples.
// This is typically used to smooth out random variation in point samples
// over bandwidth, frame rate, etc.
-class RunningAverage {
+class RunningSamples {
public:
- // Constructs a helper to average over the |window_size| most recent samples.
- explicit RunningAverage(int window_size);
- virtual ~RunningAverage();
+ // Constructs a running sample helper that stores |window_size| most
+ // recent samples.
+ explicit RunningSamples(int window_size);
+ virtual ~RunningSamples();
// Records a point sample.
void Record(int64_t value);
// Returns the average over up to |window_size| of the most recent samples.
- double Average();
+ // 0 if no sample available
+ double Average() const;
+
+ // Returns the max over up to |window_size| of the most recent samples.
+ // 0 if no sample available
+ int64_t Max() const;
private:
// Stores the desired window size, as size_t to avoid casting when comparing
@@ -39,13 +45,13 @@ class RunningAverage {
std::deque<int64_t> data_points_;
// Holds the sum of the samples in |data_points_|.
- int64_t sum_;
+ int64_t sum_ = 0;
base::ThreadChecker thread_checker_;
- DISALLOW_COPY_AND_ASSIGN(RunningAverage);
+ DISALLOW_COPY_AND_ASSIGN(RunningSamples);
};
} // namespace remoting
-#endif // REMOTING_BASE_RUNNING_AVERAGE_H_
+#endif // REMOTING_BASE_RUNNING_SAMPLES_H_
diff --git a/remoting/base/running_samples_unittest.cc b/remoting/base/running_samples_unittest.cc
new file mode 100644
index 0000000..2c2c7f5
--- /dev/null
+++ b/remoting/base/running_samples_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "remoting/base/running_samples.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+typedef void (*TestFunction)(size_t i, RunningSamples& samples);
+
+static const int64_t kTestValues[] = { 10, 20, 30, 10, 25, 16, 15 };
+
+// Test framework that verifies average() and max() at beginning, iterates
+// through all elements and meanwhile calls your own test function
+static void TestFramework(int windowSize, TestFunction testFn) {
+ RunningSamples samples(windowSize);
+ EXPECT_EQ(0, samples.Average());
+ EXPECT_EQ(0, samples.Max());
+
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ samples.Record(kTestValues[i]);
+ testFn(i, samples);
+ }
+}
+
+// Average across a single element, i.e. just return the most recent.
+TEST(RunningSamplesTest, AverageOneElementWindow) {
+ TestFramework(1, [](size_t i, RunningSamples& samples) {
+ EXPECT_EQ(static_cast<double>(kTestValues[i]), samples.Average());
+ });
+}
+
+// Average the two most recent elements.
+TEST(RunningSamplesTest, AverageTwoElementWindow) {
+ TestFramework(2, [](size_t i, RunningSamples& samples) {
+ double expected = kTestValues[i];
+ if (i > 0)
+ expected = (expected + kTestValues[i-1]) / 2;
+
+ EXPECT_EQ(expected, samples.Average());
+ });
+}
+
+// Average across all the elements if the window size exceeds the element count.
+TEST(RunningSamplesTest, AverageLongWindow) {
+ TestFramework(arraysize(kTestValues) + 1,
+ [](size_t i, RunningSamples& samples) {
+ double expected = 0.0;
+ for (size_t j = 0; j <= i; ++j)
+ expected += kTestValues[j];
+ expected /= i + 1;
+
+ EXPECT_EQ(expected, samples.Average());
+ });
+}
+
+// Max of a single element, i.e. just return the most recent.
+TEST(RunningSamplesTest, MaxOneElementWindow) {
+ TestFramework(1, [](size_t i, RunningSamples& samples) {
+ EXPECT_EQ(static_cast<double>(kTestValues[i]), samples.Max());
+ });
+}
+
+// Max of the two most recent elements.
+TEST(RunningSamplesTest, MaxTwoElementWindow) {
+ TestFramework(2, [](size_t i, RunningSamples& samples) {
+ double expected = kTestValues[i];
+ if (i > 0)
+ expected = expected > kTestValues[i-1] ? expected : kTestValues[i-1];
+
+ EXPECT_EQ(expected, samples.Max());
+ });
+}
+
+// Max of all the elements if the window size exceeds the element count.
+TEST(RunningSamplesTest, MaxLongWindow) {
+ TestFramework(arraysize(kTestValues) + 1,
+ [](size_t i, RunningSamples& samples) {
+ int64_t expected = -1;
+ for (size_t j = 0; j <= i; ++j)
+ expected = expected > kTestValues[j] ? expected : kTestValues[j];
+
+ EXPECT_EQ(expected, samples.Max());
+ });
+}
+
+} // namespace remoting \ No newline at end of file
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index f7adccc..1af00bc 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/format_macros.h"
#include "base/logging.h"
#include "jingle/glue/thread_wrapper.h"
#include "net/socket/client_socket_factory.h"
@@ -484,12 +485,20 @@ void ChromotingJniInstance::LogPerfStats() {
__android_log_print(
ANDROID_LOG_INFO, "stats",
- "Bandwidth:%.0f FrameRate:%.1f Capture:%.1f Encode:%.1f "
- "Decode:%.1f Render:%.1f Latency:%.0f",
+ "Bandwidth:%.0f FrameRate:%.1f;"
+ " (Avg, Max) Capture:%.1f, %" PRId64 " Encode:%.1f, %" PRId64
+ " Decode:%.1f, %" PRId64 " Render:%.1f, %" PRId64 " RTL:%.0f, %" PRId64,
perf_tracker_->video_bandwidth(), perf_tracker_->video_frame_rate(),
- perf_tracker_->video_capture_ms(), perf_tracker_->video_encode_ms(),
- perf_tracker_->video_decode_ms(), perf_tracker_->video_paint_ms(),
- perf_tracker_->round_trip_ms());
+ perf_tracker_->video_capture_ms().Average(),
+ perf_tracker_->video_capture_ms().Max(),
+ perf_tracker_->video_encode_ms().Average(),
+ perf_tracker_->video_encode_ms().Max(),
+ perf_tracker_->video_decode_ms().Average(),
+ perf_tracker_->video_decode_ms().Max(),
+ perf_tracker_->video_paint_ms().Average(),
+ perf_tracker_->video_paint_ms().Max(),
+ perf_tracker_->round_trip_ms().Average(),
+ perf_tracker_->round_trip_ms().Max());
client_status_logger_->LogStatistics(perf_tracker_.get());
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index e0ca0d5..a7c5601 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -1034,11 +1034,16 @@ void ChromotingInstance::UpdatePerfStatsInUI() {
scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
data->SetDouble("videoBandwidth", perf_tracker_.video_bandwidth());
data->SetDouble("videoFrameRate", perf_tracker_.video_frame_rate());
- data->SetDouble("captureLatency", perf_tracker_.video_capture_ms());
- data->SetDouble("encodeLatency", perf_tracker_.video_encode_ms());
- data->SetDouble("decodeLatency", perf_tracker_.video_decode_ms());
- data->SetDouble("renderLatency", perf_tracker_.video_paint_ms());
- data->SetDouble("roundtripLatency", perf_tracker_.round_trip_ms());
+ data->SetDouble("captureLatency", perf_tracker_.video_capture_ms().Average());
+ data->SetDouble("maxCaptureLatency", perf_tracker_.video_capture_ms().Max());
+ data->SetDouble("encodeLatency", perf_tracker_.video_encode_ms().Average());
+ data->SetDouble("maxEncodeLatency", perf_tracker_.video_encode_ms().Max());
+ data->SetDouble("decodeLatency", perf_tracker_.video_decode_ms().Average());
+ data->SetDouble("maxDecodeLatency", perf_tracker_.video_decode_ms().Max());
+ data->SetDouble("renderLatency", perf_tracker_.video_paint_ms().Average());
+ data->SetDouble("maxRenderLatency", perf_tracker_.video_paint_ms().Max());
+ data->SetDouble("roundtripLatency", perf_tracker_.round_trip_ms().Average());
+ data->SetDouble("maxRoundtripLatency", perf_tracker_.round_trip_ms().Max());
PostLegacyJsonMessage("onPerfStats", std::move(data));
}
diff --git a/remoting/client/server_log_entry_client.cc b/remoting/client/server_log_entry_client.cc
index 0686159..290165f 100644
--- a/remoting/client/server_log_entry_client.cc
+++ b/remoting/client/server_log_entry_client.cc
@@ -117,15 +117,15 @@ scoped_ptr<ServerLogEntry> MakeLogEntryForStatistics(
entry->Set("video-bandwidth",
StringPrintf("%.2f", perf_tracker->video_bandwidth()));
entry->Set("capture-latency",
- StringPrintf("%.2f", perf_tracker->video_capture_ms()));
+ StringPrintf("%.2f", perf_tracker->video_capture_ms().Average()));
entry->Set("encode-latency",
- StringPrintf("%.2f", perf_tracker->video_encode_ms()));
+ StringPrintf("%.2f", perf_tracker->video_encode_ms().Average()));
entry->Set("decode-latency",
- StringPrintf("%.2f", perf_tracker->video_decode_ms()));
+ StringPrintf("%.2f", perf_tracker->video_decode_ms().Average()));
entry->Set("render-latency",
- StringPrintf("%.2f", perf_tracker->video_frame_rate()));
+ StringPrintf("%.2f", perf_tracker->video_paint_ms().Average()));
entry->Set("roundtrip-latency",
- StringPrintf("%.2f", perf_tracker->round_trip_ms()));
+ StringPrintf("%.2f", perf_tracker->round_trip_ms().Average()));
return entry;
}
diff --git a/remoting/protocol/capture_scheduler.h b/remoting/protocol/capture_scheduler.h
index 54e2229d..3f4369a 100644
--- a/remoting/protocol/capture_scheduler.h
+++ b/remoting/protocol/capture_scheduler.h
@@ -13,7 +13,7 @@
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
-#include "remoting/base/running_average.h"
+#include "remoting/base/running_samples.h"
#include "remoting/protocol/video_feedback_stub.h"
namespace remoting {
@@ -88,8 +88,8 @@ class CaptureScheduler : public VideoFeedbackStub {
int num_of_processors_;
- RunningAverage capture_time_;
- RunningAverage encode_time_;
+ RunningSamples capture_time_;
+ RunningSamples encode_time_;
// Number of frames pending encoding.
int num_encoding_frames_;
diff --git a/remoting/protocol/performance_tracker.h b/remoting/protocol/performance_tracker.h
index 3e5bf2c..c31ca91 100644
--- a/remoting/protocol/performance_tracker.h
+++ b/remoting/protocol/performance_tracker.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "base/timer/timer.h"
#include "remoting/base/rate_counter.h"
-#include "remoting/base/running_average.h"
+#include "remoting/base/running_samples.h"
namespace remoting {
@@ -49,11 +49,11 @@ class PerformanceTracker {
double video_bandwidth() { return video_bandwidth_.Rate(); }
double video_frame_rate() { return video_frame_rate_.Rate(); }
double video_packet_rate() { return video_packet_rate_.Rate(); }
- double video_capture_ms() { return video_capture_ms_.Average(); }
- double video_encode_ms() { return video_encode_ms_.Average(); }
- double video_decode_ms() { return video_decode_ms_.Average(); }
- double video_paint_ms() { return video_paint_ms_.Average(); }
- double round_trip_ms() { return round_trip_ms_.Average(); }
+ const RunningSamples& video_capture_ms() { return video_capture_ms_; }
+ const RunningSamples& video_encode_ms() { return video_encode_ms_; }
+ const RunningSamples& video_decode_ms() { return video_decode_ms_; }
+ const RunningSamples& video_paint_ms() { return video_paint_ms_; }
+ const RunningSamples& round_trip_ms() { return round_trip_ms_; }
// Record stats for a video-packet.
void RecordVideoPacketStats(const VideoPacket& packet);
@@ -113,11 +113,11 @@ class PerformanceTracker {
// The following running-averages are uploaded to UMA per video packet and
// also used for display to users, averaged over the N most recent samples.
// N = kLatencySampleSize.
- RunningAverage video_capture_ms_;
- RunningAverage video_encode_ms_;
- RunningAverage video_decode_ms_;
- RunningAverage video_paint_ms_;
- RunningAverage round_trip_ms_;
+ RunningSamples video_capture_ms_;
+ RunningSamples video_encode_ms_;
+ RunningSamples video_decode_ms_;
+ RunningSamples video_paint_ms_;
+ RunningSamples round_trip_ms_;
// Used to update UMA stats, if set.
UpdateUmaCustomHistogramCallback uma_custom_counts_updater_;
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi
index adba780..c6cd2e1 100644
--- a/remoting/remoting_srcs.gypi
+++ b/remoting/remoting_srcs.gypi
@@ -25,8 +25,8 @@
'base/rate_counter.h',
'base/rsa_key_pair.cc',
'base/rsa_key_pair.h',
- 'base/running_average.cc',
- 'base/running_average.h',
+ 'base/running_samples.cc',
+ 'base/running_samples.h',
'base/scoped_sc_handle_win.h',
'base/socket_reader.cc',
'base/socket_reader.h',
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi
index 761607e..5f193e9 100644
--- a/remoting/remoting_test.gypi
+++ b/remoting/remoting_test.gypi
@@ -232,7 +232,7 @@
'base/rate_counter_unittest.cc',
'base/rsa_key_pair_unittest.cc',
'base/run_all_unittests.cc',
- 'base/running_average_unittest.cc',
+ 'base/running_samples_unittest.cc',
'base/test_rsa_key_pair.h',
'base/typed_buffer_unittest.cc',
'base/util_unittest.cc',
diff --git a/remoting/webapp/base/js/chromoting_event.js b/remoting/webapp/base/js/chromoting_event.js
index 476f879c..0f6fedd 100644
--- a/remoting/webapp/base/js/chromoting_event.js
+++ b/remoting/webapp/base/js/chromoting_event.js
@@ -79,6 +79,16 @@ remoting.ChromotingEvent = function(type) {
this.render_latency;
/** @type {number} */
this.roundtrip_latency;
+ /** @type {number} */
+ this.max_capture_latency;
+ /** @type {number} */
+ this.max_encode_latency;
+ /** @type {number} */
+ this.max_decode_latency;
+ /** @type {number} */
+ this.max_render_latency;
+ /** @type {number} */
+ this.max_roundtrip_latency;
/** @type {remoting.ChromotingEvent.Mode} */
this.mode;
/** @type {remoting.ChromotingEvent.SignalStrategyType} */
diff --git a/remoting/webapp/base/js/connection_stats.js b/remoting/webapp/base/js/connection_stats.js
index d08a527..61d5680 100644
--- a/remoting/webapp/base/js/connection_stats.js
+++ b/remoting/webapp/base/js/connection_stats.js
@@ -123,23 +123,36 @@ remoting.ConnectionStats.prototype.update = function(stats) {
/**
* @param {number} value
* @param {string} units
+ * @param {number} digits
* @return {string} Formatted number.
*/
- function formatStatNumber(value, units) {
+ function formatStatNumber(value, units, digits) {
if (value != undefined) {
- return value.toFixed(2) + ' ' + units;
+ return value.toFixed(digits) + ' ' + units;
} else {
return "n/a";
}
}
+ /**
+ * @param {string} type
+ * @param {number} avg
+ * @param {number} max
+ * @return {string} "type: avg, max; " e.g. "RTT: 8.0, 13; "
+ */
+ function formatStat(type, avg, max) {
+ return type + ': ' + avg.toFixed(1) + ', ' + max + '; ';
+ }
+
var statistics = document.getElementById('statistics');
this.statsElement_.innerText = (
- 'Bandwidth: ' + formatStatNumber(videoBandwidth, units) +
- ', Frame Rate: ' + formatStatNumber(stats.videoFrameRate, 'fps') +
- ', Capture: ' + formatStatNumber(stats.captureLatency, 'ms') +
- ', Encode: ' + formatStatNumber(stats.encodeLatency, 'ms') +
- ', Decode: ' + formatStatNumber(stats.decodeLatency, 'ms') +
- ', Render: ' + formatStatNumber(stats.renderLatency, 'ms') +
- ', Latency: ' + formatStatNumber(stats.roundtripLatency, 'ms'));
+ '(avg, max in ms) ' +
+ formatStat('Capture', stats.captureLatency, stats.maxCaptureLatency) +
+ formatStat('Encode', stats.encodeLatency, stats.maxEncodeLatency) +
+ formatStat('Decode', stats.decodeLatency, stats.maxDecodeLatency) +
+ formatStat('Render', stats.renderLatency, stats.maxRenderLatency) +
+ formatStat('RTT', stats.roundtripLatency, stats.maxRoundtripLatency) +
+ 'Bandwidth: ' + formatStatNumber(videoBandwidth, units, 2) + '; ' +
+ 'Frame Rate: ' + formatStatNumber(stats.videoFrameRate, 'fps', 1)
+ );
};
diff --git a/remoting/webapp/base/js/session_logger.js b/remoting/webapp/base/js/session_logger.js
index 6f26c9a..4e4eba9 100644
--- a/remoting/webapp/base/js/session_logger.js
+++ b/remoting/webapp/base/js/session_logger.js
@@ -291,6 +291,11 @@ remoting.SessionLogger.prototype.makeStats_ = function() {
entry.decode_latency = perfStats.decodeLatency;
entry.render_latency = perfStats.renderLatency;
entry.roundtrip_latency = perfStats.roundtripLatency;
+ entry.max_capture_latency = perfStats.maxCaptureLatency;
+ entry.max_encode_latency = perfStats.maxEncodeLatency;
+ entry.max_decode_latency = perfStats.maxDecodeLatency;
+ entry.max_render_latency = perfStats.maxRenderLatency;
+ entry.max_roundtrip_latency = perfStats.maxRoundtripLatency;
return entry;
}
return null;
diff --git a/remoting/webapp/base/js/stats_accumulator.js b/remoting/webapp/base/js/stats_accumulator.js
index e0edd49..e8bda09 100644
--- a/remoting/webapp/base/js/stats_accumulator.js
+++ b/remoting/webapp/base/js/stats_accumulator.js
@@ -94,6 +94,26 @@ remoting.StatsAccumulator.prototype.calcMean = function(key) {
};
/**
+ * Finds the max of the values for a given key.
+ *
+ * @param {string} key
+ * @return {number} the max of the values for that key
+ */
+remoting.StatsAccumulator.prototype.calcMax = function(key) {
+ /**
+ * @param {Array<number>} values
+ * @return {number}
+ */
+ var calcMax = function(values) {
+ if (!values || !values.length) {
+ return 0;
+ }
+ return Math.max.apply(null, values);
+ };
+ return this.map(key, calcMax);
+};
+
+/**
* Applies a given map to the list of values for a given key.
*
* @param {string} key
@@ -131,10 +151,15 @@ remoting.StatsAccumulator.prototype.getPerfStats = function() {
var stats = new remoting.ClientSession.PerfStats();
stats.videoBandwidth = this.calcMean('videoBandwidth');
stats.captureLatency = this.calcMean('captureLatency');
+ stats.maxCaptureLatency = this.calcMax('maxCaptureLatency');
stats.encodeLatency = this.calcMean('encodeLatency');
+ stats.maxEncodeLatency = this.calcMax('maxEncodeLatency');
stats.decodeLatency = this.calcMean('decodeLatency');
+ stats.maxDecodeLatency = this.calcMax('maxDecodeLatency');
stats.renderLatency = this.calcMean('renderLatency');
+ stats.maxRenderLatency = this.calcMax('maxRenderLatency');
stats.roundtripLatency = this.calcMean('roundtripLatency');
+ stats.maxRoundtripLatency = this.calcMax('maxRoundtripLatency');
for (var key in stats) {
if (stats[key] !== 0) {