xref: /dflybsd-src/sys/dev/drm/amd/display/modules/stats/stats.c (revision b843c749addef9340ee7d4e250b09fdd492602a1)
1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev  * Copyright 2016 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev  *
4*b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5*b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6*b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7*b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9*b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10*b843c749SSergey Zigachev  *
11*b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12*b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13*b843c749SSergey Zigachev  *
14*b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21*b843c749SSergey Zigachev  *
22*b843c749SSergey Zigachev  * Authors: AMD
23*b843c749SSergey Zigachev  *
24*b843c749SSergey Zigachev  */
25*b843c749SSergey Zigachev 
26*b843c749SSergey Zigachev #include "mod_stats.h"
27*b843c749SSergey Zigachev #include "dm_services.h"
28*b843c749SSergey Zigachev #include "dc.h"
29*b843c749SSergey Zigachev #include "core_types.h"
30*b843c749SSergey Zigachev 
31*b843c749SSergey Zigachev #define DAL_STATS_ENABLE_REGKEY			"DalStatsEnable"
32*b843c749SSergey Zigachev #define DAL_STATS_ENABLE_REGKEY_DEFAULT		0x00000000
33*b843c749SSergey Zigachev #define DAL_STATS_ENABLE_REGKEY_ENABLED		0x00000001
34*b843c749SSergey Zigachev 
35*b843c749SSergey Zigachev #define DAL_STATS_ENTRIES_REGKEY		"DalStatsEntries"
36*b843c749SSergey Zigachev #define DAL_STATS_ENTRIES_REGKEY_DEFAULT	0x00350000
37*b843c749SSergey Zigachev #define DAL_STATS_ENTRIES_REGKEY_MAX		0x01000000
38*b843c749SSergey Zigachev 
39*b843c749SSergey Zigachev #define DAL_STATS_EVENT_ENTRIES_DEFAULT		0x00000100
40*b843c749SSergey Zigachev 
41*b843c749SSergey Zigachev #define MOD_STATS_NUM_VSYNCS			5
42*b843c749SSergey Zigachev #define MOD_STATS_EVENT_STRING_MAX		512
43*b843c749SSergey Zigachev 
44*b843c749SSergey Zigachev struct stats_time_cache {
45*b843c749SSergey Zigachev 	unsigned int entry_id;
46*b843c749SSergey Zigachev 
47*b843c749SSergey Zigachev 	unsigned long flip_timestamp_in_ns;
48*b843c749SSergey Zigachev 	unsigned long vupdate_timestamp_in_ns;
49*b843c749SSergey Zigachev 
50*b843c749SSergey Zigachev 	unsigned int render_time_in_us;
51*b843c749SSergey Zigachev 	unsigned int avg_render_time_in_us_last_ten;
52*b843c749SSergey Zigachev 	unsigned int v_sync_time_in_us[MOD_STATS_NUM_VSYNCS];
53*b843c749SSergey Zigachev 	unsigned int num_vsync_between_flips;
54*b843c749SSergey Zigachev 
55*b843c749SSergey Zigachev 	unsigned int flip_to_vsync_time_in_us;
56*b843c749SSergey Zigachev 	unsigned int vsync_to_flip_time_in_us;
57*b843c749SSergey Zigachev 
58*b843c749SSergey Zigachev 	unsigned int min_window;
59*b843c749SSergey Zigachev 	unsigned int max_window;
60*b843c749SSergey Zigachev 	unsigned int v_total_min;
61*b843c749SSergey Zigachev 	unsigned int v_total_max;
62*b843c749SSergey Zigachev 	unsigned int event_triggers;
63*b843c749SSergey Zigachev 
64*b843c749SSergey Zigachev 	unsigned int lfc_mid_point_in_us;
65*b843c749SSergey Zigachev 	unsigned int num_frames_inserted;
66*b843c749SSergey Zigachev 	unsigned int inserted_duration_in_us;
67*b843c749SSergey Zigachev 
68*b843c749SSergey Zigachev 	unsigned int flags;
69*b843c749SSergey Zigachev };
70*b843c749SSergey Zigachev 
71*b843c749SSergey Zigachev struct stats_event_cache {
72*b843c749SSergey Zigachev 	unsigned int entry_id;
73*b843c749SSergey Zigachev 	char event_string[MOD_STATS_EVENT_STRING_MAX];
74*b843c749SSergey Zigachev };
75*b843c749SSergey Zigachev 
76*b843c749SSergey Zigachev struct core_stats {
77*b843c749SSergey Zigachev 	struct mod_stats public;
78*b843c749SSergey Zigachev 	struct dc *dc;
79*b843c749SSergey Zigachev 
80*b843c749SSergey Zigachev 	bool enabled;
81*b843c749SSergey Zigachev 	unsigned int entries;
82*b843c749SSergey Zigachev 	unsigned int event_entries;
83*b843c749SSergey Zigachev 	unsigned int entry_id;
84*b843c749SSergey Zigachev 
85*b843c749SSergey Zigachev 	struct stats_time_cache *time;
86*b843c749SSergey Zigachev 	unsigned int index;
87*b843c749SSergey Zigachev 
88*b843c749SSergey Zigachev 	struct stats_event_cache *events;
89*b843c749SSergey Zigachev 	unsigned int event_index;
90*b843c749SSergey Zigachev 
91*b843c749SSergey Zigachev };
92*b843c749SSergey Zigachev 
93*b843c749SSergey Zigachev #define MOD_STATS_TO_CORE(mod_stats)\
94*b843c749SSergey Zigachev 		container_of(mod_stats, struct core_stats, public)
95*b843c749SSergey Zigachev 
mod_stats_init(struct mod_stats * mod_stats)96*b843c749SSergey Zigachev bool mod_stats_init(struct mod_stats *mod_stats)
97*b843c749SSergey Zigachev {
98*b843c749SSergey Zigachev 	bool result = false;
99*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
100*b843c749SSergey Zigachev 	struct dc *dc = NULL;
101*b843c749SSergey Zigachev 
102*b843c749SSergey Zigachev 	if (mod_stats == NULL)
103*b843c749SSergey Zigachev 		return false;
104*b843c749SSergey Zigachev 
105*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
106*b843c749SSergey Zigachev 	dc = core_stats->dc;
107*b843c749SSergey Zigachev 
108*b843c749SSergey Zigachev 	return result;
109*b843c749SSergey Zigachev }
110*b843c749SSergey Zigachev 
mod_stats_create(struct dc * dc)111*b843c749SSergey Zigachev struct mod_stats *mod_stats_create(struct dc *dc)
112*b843c749SSergey Zigachev {
113*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
114*b843c749SSergey Zigachev 	struct persistent_data_flag flag;
115*b843c749SSergey Zigachev 	unsigned int reg_data;
116*b843c749SSergey Zigachev 	int i = 0;
117*b843c749SSergey Zigachev 
118*b843c749SSergey Zigachev 	if (dc == NULL)
119*b843c749SSergey Zigachev 		goto fail_construct;
120*b843c749SSergey Zigachev 
121*b843c749SSergey Zigachev 	core_stats = kzalloc(sizeof(struct core_stats), GFP_KERNEL);
122*b843c749SSergey Zigachev 
123*b843c749SSergey Zigachev 	if (core_stats == NULL)
124*b843c749SSergey Zigachev 		goto fail_construct;
125*b843c749SSergey Zigachev 
126*b843c749SSergey Zigachev 	core_stats->dc = dc;
127*b843c749SSergey Zigachev 
128*b843c749SSergey Zigachev 	core_stats->enabled = DAL_STATS_ENABLE_REGKEY_DEFAULT;
129*b843c749SSergey Zigachev 	if (dm_read_persistent_data(dc->ctx, NULL, NULL,
130*b843c749SSergey Zigachev 			DAL_STATS_ENABLE_REGKEY,
131*b843c749SSergey Zigachev 			&reg_data, sizeof(unsigned int), &flag))
132*b843c749SSergey Zigachev 		core_stats->enabled = reg_data;
133*b843c749SSergey Zigachev 
134*b843c749SSergey Zigachev 	if (core_stats->enabled) {
135*b843c749SSergey Zigachev 		core_stats->entries = DAL_STATS_ENTRIES_REGKEY_DEFAULT;
136*b843c749SSergey Zigachev 		if (dm_read_persistent_data(dc->ctx, NULL, NULL,
137*b843c749SSergey Zigachev 				DAL_STATS_ENTRIES_REGKEY,
138*b843c749SSergey Zigachev 				&reg_data, sizeof(unsigned int), &flag)) {
139*b843c749SSergey Zigachev 			if (reg_data > DAL_STATS_ENTRIES_REGKEY_MAX)
140*b843c749SSergey Zigachev 				core_stats->entries = DAL_STATS_ENTRIES_REGKEY_MAX;
141*b843c749SSergey Zigachev 			else
142*b843c749SSergey Zigachev 				core_stats->entries = reg_data;
143*b843c749SSergey Zigachev 		}
144*b843c749SSergey Zigachev 		core_stats->time = kcalloc(core_stats->entries,
145*b843c749SSergey Zigachev 						sizeof(struct stats_time_cache),
146*b843c749SSergey Zigachev 						GFP_KERNEL);
147*b843c749SSergey Zigachev 
148*b843c749SSergey Zigachev 		if (core_stats->time == NULL)
149*b843c749SSergey Zigachev 			goto fail_construct_time;
150*b843c749SSergey Zigachev 
151*b843c749SSergey Zigachev 		core_stats->event_entries = DAL_STATS_EVENT_ENTRIES_DEFAULT;
152*b843c749SSergey Zigachev 		core_stats->events = kcalloc(core_stats->event_entries,
153*b843c749SSergey Zigachev 					     sizeof(struct stats_event_cache),
154*b843c749SSergey Zigachev 					     GFP_KERNEL);
155*b843c749SSergey Zigachev 
156*b843c749SSergey Zigachev 		if (core_stats->events == NULL)
157*b843c749SSergey Zigachev 			goto fail_construct_events;
158*b843c749SSergey Zigachev 
159*b843c749SSergey Zigachev 	} else {
160*b843c749SSergey Zigachev 		core_stats->entries = 0;
161*b843c749SSergey Zigachev 	}
162*b843c749SSergey Zigachev 
163*b843c749SSergey Zigachev 	/* Purposely leave index 0 unused so we don't need special logic to
164*b843c749SSergey Zigachev 	 * handle calculation cases that depend on previous flip data.
165*b843c749SSergey Zigachev 	 */
166*b843c749SSergey Zigachev 	core_stats->index = 1;
167*b843c749SSergey Zigachev 	core_stats->event_index = 0;
168*b843c749SSergey Zigachev 
169*b843c749SSergey Zigachev 	// Keeps track of ordering within the different stats structures
170*b843c749SSergey Zigachev 	core_stats->entry_id = 0;
171*b843c749SSergey Zigachev 
172*b843c749SSergey Zigachev 	return &core_stats->public;
173*b843c749SSergey Zigachev 
174*b843c749SSergey Zigachev fail_construct_events:
175*b843c749SSergey Zigachev 	kfree(core_stats->time);
176*b843c749SSergey Zigachev 
177*b843c749SSergey Zigachev fail_construct_time:
178*b843c749SSergey Zigachev 	kfree(core_stats);
179*b843c749SSergey Zigachev 
180*b843c749SSergey Zigachev fail_construct:
181*b843c749SSergey Zigachev 	return NULL;
182*b843c749SSergey Zigachev }
183*b843c749SSergey Zigachev 
mod_stats_destroy(struct mod_stats * mod_stats)184*b843c749SSergey Zigachev void mod_stats_destroy(struct mod_stats *mod_stats)
185*b843c749SSergey Zigachev {
186*b843c749SSergey Zigachev 	if (mod_stats != NULL) {
187*b843c749SSergey Zigachev 		struct core_stats *core_stats = MOD_STATS_TO_CORE(mod_stats);
188*b843c749SSergey Zigachev 
189*b843c749SSergey Zigachev 		if (core_stats->time != NULL)
190*b843c749SSergey Zigachev 			kfree(core_stats->time);
191*b843c749SSergey Zigachev 
192*b843c749SSergey Zigachev 		if (core_stats->events != NULL)
193*b843c749SSergey Zigachev 			kfree(core_stats->events);
194*b843c749SSergey Zigachev 
195*b843c749SSergey Zigachev 		kfree(core_stats);
196*b843c749SSergey Zigachev 	}
197*b843c749SSergey Zigachev }
198*b843c749SSergey Zigachev 
mod_stats_dump(struct mod_stats * mod_stats)199*b843c749SSergey Zigachev void mod_stats_dump(struct mod_stats *mod_stats)
200*b843c749SSergey Zigachev {
201*b843c749SSergey Zigachev 	struct dc  *dc = NULL;
202*b843c749SSergey Zigachev 	struct dal_logger *logger = NULL;
203*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
204*b843c749SSergey Zigachev 	struct stats_time_cache *time = NULL;
205*b843c749SSergey Zigachev 	struct stats_event_cache *events = NULL;
206*b843c749SSergey Zigachev 	unsigned int time_index = 1;
207*b843c749SSergey Zigachev 	unsigned int event_index = 0;
208*b843c749SSergey Zigachev 	unsigned int index = 0;
209*b843c749SSergey Zigachev 	struct log_entry log_entry;
210*b843c749SSergey Zigachev 
211*b843c749SSergey Zigachev 	if (mod_stats == NULL)
212*b843c749SSergey Zigachev 		return;
213*b843c749SSergey Zigachev 
214*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
215*b843c749SSergey Zigachev 	dc = core_stats->dc;
216*b843c749SSergey Zigachev 	logger = dc->ctx->logger;
217*b843c749SSergey Zigachev 	time = core_stats->time;
218*b843c749SSergey Zigachev 	events = core_stats->events;
219*b843c749SSergey Zigachev 
220*b843c749SSergey Zigachev 	DISPLAY_STATS_BEGIN(log_entry);
221*b843c749SSergey Zigachev 
222*b843c749SSergey Zigachev 	DISPLAY_STATS("==Display Caps==\n");
223*b843c749SSergey Zigachev 
224*b843c749SSergey Zigachev 	DISPLAY_STATS("==Display Stats==\n");
225*b843c749SSergey Zigachev 
226*b843c749SSergey Zigachev 	DISPLAY_STATS("%10s %10s %10s %10s %10s"
227*b843c749SSergey Zigachev 			" %11s %11s %17s %10s %14s"
228*b843c749SSergey Zigachev 			" %10s %10s %10s %10s %10s"
229*b843c749SSergey Zigachev 			" %10s %10s %10s %10s\n",
230*b843c749SSergey Zigachev 		"render", "avgRender",
231*b843c749SSergey Zigachev 		"minWindow", "midPoint", "maxWindow",
232*b843c749SSergey Zigachev 		"vsyncToFlip", "flipToVsync", "vsyncsBetweenFlip",
233*b843c749SSergey Zigachev 		"numFrame", "insertDuration",
234*b843c749SSergey Zigachev 		"vTotalMin", "vTotalMax", "eventTrigs",
235*b843c749SSergey Zigachev 		"vSyncTime1", "vSyncTime2", "vSyncTime3",
236*b843c749SSergey Zigachev 		"vSyncTime4", "vSyncTime5", "flags");
237*b843c749SSergey Zigachev 
238*b843c749SSergey Zigachev 	for (int i = 0; i < core_stats->entry_id; i++) {
239*b843c749SSergey Zigachev 		if (event_index < core_stats->event_index &&
240*b843c749SSergey Zigachev 				i == events[event_index].entry_id) {
241*b843c749SSergey Zigachev 			DISPLAY_STATS("==Event==%s\n", events[event_index].event_string);
242*b843c749SSergey Zigachev 			event_index++;
243*b843c749SSergey Zigachev 		} else if (time_index < core_stats->index &&
244*b843c749SSergey Zigachev 				i == time[time_index].entry_id) {
245*b843c749SSergey Zigachev 			DISPLAY_STATS("%10u %10u %10u %10u %10u"
246*b843c749SSergey Zigachev 					" %11u %11u %17u %10u %14u"
247*b843c749SSergey Zigachev 					" %10u %10u %10u %10u %10u"
248*b843c749SSergey Zigachev 					" %10u %10u %10u %10u\n",
249*b843c749SSergey Zigachev 				time[time_index].render_time_in_us,
250*b843c749SSergey Zigachev 				time[time_index].avg_render_time_in_us_last_ten,
251*b843c749SSergey Zigachev 				time[time_index].min_window,
252*b843c749SSergey Zigachev 				time[time_index].lfc_mid_point_in_us,
253*b843c749SSergey Zigachev 				time[time_index].max_window,
254*b843c749SSergey Zigachev 				time[time_index].vsync_to_flip_time_in_us,
255*b843c749SSergey Zigachev 				time[time_index].flip_to_vsync_time_in_us,
256*b843c749SSergey Zigachev 				time[time_index].num_vsync_between_flips,
257*b843c749SSergey Zigachev 				time[time_index].num_frames_inserted,
258*b843c749SSergey Zigachev 				time[time_index].inserted_duration_in_us,
259*b843c749SSergey Zigachev 				time[time_index].v_total_min,
260*b843c749SSergey Zigachev 				time[time_index].v_total_max,
261*b843c749SSergey Zigachev 				time[time_index].event_triggers,
262*b843c749SSergey Zigachev 				time[time_index].v_sync_time_in_us[0],
263*b843c749SSergey Zigachev 				time[time_index].v_sync_time_in_us[1],
264*b843c749SSergey Zigachev 				time[time_index].v_sync_time_in_us[2],
265*b843c749SSergey Zigachev 				time[time_index].v_sync_time_in_us[3],
266*b843c749SSergey Zigachev 				time[time_index].v_sync_time_in_us[4],
267*b843c749SSergey Zigachev 				time[time_index].flags);
268*b843c749SSergey Zigachev 
269*b843c749SSergey Zigachev 			time_index++;
270*b843c749SSergey Zigachev 		}
271*b843c749SSergey Zigachev 	}
272*b843c749SSergey Zigachev 
273*b843c749SSergey Zigachev 	DISPLAY_STATS_END(log_entry);
274*b843c749SSergey Zigachev }
275*b843c749SSergey Zigachev 
mod_stats_reset_data(struct mod_stats * mod_stats)276*b843c749SSergey Zigachev void mod_stats_reset_data(struct mod_stats *mod_stats)
277*b843c749SSergey Zigachev {
278*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
279*b843c749SSergey Zigachev 	struct stats_time_cache *time = NULL;
280*b843c749SSergey Zigachev 	unsigned int index = 0;
281*b843c749SSergey Zigachev 
282*b843c749SSergey Zigachev 	if (mod_stats == NULL)
283*b843c749SSergey Zigachev 		return;
284*b843c749SSergey Zigachev 
285*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
286*b843c749SSergey Zigachev 
287*b843c749SSergey Zigachev 	memset(core_stats->time, 0,
288*b843c749SSergey Zigachev 		sizeof(struct stats_time_cache) * core_stats->entries);
289*b843c749SSergey Zigachev 
290*b843c749SSergey Zigachev 	memset(core_stats->events, 0,
291*b843c749SSergey Zigachev 		sizeof(struct stats_event_cache) * core_stats->event_entries);
292*b843c749SSergey Zigachev 
293*b843c749SSergey Zigachev 	core_stats->index = 1;
294*b843c749SSergey Zigachev 	core_stats->event_index = 0;
295*b843c749SSergey Zigachev 
296*b843c749SSergey Zigachev 	// Keeps track of ordering within the different stats structures
297*b843c749SSergey Zigachev 	core_stats->entry_id = 0;
298*b843c749SSergey Zigachev }
299*b843c749SSergey Zigachev 
mod_stats_update_event(struct mod_stats * mod_stats,char * event_string,unsigned int length)300*b843c749SSergey Zigachev void mod_stats_update_event(struct mod_stats *mod_stats,
301*b843c749SSergey Zigachev 		char *event_string,
302*b843c749SSergey Zigachev 		unsigned int length)
303*b843c749SSergey Zigachev {
304*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
305*b843c749SSergey Zigachev 	struct stats_event_cache *events = NULL;
306*b843c749SSergey Zigachev 	unsigned int index = 0;
307*b843c749SSergey Zigachev 	unsigned int copy_length = 0;
308*b843c749SSergey Zigachev 
309*b843c749SSergey Zigachev 	if (mod_stats == NULL)
310*b843c749SSergey Zigachev 		return;
311*b843c749SSergey Zigachev 
312*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
313*b843c749SSergey Zigachev 
314*b843c749SSergey Zigachev 	if (core_stats->event_index >= core_stats->event_entries)
315*b843c749SSergey Zigachev 		return;
316*b843c749SSergey Zigachev 
317*b843c749SSergey Zigachev 	events = core_stats->events;
318*b843c749SSergey Zigachev 	index = core_stats->event_index;
319*b843c749SSergey Zigachev 
320*b843c749SSergey Zigachev 	copy_length = length;
321*b843c749SSergey Zigachev 	if (length > MOD_STATS_EVENT_STRING_MAX)
322*b843c749SSergey Zigachev 		copy_length = MOD_STATS_EVENT_STRING_MAX;
323*b843c749SSergey Zigachev 
324*b843c749SSergey Zigachev 	memcpy(&events[index].event_string, event_string, copy_length);
325*b843c749SSergey Zigachev 	events[index].event_string[copy_length - 1] = '\0';
326*b843c749SSergey Zigachev 
327*b843c749SSergey Zigachev 	events[index].entry_id = core_stats->entry_id;
328*b843c749SSergey Zigachev 	core_stats->event_index++;
329*b843c749SSergey Zigachev 	core_stats->entry_id++;
330*b843c749SSergey Zigachev }
331*b843c749SSergey Zigachev 
mod_stats_update_flip(struct mod_stats * mod_stats,unsigned long timestamp_in_ns)332*b843c749SSergey Zigachev void mod_stats_update_flip(struct mod_stats *mod_stats,
333*b843c749SSergey Zigachev 		unsigned long timestamp_in_ns)
334*b843c749SSergey Zigachev {
335*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
336*b843c749SSergey Zigachev 	struct stats_time_cache *time = NULL;
337*b843c749SSergey Zigachev 	unsigned int index = 0;
338*b843c749SSergey Zigachev 
339*b843c749SSergey Zigachev 	if (mod_stats == NULL)
340*b843c749SSergey Zigachev 		return;
341*b843c749SSergey Zigachev 
342*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
343*b843c749SSergey Zigachev 
344*b843c749SSergey Zigachev 	if (core_stats->index >= core_stats->entries)
345*b843c749SSergey Zigachev 		return;
346*b843c749SSergey Zigachev 
347*b843c749SSergey Zigachev 	time = core_stats->time;
348*b843c749SSergey Zigachev 	index = core_stats->index;
349*b843c749SSergey Zigachev 
350*b843c749SSergey Zigachev 	time[index].flip_timestamp_in_ns = timestamp_in_ns;
351*b843c749SSergey Zigachev 	time[index].render_time_in_us =
352*b843c749SSergey Zigachev 		(timestamp_in_ns - time[index - 1].flip_timestamp_in_ns) / 1000;
353*b843c749SSergey Zigachev 
354*b843c749SSergey Zigachev 	if (index >= 10) {
355*b843c749SSergey Zigachev 		for (unsigned int i = 0; i < 10; i++)
356*b843c749SSergey Zigachev 			time[index].avg_render_time_in_us_last_ten +=
357*b843c749SSergey Zigachev 					time[index - i].render_time_in_us;
358*b843c749SSergey Zigachev 		time[index].avg_render_time_in_us_last_ten /= 10;
359*b843c749SSergey Zigachev 	}
360*b843c749SSergey Zigachev 
361*b843c749SSergey Zigachev 	if (time[index].num_vsync_between_flips > 0)
362*b843c749SSergey Zigachev 		time[index].vsync_to_flip_time_in_us =
363*b843c749SSergey Zigachev 			(timestamp_in_ns -
364*b843c749SSergey Zigachev 				time[index].vupdate_timestamp_in_ns) / 1000;
365*b843c749SSergey Zigachev 	else
366*b843c749SSergey Zigachev 		time[index].vsync_to_flip_time_in_us =
367*b843c749SSergey Zigachev 			(timestamp_in_ns -
368*b843c749SSergey Zigachev 				time[index - 1].vupdate_timestamp_in_ns) / 1000;
369*b843c749SSergey Zigachev 
370*b843c749SSergey Zigachev 	time[index].entry_id = core_stats->entry_id;
371*b843c749SSergey Zigachev 	core_stats->index++;
372*b843c749SSergey Zigachev 	core_stats->entry_id++;
373*b843c749SSergey Zigachev }
374*b843c749SSergey Zigachev 
mod_stats_update_vupdate(struct mod_stats * mod_stats,unsigned long timestamp_in_ns)375*b843c749SSergey Zigachev void mod_stats_update_vupdate(struct mod_stats *mod_stats,
376*b843c749SSergey Zigachev 		unsigned long timestamp_in_ns)
377*b843c749SSergey Zigachev {
378*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
379*b843c749SSergey Zigachev 	struct stats_time_cache *time = NULL;
380*b843c749SSergey Zigachev 	unsigned int index = 0;
381*b843c749SSergey Zigachev 	unsigned int num_vsyncs = 0;
382*b843c749SSergey Zigachev 	unsigned int prev_vsync_in_ns = 0;
383*b843c749SSergey Zigachev 
384*b843c749SSergey Zigachev 	if (mod_stats == NULL)
385*b843c749SSergey Zigachev 		return;
386*b843c749SSergey Zigachev 
387*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
388*b843c749SSergey Zigachev 
389*b843c749SSergey Zigachev 	if (core_stats->index >= core_stats->entries)
390*b843c749SSergey Zigachev 		return;
391*b843c749SSergey Zigachev 
392*b843c749SSergey Zigachev 	time = core_stats->time;
393*b843c749SSergey Zigachev 	index = core_stats->index;
394*b843c749SSergey Zigachev 	num_vsyncs = time[index].num_vsync_between_flips;
395*b843c749SSergey Zigachev 
396*b843c749SSergey Zigachev 	if (num_vsyncs < MOD_STATS_NUM_VSYNCS) {
397*b843c749SSergey Zigachev 		if (num_vsyncs == 0) {
398*b843c749SSergey Zigachev 			prev_vsync_in_ns =
399*b843c749SSergey Zigachev 				time[index - 1].vupdate_timestamp_in_ns;
400*b843c749SSergey Zigachev 
401*b843c749SSergey Zigachev 			time[index].flip_to_vsync_time_in_us =
402*b843c749SSergey Zigachev 				(timestamp_in_ns -
403*b843c749SSergey Zigachev 					time[index - 1].flip_timestamp_in_ns) /
404*b843c749SSergey Zigachev 					1000;
405*b843c749SSergey Zigachev 		} else {
406*b843c749SSergey Zigachev 			prev_vsync_in_ns =
407*b843c749SSergey Zigachev 				time[index].vupdate_timestamp_in_ns;
408*b843c749SSergey Zigachev 		}
409*b843c749SSergey Zigachev 
410*b843c749SSergey Zigachev 		time[index].v_sync_time_in_us[num_vsyncs] =
411*b843c749SSergey Zigachev 			(timestamp_in_ns - prev_vsync_in_ns) / 1000;
412*b843c749SSergey Zigachev 	}
413*b843c749SSergey Zigachev 
414*b843c749SSergey Zigachev 	time[index].vupdate_timestamp_in_ns = timestamp_in_ns;
415*b843c749SSergey Zigachev 	time[index].num_vsync_between_flips++;
416*b843c749SSergey Zigachev }
417*b843c749SSergey Zigachev 
mod_stats_update_freesync(struct mod_stats * mod_stats,unsigned int v_total_min,unsigned int v_total_max,unsigned int event_triggers,unsigned int window_min,unsigned int window_max,unsigned int lfc_mid_point_in_us,unsigned int inserted_frames,unsigned int inserted_duration_in_us)418*b843c749SSergey Zigachev void mod_stats_update_freesync(struct mod_stats *mod_stats,
419*b843c749SSergey Zigachev 		unsigned int v_total_min,
420*b843c749SSergey Zigachev 		unsigned int v_total_max,
421*b843c749SSergey Zigachev 		unsigned int event_triggers,
422*b843c749SSergey Zigachev 		unsigned int window_min,
423*b843c749SSergey Zigachev 		unsigned int window_max,
424*b843c749SSergey Zigachev 		unsigned int lfc_mid_point_in_us,
425*b843c749SSergey Zigachev 		unsigned int inserted_frames,
426*b843c749SSergey Zigachev 		unsigned int inserted_duration_in_us)
427*b843c749SSergey Zigachev {
428*b843c749SSergey Zigachev 	struct core_stats *core_stats = NULL;
429*b843c749SSergey Zigachev 	struct stats_time_cache *time = NULL;
430*b843c749SSergey Zigachev 	unsigned int index = 0;
431*b843c749SSergey Zigachev 
432*b843c749SSergey Zigachev 	if (mod_stats == NULL)
433*b843c749SSergey Zigachev 		return;
434*b843c749SSergey Zigachev 
435*b843c749SSergey Zigachev 	core_stats = MOD_STATS_TO_CORE(mod_stats);
436*b843c749SSergey Zigachev 
437*b843c749SSergey Zigachev 	if (core_stats->index >= core_stats->entries)
438*b843c749SSergey Zigachev 		return;
439*b843c749SSergey Zigachev 
440*b843c749SSergey Zigachev 	time = core_stats->time;
441*b843c749SSergey Zigachev 	index = core_stats->index;
442*b843c749SSergey Zigachev 
443*b843c749SSergey Zigachev 	time[index].v_total_min = v_total_min;
444*b843c749SSergey Zigachev 	time[index].v_total_max = v_total_max;
445*b843c749SSergey Zigachev 	time[index].event_triggers = event_triggers;
446*b843c749SSergey Zigachev 	time[index].min_window = window_min;
447*b843c749SSergey Zigachev 	time[index].max_window = window_max;
448*b843c749SSergey Zigachev 	time[index].lfc_mid_point_in_us = lfc_mid_point_in_us;
449*b843c749SSergey Zigachev 	time[index].num_frames_inserted = inserted_frames;
450*b843c749SSergey Zigachev 	time[index].inserted_duration_in_us = inserted_duration_in_us;
451*b843c749SSergey Zigachev }
452*b843c749SSergey Zigachev 
453