1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135

cc / raster / raster_query_queue.cc [blame]

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/raster/raster_query_queue.h"

#include <utility>

#include "base/strings/stringprintf.h"
#include "cc/base/histograms.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/raster_interface.h"

namespace cc {

RasterQuery::RasterQuery() = default;

RasterQuery::~RasterQuery() = default;

RasterQueryQueue::RasterQueryQueue(
    viz::RasterContextProvider* const worker_context_provider)
    : worker_context_provider_(worker_context_provider) {}

RasterQueryQueue::~RasterQueryQueue() = default;

void RasterQueryQueue::Append(RasterQuery raster_query) {
  // It is important for this method to not be called with the raster context
  // lock to avoid a deadlock in CheckRasterFinishedQueries, which acquired
  // the raster context lock while holding this lock.
  base::AutoLock hold(pending_raster_queries_lock_);
  pending_raster_queries_.push_back(std::move(raster_query));
}

#define UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(name, total_time) \
  UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(                              \
      name, total_time, base::Microseconds(1), base::Milliseconds(100), 100);

bool RasterQueryQueue::CheckRasterFinishedQueries() {
  base::AutoLock hold(pending_raster_queries_lock_);
  if (pending_raster_queries_.empty())
    return false;

  viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
      worker_context_provider_);
  auto* ri = scoped_context.RasterInterface();

  auto it = pending_raster_queries_.begin();
  while (it != pending_raster_queries_.end()) {
    GLuint complete = 0;
    ri->GetQueryObjectuivEXT(it->raster_duration_query_id,
                             GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT,
                             &complete);
    if (!complete)
      break;

#if DCHECK_IS_ON()
    if (it->raster_start_query_id) {
      // We issued the GL_COMMANDS_ISSUED_TIMESTAMP_CHROMIUM query prior to the
      // GL_COMMANDS_ISSUED_CHROMIUM query. Therefore, if the result of the
      // latter is available, the result of the former should be too.
      complete = 0;
      ri->GetQueryObjectuivEXT(it->raster_start_query_id,
                               GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT,
                               &complete);
      DCHECK(complete);
    }
#endif

    GLuint gpu_raster_duration = 0u;
    ri->GetQueryObjectuivEXT(it->raster_duration_query_id, GL_QUERY_RESULT_EXT,
                             &gpu_raster_duration);
    ri->DeleteQueriesEXT(1, &it->raster_duration_query_id);

    base::TimeDelta raster_duration =
        it->worker_raster_duration + base::Microseconds(gpu_raster_duration);

    // It is safe to use the UMA macros here with runtime generated strings
    // because the client name should be initialized once in the process, before
    // recording any metrics here.
    const char* client_name = GetClientNameForMetrics();

    if (it->raster_start_query_id) {
      GLuint64 gpu_raster_start_time = 0u;
      ri->GetQueryObjectui64vEXT(it->raster_start_query_id, GL_QUERY_RESULT_EXT,
                                 &gpu_raster_start_time);
      ri->DeleteQueriesEXT(1, &it->raster_start_query_id);

      // The base::checked_cast<int64_t> should not crash as long as the GPU
      // process was not compromised: that's because the result of the query
      // should have been generated using base::TimeDelta::InMicroseconds()
      // there, so the result should fit in an int64_t.
      base::TimeDelta raster_scheduling_delay =
          base::Microseconds(
              base::checked_cast<int64_t>(gpu_raster_start_time)) -
          it->raster_buffer_creation_time.since_origin();

      // We expect the clock we're using to be monotonic, so we shouldn't get a
      // negative scheduling delay.
      DCHECK_GE(raster_scheduling_delay.InMicroseconds(), 0u);
      UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
          base::StringPrintf(
              "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes.All",
              client_name),
          raster_scheduling_delay);
      if (it->depends_on_hardware_accelerated_jpeg_candidates) {
        UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
            base::StringPrintf(
                "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes."
                "TilesWithJpegHwDecodeCandidates",
                client_name),
            raster_scheduling_delay);
      }
      if (it->depends_on_hardware_accelerated_webp_candidates) {
        UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
            base::StringPrintf(
                "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes."
                "TilesWithWebPHwDecodeCandidates",
                client_name),
            raster_scheduling_delay);
      }
    }

    UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
        base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Oop",
                           client_name),
        raster_duration);

    it = pending_raster_queries_.erase(it);
  }

  return pending_raster_queries_.size() > 0u;
}

}  // namespace cc