diff options
author | eustas <eustas@chromium.org> | 2016-01-22 08:35:09 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-22 16:37:33 +0000 |
commit | 15b1075e589fbbcd89111ea43d2b96c8168b96e2 (patch) | |
tree | 73fcccf3d18d904b16abe0c2de5e04a85402ce03 /net | |
parent | 8ab1f83653dbb621f5639d773ef8defd209642b7 (diff) | |
download | chromium_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.cc | 96 | ||||
-rw-r--r-- | net/filter/brotli_filter_unittest.cc | 16 |
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 |