pending_operations.cc 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // Copyright 2022 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. #include "media/capabilities/pending_operations.h"
  5. #include <string>
  6. #include "base/bind.h"
  7. #include "base/logging.h"
  8. #include "base/metrics/histogram_functions.h"
  9. #include "base/threading/thread_task_runner_handle.h"
  10. namespace media {
  11. namespace {
  12. // Timeout threshold for DB operations. See OnOperationTimeout().
  13. // NOTE: Used by UmaHistogramOpTime. Change the name if you change the time.
  14. static constexpr base::TimeDelta kPendingOpTimeout = base::Seconds(30);
  15. } // namespace
  16. PendingOperations::PendingOperation::PendingOperation(
  17. const std::string& uma_prefix,
  18. std::string uma_str,
  19. std::unique_ptr<base::CancelableOnceClosure> timeout_closure)
  20. : uma_prefix_(uma_prefix),
  21. uma_str_(uma_str),
  22. timeout_closure_(std::move(timeout_closure)),
  23. start_ticks_(base::TimeTicks::Now()) {
  24. DVLOG(3) << __func__ << " Started " << uma_str_;
  25. }
  26. PendingOperations::PendingOperation::~PendingOperation() {
  27. // Destroying a pending operation that hasn't timed out yet implies the
  28. // operation has completed.
  29. if (timeout_closure_ && !timeout_closure_->IsCancelled()) {
  30. base::TimeDelta op_duration = base::TimeTicks::Now() - start_ticks_;
  31. UmaHistogramOpTime(uma_str_, op_duration);
  32. DVLOG(3) << __func__ << " Completed " << uma_str_ << " ("
  33. << op_duration.InMilliseconds() << ")";
  34. // Ensure the timeout doesn't fire. Destruction should cancel the callback
  35. // implicitly, but that's not a documented contract, so just taking the safe
  36. // route.
  37. timeout_closure_->Cancel();
  38. }
  39. }
  40. void PendingOperations::PendingOperation::UmaHistogramOpTime(
  41. const std::string& op_name,
  42. base::TimeDelta duration) {
  43. base::UmaHistogramCustomMicrosecondsTimes(uma_prefix_ + op_name, duration,
  44. base::Milliseconds(1),
  45. kPendingOpTimeout, 50);
  46. }
  47. void PendingOperations::PendingOperation::OnTimeout() {
  48. UmaHistogramOpTime(uma_str_, kPendingOpTimeout);
  49. LOG(WARNING) << " Timeout performing " << uma_str_
  50. << " operation on WebrtcVideoStatsDB";
  51. // Cancel the closure to ensure we don't double report the task as completed
  52. // in ~PendingOperation().
  53. timeout_closure_->Cancel();
  54. }
  55. PendingOperations::PendingOperations(std::string uma_prefix)
  56. : uma_prefix_(uma_prefix) {}
  57. PendingOperations::~PendingOperations() {
  58. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  59. }
  60. PendingOperations::Id PendingOperations::Start(std::string uma_str) {
  61. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  62. Id op_id = next_op_id_++;
  63. auto timeout_closure = std::make_unique<base::CancelableOnceClosure>(
  64. base::BindOnce(&PendingOperations::OnTimeout,
  65. weak_ptr_factory_.GetWeakPtr(), op_id));
  66. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  67. FROM_HERE, timeout_closure->callback(), kPendingOpTimeout);
  68. pending_ops_.emplace(
  69. op_id, std::make_unique<PendingOperation>(uma_prefix_, uma_str,
  70. std::move(timeout_closure)));
  71. return op_id;
  72. }
  73. void PendingOperations::Complete(Id op_id) {
  74. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  75. // Destructing the PendingOperation will trigger UMA for completion timing.
  76. int count = pending_ops_.erase(op_id);
  77. // No big deal, but very unusual. Timeout is very generous, so tasks that
  78. // timeout are generally assumed to be permanently hung.
  79. if (!count)
  80. DVLOG(2) << __func__ << " DB operation completed after timeout.";
  81. }
  82. void PendingOperations::OnTimeout(Id op_id) {
  83. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  84. auto it = pending_ops_.find(op_id);
  85. DCHECK(it != pending_ops_.end());
  86. it->second->OnTimeout();
  87. pending_ops_.erase(it);
  88. }
  89. } // namespace media