blob: accd0a2e40feaa15e834ddc3d591b385ec573fc0 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_SCENIC_LIB_SCHEDULING_FRAME_STATS_H_
#define SRC_UI_SCENIC_LIB_SCHEDULING_FRAME_STATS_H_
#include <lib/async/cpp/task.h>
#include <lib/zx/time.h>
#include <deque>
#include <functional>
#include "lib/inspect/cpp/inspect.h"
#include "src/lib/cobalt/cpp/cobalt_logger.h"
#include "src/ui/scenic/lib/scheduling/frame_scheduler.h"
#include "third_party/cobalt/src/registry/buckets_config.h"
namespace scheduling {
// Class for managing and reporting frame stats from FrameScheduler. Used for debug data, i.e.
// inspect.
class FrameStats {
public:
FrameStats(inspect::Node inspect_node, std::shared_ptr<cobalt::CobaltLogger> cobalt_logger);
struct Timestamps {
zx::time latch_point_time;
zx::time render_start_time;
zx::time render_done_time;
zx::time target_presentation_time;
zx::time actual_presentation_time;
};
void RecordFrame(Timestamps timestamps, zx::duration display_vsync_interval);
// Time interval between each flush is 10 minutes.
static constexpr zx::duration kCobaltDataCollectionInterval = zx::min(10);
private:
typedef std::unordered_map<uint32_t, uint32_t> CobaltFrameHistogram;
static constexpr size_t kNumFramesToReport = 200;
static constexpr size_t kNumDroppedFramesToReport = 50;
static constexpr size_t kNumDelayedFramesToReport = 50;
static constexpr size_t kNumMinutesHistory = 10;
struct HistoryStats {
// The key for this history.
// Calculated by truncating the frame timestamp (to minutes).
//
// This denotes the interval for the following measurements.
uint64_t key;
// The total number of frames that attempted rendering during the interval.
uint64_t total_frames;
// The total number of frames that were successfully rendered during the interval.
uint64_t rendered_frames;
// The number of rendered frames that were delayed during the interval.
uint64_t delayed_rendered_frames;
// The total amount of time spent rendering the rendered frames during the interval.
zx::duration render_time;
// The total amount of time spent rendering just the delayed frames during the interval.
zx::duration delayed_frame_render_time;
// The total number of frames that were dropped during the interval.
uint64_t dropped_frames;
HistoryStats& operator+=(const HistoryStats& other) {
key = std::max(key, other.key);
total_frames += other.total_frames;
rendered_frames += other.rendered_frames;
delayed_rendered_frames += other.delayed_rendered_frames;
render_time += other.render_time;
delayed_frame_render_time += other.delayed_frame_render_time;
dropped_frames += other.dropped_frames;
return *this;
}
template <typename T>
void RecordToNode(inspect::Node* node, T* list) const {
node->CreateUint("minute_key", key, list);
node->CreateInt("total_frames", total_frames, list);
node->CreateInt("rendered_frames", rendered_frames, list);
node->CreateInt("delayed_rendered_frames", delayed_rendered_frames, list);
node->CreateInt("render_time_ns", render_time.get(), list);
node->CreateInt("delayed_frame_render_time_ns", delayed_frame_render_time.get(), list);
node->CreateInt("dropped_frames", dropped_frames, list);
if (rendered_frames) {
node->CreateInt("Average Time Per Frame (ms)", render_time.to_msecs() / rendered_frames,
list);
node->CreateInt("Average Frames Per Second", zx::sec(1) / (render_time / rendered_frames),
list);
}
if (delayed_rendered_frames) {
node->CreateInt("Average Time Per Delayed Frame (ms)",
delayed_frame_render_time.to_msecs() / delayed_rendered_frames, list);
}
}
};
static zx::duration CalculateMeanDuration(
const std::deque<Timestamps>& timestamps,
std::function<zx::duration(const Timestamps&)> duration_func, uint32_t percentile);
void AddHistory(const HistoryStats& stats);
void RecordDroppedFrame(const Timestamps& timestamps);
void RecordDelayedFrame(const Timestamps& timestamps);
void RecordOnTimeFrame(const Timestamps& timestamps);
void ReportStats(inspect::Inspector* insp) const;
// Note that both scenic_render_time and scenic_latch_to_actual_presentation
// metrics in Cobalt has the same histogram settings. Therefore we create only
// one bucket config for both usages.
void InitializeFrameTimeBucketConfig();
uint32_t GetCobaltBucketIndex(zx::duration duration);
// Flush all histograms into Cobalt and empty them.
void LogFrameTimes();
// Helper function to convert histograms in unordered_map format to Cobalt-readable
// vector of histogram buckets.
std::vector<fuchsia::cobalt::HistogramBucket> CreateCobaltBucketsFromHistogram(
const CobaltFrameHistogram& histogram);
uint64_t frame_count_ = 0;
uint64_t dropped_frame_count_ = 0;
uint64_t delayed_frame_count_ = 0;
// Ring buffer of the last kNum*FramesToReport.
std::deque<Timestamps> frame_times_;
std::deque<Timestamps> dropped_frames_;
std::deque<Timestamps> delayed_frames_;
// Ring buffer of stats for the last kNumMinutesHistory minutes of frame timings.
std::deque<HistoryStats> history_stats_;
inspect::Node inspect_node_;
inspect::LazyNode inspect_frame_stats_dump_;
// Histograms for collecting latch point to actual presentation times.
CobaltFrameHistogram cobalt_on_time_frame_times_histogram_;
CobaltFrameHistogram cobalt_dropped_frame_times_histogram_;
CobaltFrameHistogram cobalt_delayed_frame_times_histogram_;
// Histogram for collecting render start to render done times.
CobaltFrameHistogram cobalt_render_times_histogram_;
// Used for getting the cobalt histogram bucket number given a frame time number.
std::unique_ptr<cobalt::config::IntegerBucketConfig> frame_times_bucket_config_;
std::shared_ptr<cobalt::CobaltLogger> cobalt_logger_;
async::TaskClosureMethod<FrameStats, &FrameStats::LogFrameTimes> cobalt_logging_task_{this};
};
} // namespace scheduling
#endif // SRC_UI_SCENIC_LIB_SCHEDULING_FRAME_STATS_H_