summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoreustas <eustas@chromium.org>2016-01-22 08:35:09 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-22 16:37:33 +0000
commit15b1075e589fbbcd89111ea43d2b96c8168b96e2 (patch)
tree73fcccf3d18d904b16abe0c2de5e04a85402ce03 /net
parent8ab1f83653dbb621f5639d773ef8defd209642b7 (diff)
downloadchromium_src-15b1075e589fbbcd89111ea43d2b96c8168b96e2.zip
chromium_src-15b1075e589fbbcd89111ea43d2b96c8168b96e2.tar.gz
chromium_src-15b1075e589fbbcd89111ea43d2b96c8168b96e2.tar.bz2
Add UMAs to BrotliFilter.
BUG=472009 Review URL: https://codereview.chromium.org/1572983003/ Cr-Commit-Position: refs/heads/master@{#370108} (cherry picked from commit ec0fd9b4321fb0ae5b27ec5ff582b51710ce9f3a) ADDITIONAL COMMIT: Fix division by zero. Test filter with empty output. BUG=579672 Review URL: https://codereview.chromium.org/1616863002 Cr-Commit-Position: refs/heads/master@{#370675} (cherry picked from commit b266c8153a66f01644f3361fe9cc7d439df1e981) NOTRY=true NOPRESUBMIT=true Review URL: https://codereview.chromium.org/1621663002 Cr-Commit-Position: refs/branch-heads/2623@{#73} Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
Diffstat (limited to 'net')
-rw-r--r--net/filter/brotli_filter.cc96
-rw-r--r--net/filter/brotli_filter_unittest.cc16
2 files changed, 102 insertions, 10 deletions
diff --git a/net/filter/brotli_filter.cc b/net/filter/brotli_filter.cc
index 939a6f7..7ce402ec 100644
--- a/net/filter/brotli_filter.cc
+++ b/net/filter/brotli_filter.cc
@@ -6,6 +6,7 @@
#include "base/bit_cast.h"
#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "third_party/brotli/dec/decode.h"
@@ -20,11 +21,42 @@ namespace net {
class BrotliFilter : public Filter {
public:
BrotliFilter(FilterType type)
- : Filter(type), decoding_status_(DECODING_IN_PROGRESS) {
- BrotliStateInit(&brotli_state_);
+ : Filter(type),
+ decoding_status_(DecodingStatus::DECODING_IN_PROGRESS),
+ used_memory_(0),
+ used_memory_maximum_(0),
+ consumed_bytes_(0),
+ produced_bytes_(0) {
+ brotli_state_ = BrotliCreateState(BrotliFilter::AllocateMemory,
+ BrotliFilter::FreeMemory, this);
+ CHECK(brotli_state_);
}
- ~BrotliFilter() override { BrotliStateCleanup(&brotli_state_); }
+ ~BrotliFilter() override {
+ BrotliDestroyState(brotli_state_);
+ brotli_state_ = nullptr;
+ DCHECK(used_memory_ == 0);
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "BrotliFilter.Status", static_cast<int>(decoding_status_),
+ static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT));
+ if (decoding_status_ == DecodingStatus::DECODING_DONE) {
+ // CompressionPercent is undefined when there is no output produced.
+ if (produced_bytes_ != 0) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ "BrotliFilter.CompressionPercent",
+ static_cast<int>((consumed_bytes_ * 100) / produced_bytes_));
+ }
+ }
+
+ // All code here is for gathering stats, and can be removed when
+ // BrotliFilter is considered stable.
+ static const int kBuckets = 48;
+ static const int64_t kMaxKb = 1 << (kBuckets / 3); // 64MiB in KiB
+ UMA_HISTOGRAM_CUSTOM_COUNTS("BrotliFilter.UsedMemoryKB",
+ used_memory_maximum_ / 1024, 1, kMaxKb,
+ kBuckets);
+ }
// Decodes the pre-filter data and writes the output into the |dest_buffer|
// passed in.
@@ -42,12 +74,12 @@ class BrotliFilter : public Filter {
if (!dest_buffer || !dest_len)
return Filter::FILTER_ERROR;
- if (decoding_status_ == DECODING_DONE) {
+ if (decoding_status_ == DecodingStatus::DECODING_DONE) {
*dest_len = 0;
return Filter::FILTER_DONE;
}
- if (decoding_status_ != DECODING_IN_PROGRESS)
+ if (decoding_status_ != DecodingStatus::DECODING_IN_PROGRESS)
return Filter::FILTER_ERROR;
size_t output_buffer_size = base::checked_cast<size_t>(*dest_len);
@@ -60,10 +92,12 @@ class BrotliFilter : public Filter {
size_t total_out = 0;
BrotliResult result =
BrotliDecompressStream(&available_in, &next_in, &available_out,
- &next_out, &total_out, &brotli_state_);
+ &next_out, &total_out, brotli_state_);
CHECK(available_in <= input_buffer_size);
CHECK(available_out <= output_buffer_size);
+ consumed_bytes_ += input_buffer_size - available_in;
+ produced_bytes_ += output_buffer_size - available_out;
base::CheckedNumeric<size_t> safe_bytes_written(output_buffer_size);
safe_bytes_written -= available_out;
@@ -78,7 +112,7 @@ class BrotliFilter : public Filter {
stream_data_len_ = base::checked_cast<int>(available_in);
next_stream_data_ = bit_cast<char*>(next_in);
if (result == BROTLI_RESULT_SUCCESS) {
- decoding_status_ = DECODING_DONE;
+ decoding_status_ = DecodingStatus::DECODING_DONE;
return Filter::FILTER_DONE;
}
return Filter::FILTER_OK;
@@ -90,19 +124,61 @@ class BrotliFilter : public Filter {
return Filter::FILTER_NEED_MORE_DATA;
default:
- decoding_status_ = DECODING_ERROR;
+ decoding_status_ = DecodingStatus::DECODING_ERROR;
return Filter::FILTER_ERROR;
}
}
private:
- enum DecodingStatus { DECODING_IN_PROGRESS, DECODING_DONE, DECODING_ERROR };
+ static void* AllocateMemory(void* opaque, size_t size) {
+ BrotliFilter* filter = reinterpret_cast<BrotliFilter*>(opaque);
+ return filter->AllocateMemoryInternal(size);
+ }
+
+ static void FreeMemory(void* opaque, void* address) {
+ BrotliFilter* filter = reinterpret_cast<BrotliFilter*>(opaque);
+ filter->FreeMemoryInternal(address);
+ }
+
+ void* AllocateMemoryInternal(size_t size) {
+ size_t* array = reinterpret_cast<size_t*>(malloc(size + sizeof(size_t)));
+ if (!array)
+ return nullptr;
+ used_memory_ += size;
+ if (used_memory_maximum_ < used_memory_)
+ used_memory_maximum_ = used_memory_;
+ array[0] = size;
+ return &array[1];
+ }
+
+ void FreeMemoryInternal(void* address) {
+ if (!address)
+ return;
+ size_t* array = reinterpret_cast<size_t*>(address);
+ used_memory_ -= array[-1];
+ free(&array[-1]);
+ }
+
+ // Reported in UMA and must be kept in sync with the histograms.xml file.
+ enum class DecodingStatus : int {
+ DECODING_IN_PROGRESS = 0,
+ DECODING_DONE,
+ DECODING_ERROR,
+
+ DECODING_STATUS_COUNT
+ // DECODING_STATUS_COUNT must always be the last element in this enum.
+ };
// Tracks the status of decoding.
// This variable is updated only by ReadFilteredData.
DecodingStatus decoding_status_;
- BrotliState brotli_state_;
+ BrotliState* brotli_state_;
+
+ size_t used_memory_;
+ size_t used_memory_maximum_;
+ size_t consumed_bytes_;
+ size_t produced_bytes_;
DISALLOW_COPY_AND_ASSIGN(BrotliFilter);
};
diff --git a/net/filter/brotli_filter_unittest.cc b/net/filter/brotli_filter_unittest.cc
index 9c9ce65..38cfc82 100644
--- a/net/filter/brotli_filter_unittest.cc
+++ b/net/filter/brotli_filter_unittest.cc
@@ -250,4 +250,20 @@ TEST_F(BrotliUnitTest, DecodeMissingData) {
EXPECT_EQ(Filter::FILTER_ERROR, code);
}
+// Decoding brotli stream with empty output data.
+TEST_F(BrotliUnitTest, DecodeEmptyData) {
+ char data[1] = {6}; // WBITS = 16, ISLAST = 1, ISLASTEMPTY = 1
+ int data_len = 1;
+
+ InitFilter();
+ char decode_buffer[kDefaultBufferSize];
+ int decode_size = kDefaultBufferSize;
+ int code = DecodeAllWithFilter(filter_.get(), data, data_len, decode_buffer,
+ &decode_size);
+
+ // Expect success / empty output.
+ EXPECT_EQ(Filter::FILTER_DONE, code);
+ EXPECT_EQ(0, decode_size);
+}
+
} // namespace net