blob: ebc15e4e152a994843cf39cb3440ef2f3ae8ecd1 [file] [log] [blame] [edit]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VM_TOOLS_SOMMELIER_SOMMELIER_TIMING_H_
#define VM_TOOLS_SOMMELIER_SOMMELIER_TIMING_H_
#include <list>
#include <map>
#include <stdint.h>
#include <string>
#include <time.h>
const int kUnknownBufferId = -1;
const int kUnknownSurfaceId = -1;
class Timing {
public:
explicit Timing(const char* fname) : filename(fname) {}
void RecordStartTime();
void UpdateLastAttach(int surface_id, int buffer_id);
void UpdateLastCommit(int surface_id);
void UpdateLastRelease(int buffer_id);
void OutputLog();
private:
// 10 min * 60 sec/min * 60 frames/sec * 3 actions/frame = 108000 actions
static const int kMaxNumActions = 10 * 60 * 60 * 3;
struct BufferAction {
enum Type { UNKNOWN, ATTACH, COMMIT, RELEASE };
int64_t delta_time;
int surface_id;
int buffer_id;
Type action_type;
BufferAction()
: surface_id(kUnknownSurfaceId),
buffer_id(kUnknownBufferId),
action_type(UNKNOWN) {}
explicit BufferAction(int64_t dt,
int sid = kUnknownSurfaceId,
int bid = kUnknownBufferId,
Type type = UNKNOWN)
: delta_time(dt), surface_id(sid), buffer_id(bid), action_type(type) {}
};
BufferAction actions[kMaxNumActions];
int event_id = 0;
int saves = 0;
const char* filename;
timespec last_event;
int64_t GetTime();
}; // class Timing
// SurfaceStats tracks statistics for a single surface in a number of
// discrete contiguous windows. Besides for some very basic accounting
// and state to track across separate windows, state is reset between
// windows.
class SurfaceStats {
public:
SurfaceStats();
// Resets the state to start tracking a new reporting window.
void StartNewWindow();
void AddFrame(uint32_t steam_id, bool activated);
int GetNumFrames() const { return num_frames; }
std::string Summarize(int surface_id) const;
static std::string GenerateHeader();
private:
// Number of buckets to internally accumulate to. Internally more buckets
// are tracked to give reasonable precision for the percentiles.
static const int kMaxBuckets = 200;
// Size of each bucket in fps.
static constexpr double kBucketSize = 1.0f;
// The number of internal buckets (of kBucketSize) to merge to form each
// of the externally logged buckets. Resulting logged bucket size is
// kLogBuckets * kBucketSize. Externally less buckets are shown to
// avoid too much information/space while still allow characterization of
// the data.
static const int kLogBuckets = 5;
// Threshold for slow frames expressed as a ration of the median.
static constexpr double kSlowFrameThresholdRatio = 0.8f;
// Tracks the start of the surface being tracked at all.
timespec start_event;
// Timestamps of the first and last frames of the current reporting period.
timespec first_event;
timespec last_event;
// The total number of frames seen on this surface since statistics
// started being tracked.
int total_frames;
// The rest of the statistics apply to the current reporting period only.
// Steam game id as reported by the game, if available.
uint32_t steam_game_id;
// The number of frames in the current reporting period.
int num_frames;
// The number of frames where the window was activated at the time of the
// frame being committed, in the current reporting period.
int num_activated;
// The running mean fps, per Welford's online algorithm for computing
// variance.
double mean_fps;
// The aggregated squared distance from the the mean, per Welford's
// online algorithm.
double sq_dist_mean;
// The minimum per-frame fps seen in the current reporting period.
double min_fps;
// The maximum per-frame fps seen in the current reporting period.
double max_fps;
// Histogram of frame timings, each bucket of kBucketSize fps.
// The histogram should be sized to give a good view into .1% and 1%
// low fps on a typical reporting period.
int buckets[kMaxBuckets];
static double GetBucketValue(int bucket_num);
double EstimatePercentile(double percentile) const;
int CountSlowFrames(double threshold) const;
}; // class SurfaceStats
class FrameStats {
public:
explicit FrameStats(const char* stats_name, const char* log_name)
: filename(stats_name), log_filename(log_name) {}
void AddFrame(int surface_id, uint32_t steam_id, bool activated);
void OutputStats();
private:
// Total number of log lines across all surfaces.
static const int kMaxLogSize = 60;
const char* filename;
const char* log_filename;
std::map<int, SurfaceStats> surface_stats;
std::string header;
std::list<std::string> recent_logs;
}; // class FrameStats
#endif // VM_TOOLS_SOMMELIER_SOMMELIER_TIMING_H_