Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: components/autofill/core/browser/autofill_metrics.cc

Issue 2870163003: Log Autofill.Quality.*.ByFieldType by predicted type for unknown data. (Closed)
Patch Set: comments from mathp Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/browser/autofill_metrics.h" 5 #include "components/autofill/core/browser/autofill_metrics.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
13 #include "base/metrics/sparse_histogram.h" 13 #include "base/metrics/sparse_histogram.h"
14 #include "base/metrics/user_metrics.h" 14 #include "base/metrics/user_metrics.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/string_util.h"
15 #include "base/time/time.h" 17 #include "base/time/time.h"
16 #include "components/autofill/core/browser/autofill_experiments.h" 18 #include "components/autofill/core/browser/autofill_experiments.h"
17 #include "components/autofill/core/browser/autofill_field.h" 19 #include "components/autofill/core/browser/autofill_field.h"
18 #include "components/autofill/core/browser/autofill_type.h" 20 #include "components/autofill/core/browser/autofill_type.h"
19 #include "components/autofill/core/browser/form_structure.h" 21 #include "components/autofill/core/browser/form_structure.h"
20 #include "components/autofill/core/common/form_data.h" 22 #include "components/autofill/core/common/form_data.h"
21 #include "components/ukm/public/ukm_entry_builder.h" 23 #include "components/ukm/public/ukm_entry_builder.h"
22 24
23 namespace internal { 25 namespace internal {
24 const char kUKMCardUploadDecisionEntryName[] = "Autofill.CardUploadDecision"; 26 const char kUKMCardUploadDecisionEntryName[] = "Autofill.CardUploadDecision";
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 GROUP_CREDIT_CARD_DATE, 75 GROUP_CREDIT_CARD_DATE,
74 GROUP_CREDIT_CARD_TYPE, 76 GROUP_CREDIT_CARD_TYPE,
75 GROUP_PASSWORD, 77 GROUP_PASSWORD,
76 GROUP_ADDRESS_LINE_3, 78 GROUP_ADDRESS_LINE_3,
77 GROUP_USERNAME, 79 GROUP_USERNAME,
78 GROUP_STREET_ADDRESS, 80 GROUP_STREET_ADDRESS,
79 GROUP_CREDIT_CARD_VERIFICATION, 81 GROUP_CREDIT_CARD_VERIFICATION,
80 NUM_FIELD_TYPE_GROUPS_FOR_METRICS 82 NUM_FIELD_TYPE_GROUPS_FOR_METRICS
81 }; 83 };
82 84
85 const int KMaxFieldTypeGroupMetric =
86 (NUM_FIELD_TYPE_GROUPS_FOR_METRICS << 8) |
87 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS;
88
83 std::string PreviousSaveCreditCardPromptUserDecisionToString( 89 std::string PreviousSaveCreditCardPromptUserDecisionToString(
84 int previous_save_credit_card_prompt_user_decision) { 90 int previous_save_credit_card_prompt_user_decision) {
85 DCHECK_LT(previous_save_credit_card_prompt_user_decision, 91 DCHECK_LT(previous_save_credit_card_prompt_user_decision,
86 prefs::NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS); 92 prefs::NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS);
87 std::string previous_response; 93 std::string previous_response;
88 if (previous_save_credit_card_prompt_user_decision == 94 if (previous_save_credit_card_prompt_user_decision ==
89 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED) 95 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED)
90 previous_response = ".PreviouslyAccepted"; 96 previous_response = ".PreviouslyAccepted";
91 else if (previous_save_credit_card_prompt_user_decision == 97 else if (previous_save_credit_card_prompt_user_decision ==
92 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED) 98 prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED)
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 227
222 case USERNAME_FIELD: 228 case USERNAME_FIELD:
223 group = GROUP_USERNAME; 229 group = GROUP_USERNAME;
224 break; 230 break;
225 231
226 case TRANSACTION: 232 case TRANSACTION:
227 NOTREACHED(); 233 NOTREACHED();
228 break; 234 break;
229 } 235 }
230 236
231 // Interpolate the |metric| with the |group|, so that all metrics for a given 237 // Use bits 8-15 for the group and bits 0-7 for the metric.
232 // |group| are adjacent. 238 static_assert(AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS <= UINT8_MAX,
233 return (group * AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS) + metric; 239 "maximum field type quality metric must fit into 8 bits");
240 static_assert(NUM_FIELD_TYPE_GROUPS_FOR_METRICS <= UINT8_MAX,
241 "number of field type groups must fit into 8 bits");
242 return (group << 8) | metric;
234 } 243 }
235 244
236 namespace { 245 namespace {
237 246
238 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name| 247 // A version of the UMA_HISTOGRAM_ENUMERATION macro that allows the |name|
239 // to vary over the program's runtime. 248 // to vary over the program's runtime.
240 void LogUMAHistogramEnumeration(const std::string& name, 249 void LogUMAHistogramEnumeration(const std::string& name,
241 int sample, 250 int sample,
242 int boundary_value) { 251 int boundary_value) {
243 DCHECK_LT(sample, boundary_value); 252 DCHECK_LT(sample, boundary_value);
(...skipping 17 matching lines...) Expand all
261 base::HistogramBase* histogram = 270 base::HistogramBase* histogram =
262 base::Histogram::FactoryTimeGet( 271 base::Histogram::FactoryTimeGet(
263 name, 272 name,
264 base::TimeDelta::FromMilliseconds(1), 273 base::TimeDelta::FromMilliseconds(1),
265 base::TimeDelta::FromHours(1), 274 base::TimeDelta::FromHours(1),
266 50, 275 50,
267 base::HistogramBase::kUmaTargetedHistogramFlag); 276 base::HistogramBase::kUmaTargetedHistogramFlag);
268 histogram->AddTime(duration); 277 histogram->AddTime(duration);
269 } 278 }
270 279
271 // Logs a type quality metric. The primary histogram name is constructed based 280 const char* GetQualityMetricTypeSuffix(
272 // on |base_name|. The field-specific histogram name also factors in the 281 AutofillMetrics::QualityMetricType metric_type) {
273 // |field_type|. Logs a sample of |metric|, which should be in the range
274 // [0, |num_possible_metrics|). May log a suffixed version of the metric
275 // depending on |metric_type|.
276 void LogTypeQualityMetric(const std::string& base_name,
277 AutofillMetrics::FieldTypeQualityMetric metric,
278 ServerFieldType field_type,
279 AutofillMetrics::QualityMetricType metric_type) {
280 DCHECK_LT(metric, AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
281
282 std::string suffix;
283 switch (metric_type) { 282 switch (metric_type) {
284 case AutofillMetrics::TYPE_SUBMISSION:
285 break;
286 case AutofillMetrics::TYPE_NO_SUBMISSION:
287 suffix = ".NoSubmission";
288 break;
289 case AutofillMetrics::TYPE_AUTOCOMPLETE_BASED:
290 suffix = ".BasedOnAutocomplete";
291 break;
292 default: 283 default:
293 NOTREACHED(); 284 NOTREACHED();
285 // Fall through...
286
287 case AutofillMetrics::TYPE_SUBMISSION:
288 return "";
289 case AutofillMetrics::TYPE_NO_SUBMISSION:
290 return ".NoSubmission";
291 case AutofillMetrics::TYPE_AUTOCOMPLETE_BASED:
292 return ".BasedOnAutocomplete";
294 } 293 }
295 LogUMAHistogramEnumeration(base_name + suffix, metric, 294 }
295
296 // Given a set of |possible_types| for a field, select the best type to use as
297 // the "actual" field type when calculating metrics. If the |predicted_type| is
298 // among the |possible_types] then use that as the best type (i.e., the
299 // prediction is deemed to have been correct).
300 ServerFieldType GetActualFieldType(const ServerFieldTypeSet& possible_types,
301 ServerFieldType predicted_type) {
302 DCHECK_NE(possible_types.size(), 0u);
303
304 if (possible_types.count(EMPTY_TYPE)) {
305 DCHECK_EQ(possible_types.size(), 1u);
306 return EMPTY_TYPE;
307 }
308
309 if (possible_types.count(UNKNOWN_TYPE)) {
310 DCHECK_EQ(possible_types.size(), 1u);
311 return UNKNOWN_TYPE;
312 }
313
314 if (possible_types.count(predicted_type))
315 return predicted_type;
316
317 // Collapse field types that Chrome treats as identical, e.g. home and
318 // billing address fields.
319 ServerFieldTypeSet collapsed_field_types;
320 for (const auto& type : possible_types) {
321 DCHECK_NE(type, EMPTY_TYPE);
322 DCHECK_NE(type, UNKNOWN_TYPE);
323
324 // Collapse the
Mathieu 2017/05/31 20:07:18 fix plz :)
Roger McFarlane (Chromium) 2017/06/01 20:23:16 Done.
325 if (type == PHONE_HOME_CITY_AND_NUMBER)
326 collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
327 else
328 collapsed_field_types.insert(AutofillType(type).GetStorableType());
329 }
330
331 // Capture the field's type, if it is unambiguous.
332 ServerFieldType actual_type = AMBIGUOUS_TYPE;
333 if (collapsed_field_types.size() == 1)
334 actual_type = *collapsed_field_types.begin();
335
336 DVLOG(2) << "Inferred Type: " << AutofillType(actual_type).ToString();
337 return actual_type;
338 }
339
340 // Logs field type prediction quality metrics. The primary histogram name is
341 // constructed based on |source| The field-specific histogram name also factors
342 // possible and predicted field types (|possible_types| and |predicted_type|,
343 // respectively). May log a suffixed version of the metric depending on
344 // |metric_type|.
345 void LogPredictionQualityMetrics(
346 const base::StringPiece& source,
347 const ServerFieldTypeSet& possible_types,
348 ServerFieldType predicted_type,
349 AutofillMetrics::QualityMetricType metric_type) {
350 // Generate histogram names.
351 const char* const suffix = GetQualityMetricTypeSuffix(metric_type);
352 std::string raw_data_histogram =
353 base::JoinString({"Autofill.FieldPrediction.", source, suffix}, "");
354 std::string aggregate_histogram = base::JoinString(
355 {"Autofill.FieldPredictionQuality.Aggregate.", source, suffix}, "");
356 std::string type_specific_histogram = base::JoinString(
357 {"Autofill.FieldPredictionQuality.ByFieldType.", source, suffix}, "");
358
359 // Get the best type classification we can for the field.
360 ServerFieldType actual_type =
361 GetActualFieldType(possible_types, predicted_type);
362
363 DVLOG(2) << "Predicted: " << AutofillType(predicted_type).ToString() << "; "
364 << "Actual: " << AutofillType(actual_type).ToString();
365
366 DCHECK_LE(predicted_type, UINT16_MAX);
367 DCHECK_LE(actual_type, UINT16_MAX);
368 UMA_HISTOGRAM_SPARSE_SLOWLY(raw_data_histogram,
369 (predicted_type << 16) | actual_type);
370
371 // NO_SERVER_DATA is the equivalent of predicting UNKNOWN.
372 if (predicted_type == NO_SERVER_DATA)
373 predicted_type = UNKNOWN_TYPE;
374
375 // The actual type being EMPTY_TYPE is the same as UNKNOWN_TYPE for comparison
376 // purposes, but remember whether or not it was empty for more precise logging
377 // later.
378 bool is_empty = (actual_type == EMPTY_TYPE);
379 bool is_ambiguous = (actual_type == AMBIGUOUS_TYPE);
380 if (is_empty || is_ambiguous)
381 actual_type = UNKNOWN_TYPE;
382
383 // If the predicted and actual types match then it's either a true positive
384 // or a true negative (if they are both unknown). Do not log type specific
385 // true negatives (instead log a true positive for the "Ambiguous" type).
386 if (predicted_type == actual_type) {
387 if (actual_type == UNKNOWN_TYPE) {
388 // Only log aggregate true negative; do not log type specific metrics
389 // for UNKNOWN/EMPTY.
390 DVLOG(2) << "TRUE NEGATIVE";
391 LogUMAHistogramEnumeration(
392 aggregate_histogram,
393 (is_empty ? AutofillMetrics::TRUE_NEGATIVE_EMPTY
394 : (is_ambiguous ? AutofillMetrics::TRUE_NEGATIVE_AMBIGUOUS
395 : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN)),
396 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
397 return;
398 }
399
400 DVLOG(2) << "TRUE POSITIVE";
401 // Log both aggregate and type specific true positive if we correctly
402 // predict that type with which the field was filled.
403 LogUMAHistogramEnumeration(aggregate_histogram,
404 AutofillMetrics::TRUE_POSITIVE,
405 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
406 LogUMAHistogramEnumeration(
407 type_specific_histogram,
408 GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE),
409 KMaxFieldTypeGroupMetric);
410 return;
411 }
412
413 // Note: At this point predicted_type != actual type
414 // If actual type is UNKNOWN_TYPE then the prediction is a false positive.
415 // Further specialize the type of false positive by whether the field was
416 // empty or contained an unknown value.
417 if (actual_type == UNKNOWN_TYPE) {
418 DVLOG(2) << "FALSE POSITIVE";
419 auto metric =
420 (is_empty ? AutofillMetrics::FALSE_POSITIVE_EMPTY
421 : (is_ambiguous ? AutofillMetrics::FALSE_POSITIVE_AMBIGUOUS
422 : AutofillMetrics::FALSE_POSITIVE_UNKNOWN));
423 LogUMAHistogramEnumeration(aggregate_histogram, metric,
424 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
425 LogUMAHistogramEnumeration(type_specific_histogram,
426 GetFieldTypeGroupMetric(predicted_type, metric),
427 KMaxFieldTypeGroupMetric);
428 return;
429 }
430
431 // Note: At this point predicted_type != actual type, actual_type != UNKNOWN.
432 // If predicted type is UNKNOWN_TYPE then the prediction is a false negative
433 // unknown.
434 if (predicted_type == UNKNOWN_TYPE) {
435 DVLOG(2) << "FALSE NEGATIVE";
436 LogUMAHistogramEnumeration(aggregate_histogram,
437 AutofillMetrics::FALSE_NEGATIVE_UNKNOWN,
438 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
439 LogUMAHistogramEnumeration(
440 type_specific_histogram,
441 GetFieldTypeGroupMetric(actual_type,
442 AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
443 KMaxFieldTypeGroupMetric);
444 return;
445 }
446
447 DVLOG(2) << "MISMATCH";
448
449 // Note: At this point predicted_type != actual type, actual_type != UNKNOWN,
450 // predicted_type != UNKNOWN.
451 // This is a mismatch. From the reference of the actual type, this is a false
452 // negative (it was T, but predicted U). From the reference of the prediction,
453 // this is a false positive (predicted it was T, but it was U).
454 LogUMAHistogramEnumeration(aggregate_histogram,
455 AutofillMetrics::FALSE_NEGATIVE_MISMATCH,
296 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); 456 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS);
297 457 LogUMAHistogramEnumeration(
298 int field_type_group_metric = GetFieldTypeGroupMetric(field_type, metric); 458 type_specific_histogram,
299 int num_field_type_group_metrics = 459 GetFieldTypeGroupMetric(actual_type,
300 AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS * 460 AutofillMetrics::FALSE_NEGATIVE_MISMATCH),
301 NUM_FIELD_TYPE_GROUPS_FOR_METRICS; 461 KMaxFieldTypeGroupMetric);
302 LogUMAHistogramEnumeration(base_name + ".ByFieldType" + suffix, 462 LogUMAHistogramEnumeration(
303 field_type_group_metric, 463 type_specific_histogram,
304 num_field_type_group_metrics); 464 GetFieldTypeGroupMetric(predicted_type,
465 AutofillMetrics::FALSE_POSITIVE_MISMATCH),
466 KMaxFieldTypeGroupMetric);
305 } 467 }
306 468
307 } // namespace 469 } // namespace
308 470
309 // static 471 // static
310 void AutofillMetrics::LogCardUploadDecisionMetrics( 472 void AutofillMetrics::LogCardUploadDecisionMetrics(
311 int upload_decision_metrics) { 473 int upload_decision_metrics) {
312 DCHECK(upload_decision_metrics); 474 DCHECK(upload_decision_metrics);
313 DCHECK_LT(upload_decision_metrics, 1 << kNumCardUploadDecisionMetrics); 475 DCHECK_LT(upload_decision_metrics, 1 << kNumCardUploadDecisionMetrics);
314 476
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 } 655 }
494 656
495 // static 657 // static
496 void AutofillMetrics::LogDeveloperEngagementMetric( 658 void AutofillMetrics::LogDeveloperEngagementMetric(
497 DeveloperEngagementMetric metric) { 659 DeveloperEngagementMetric metric) {
498 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS); 660 DCHECK_LT(metric, NUM_DEVELOPER_ENGAGEMENT_METRICS);
499 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric, 661 UMA_HISTOGRAM_ENUMERATION("Autofill.DeveloperEngagement", metric,
500 NUM_DEVELOPER_ENGAGEMENT_METRICS); 662 NUM_DEVELOPER_ENGAGEMENT_METRICS);
501 } 663 }
502 664
503 // static 665 void AutofillMetrics::LogHeuristicPredictionQualityMetrics(
504 void AutofillMetrics::LogHeuristicTypePrediction( 666 const ServerFieldTypeSet& possible_types,
505 FieldTypeQualityMetric metric, 667 ServerFieldType predicted_type,
506 ServerFieldType field_type, 668 AutofillMetrics::QualityMetricType metric_type) {
507 QualityMetricType metric_type) { 669 LogPredictionQualityMetrics("Heuristic", possible_types, predicted_type,
508 LogTypeQualityMetric("Autofill.Quality.HeuristicType", metric, field_type, 670 metric_type);
509 metric_type); 671 }
672
673 void AutofillMetrics::LogServerPredictionQualityMetrics(
674 const ServerFieldTypeSet& possible_types,
675 ServerFieldType predicted_type,
676 AutofillMetrics::QualityMetricType metric_type) {
677 LogPredictionQualityMetrics("Server", possible_types, predicted_type,
678 metric_type);
679 }
680
681 void AutofillMetrics::LogOverallPredictionQualityMetrics(
682 const ServerFieldTypeSet& possible_types,
683 ServerFieldType predicted_type,
684 AutofillMetrics::QualityMetricType metric_type) {
685 LogPredictionQualityMetrics("Overall", possible_types, predicted_type,
686 metric_type);
510 } 687 }
511 688
512 // static 689 // static
513 void AutofillMetrics::LogOverallTypePrediction(FieldTypeQualityMetric metric,
514 ServerFieldType field_type,
515 QualityMetricType metric_type) {
516 LogTypeQualityMetric("Autofill.Quality.PredictedType", metric, field_type,
517 metric_type);
518 }
519
520 // static
521 void AutofillMetrics::LogServerTypePrediction(FieldTypeQualityMetric metric,
522 ServerFieldType field_type,
523 QualityMetricType metric_type) {
524 LogTypeQualityMetric("Autofill.Quality.ServerType", metric, field_type,
525 metric_type);
526 }
527
528 // static
529 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) { 690 void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) {
530 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS); 691 DCHECK_LT(metric, NUM_SERVER_QUERY_METRICS);
531 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric, 692 UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
532 NUM_SERVER_QUERY_METRICS); 693 NUM_SERVER_QUERY_METRICS);
533 } 694 }
534 695
535 // static 696 // static
536 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) { 697 void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) {
537 DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS); 698 DCHECK_LT(metric, NUM_USER_HAPPINESS_METRICS);
538 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric, 699 UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after
1181 DCHECK(!form_parsed_timestamp_.is_null()); 1342 DCHECK(!form_parsed_timestamp_.is_null());
1182 return (base::TimeTicks::Now() - form_parsed_timestamp_).InMilliseconds(); 1343 return (base::TimeTicks::Now() - form_parsed_timestamp_).InMilliseconds();
1183 } 1344 }
1184 1345
1185 void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() { 1346 void AutofillMetrics::FormInteractionsUkmLogger::GetNewSourceID() {
1186 source_id_ = ukm_recorder_->GetNewSourceID(); 1347 source_id_ = ukm_recorder_->GetNewSourceID();
1187 ukm_recorder_->UpdateSourceURL(source_id_, url_); 1348 ukm_recorder_->UpdateSourceURL(source_id_, url_);
1188 } 1349 }
1189 1350
1190 } // namespace autofill 1351 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698