1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h" 6 7 #include "base/md5.h" 8 #include "base/metrics/histogram.h" 9 10 SpellCheckHostMetrics::SpellCheckHostMetrics() 11 : misspelled_word_count_(0), 12 last_misspelled_word_count_(-1), 13 spellchecked_word_count_(0), 14 last_spellchecked_word_count_(-1), 15 suggestion_show_count_(0), 16 last_suggestion_show_count_(-1), 17 replaced_word_count_(0), 18 last_replaced_word_count_(-1), 19 last_unique_word_count_(-1), 20 start_time_(base::TimeTicks::Now()) { 21 const uint64 kHistogramTimerDurationInMinutes = 30; 22 recording_timer_.Start(FROM_HERE, 23 base::TimeDelta::FromMinutes(kHistogramTimerDurationInMinutes), 24 this, &SpellCheckHostMetrics::OnHistogramTimerExpired); 25 RecordWordCounts(); 26 } 27 28 SpellCheckHostMetrics::~SpellCheckHostMetrics() { 29 } 30 31 // static 32 void SpellCheckHostMetrics::RecordCustomWordCountStats(size_t count) { 33 UMA_HISTOGRAM_COUNTS("SpellCheck.CustomWords", count); 34 } 35 36 void SpellCheckHostMetrics::RecordEnabledStats(bool enabled) { 37 UMA_HISTOGRAM_BOOLEAN("SpellCheck.Enabled", enabled); 38 // Because SpellCheckHost is instantiated lazily, the size of 39 // custom dictionary is unknown at this time. We mark it as -1 and 40 // record actual value later. See SpellCheckHost for more detail. 41 if (enabled) 42 RecordCustomWordCountStats(-1); 43 } 44 45 void SpellCheckHostMetrics::RecordCheckedWordStats(const base::string16& word, 46 bool misspell) { 47 spellchecked_word_count_++; 48 if (misspell) { 49 misspelled_word_count_++; 50 // If an user misspelled, that user should be counted as a part of 51 // the population. So we ensure to instantiate the histogram 52 // entries here at the first time. 53 if (misspelled_word_count_ == 1) 54 RecordReplacedWordStats(0); 55 } 56 57 int percentage = (100 * misspelled_word_count_) / spellchecked_word_count_; 58 UMA_HISTOGRAM_PERCENTAGE("SpellCheck.MisspellRatio", percentage); 59 60 // Collects actual number of checked words, excluding duplication. 61 base::MD5Digest digest; 62 base::MD5Sum(reinterpret_cast<const unsigned char*>(word.c_str()), 63 word.size() * sizeof(base::char16), &digest); 64 checked_word_hashes_.insert(base::MD5DigestToBase16(digest)); 65 66 RecordWordCounts(); 67 } 68 69 void SpellCheckHostMetrics::OnHistogramTimerExpired() { 70 if (0 < spellchecked_word_count_) { 71 // Collects word checking rate, which is represented 72 // as a word count per hour. 73 base::TimeDelta since_start = base::TimeTicks::Now() - start_time_; 74 // This shouldn't happen since OnHistogramTimerExpired() is called on 75 // a 30 minute interval. If the time was 0 we will end up dividing by zero. 76 CHECK_NE(0, since_start.InSeconds()); 77 size_t checked_words_per_hour = spellchecked_word_count_ * 78 base::TimeDelta::FromHours(1).InSeconds() / since_start.InSeconds(); 79 UMA_HISTOGRAM_COUNTS("SpellCheck.CheckedWordsPerHour", 80 checked_words_per_hour); 81 } 82 } 83 84 void SpellCheckHostMetrics::RecordDictionaryCorruptionStats(bool corrupted) { 85 UMA_HISTOGRAM_BOOLEAN("SpellCheck.DictionaryCorrupted", corrupted); 86 } 87 88 void SpellCheckHostMetrics::RecordSuggestionStats(int delta) { 89 suggestion_show_count_ += delta; 90 // RecordReplacedWordStats() Calls RecordWordCounts() eventually. 91 RecordReplacedWordStats(0); 92 } 93 94 void SpellCheckHostMetrics::RecordReplacedWordStats(int delta) { 95 replaced_word_count_ += delta; 96 97 if (misspelled_word_count_) { 98 // zero |misspelled_word_count_| is possible when an extension 99 // gives the misspelling, which is not recorded as a part of this 100 // metrics. 101 int percentage = (100 * replaced_word_count_) / misspelled_word_count_; 102 UMA_HISTOGRAM_PERCENTAGE("SpellCheck.ReplaceRatio", percentage); 103 } 104 105 if (suggestion_show_count_) { 106 int percentage = (100 * replaced_word_count_) / suggestion_show_count_; 107 UMA_HISTOGRAM_PERCENTAGE("SpellCheck.SuggestionHitRatio", percentage); 108 } 109 110 RecordWordCounts(); 111 } 112 113 void SpellCheckHostMetrics::RecordWordCounts() { 114 if (spellchecked_word_count_ != last_spellchecked_word_count_) { 115 DCHECK(spellchecked_word_count_ > last_spellchecked_word_count_); 116 UMA_HISTOGRAM_COUNTS("SpellCheck.CheckedWords", spellchecked_word_count_); 117 last_spellchecked_word_count_ = spellchecked_word_count_; 118 } 119 120 if (misspelled_word_count_ != last_misspelled_word_count_) { 121 DCHECK(misspelled_word_count_ > last_misspelled_word_count_); 122 UMA_HISTOGRAM_COUNTS("SpellCheck.MisspelledWords", misspelled_word_count_); 123 last_misspelled_word_count_ = misspelled_word_count_; 124 } 125 126 if (replaced_word_count_ != last_replaced_word_count_) { 127 DCHECK(replaced_word_count_ > last_replaced_word_count_); 128 UMA_HISTOGRAM_COUNTS("SpellCheck.ReplacedWords", replaced_word_count_); 129 last_replaced_word_count_ = replaced_word_count_; 130 } 131 132 if (((int)checked_word_hashes_.size()) != last_unique_word_count_) { 133 DCHECK((int)checked_word_hashes_.size() > last_unique_word_count_); 134 UMA_HISTOGRAM_COUNTS("SpellCheck.UniqueWords", checked_word_hashes_.size()); 135 last_unique_word_count_ = checked_word_hashes_.size(); 136 } 137 138 if (suggestion_show_count_ != last_suggestion_show_count_) { 139 DCHECK(suggestion_show_count_ > last_suggestion_show_count_); 140 UMA_HISTOGRAM_COUNTS("SpellCheck.ShownSuggestions", suggestion_show_count_); 141 last_suggestion_show_count_ = suggestion_show_count_; 142 } 143 } 144 145 void SpellCheckHostMetrics::RecordSpellingServiceStats(bool enabled) { 146 UMA_HISTOGRAM_BOOLEAN("SpellCheck.SpellingService.Enabled", enabled); 147 } 148