• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * drivers/amlogic/amports/vdec_profile.c
3  *
4  * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16 */
17 
18 #include <linux/kernel.h>
19 #include <linux/mutex.h>
20 #include <linux/types.h>
21 #include <linux/debugfs.h>
22 #include <linux/moduleparam.h>
23 #include <linux/sched/clock.h>
24 
25 #include <linux/amlogic/media/utils/vdec_reg.h>
26 #include <linux/amlogic/meson_atrace.h>
27 #include "vdec_profile.h"
28 #include "vdec.h"
29 
30 
31 #define ISA_TIMERE 0x2662
32 #define ISA_TIMERE_HI 0x2663
33 
34 #define PROFILE_REC_SIZE 40
35 
36 static DEFINE_MUTEX(vdec_profile_mutex);
37 static int rec_wp;
38 static bool rec_wrapped;
39 static uint dec_time_stat_flag;
40 static uint dec_time_stat_reset;
41 
42 
43 struct dentry *root, *event;
44 
45 #define MAX_INSTANCE_MUN  9
46 
47 struct vdec_profile_time_stat_s {
48 	int time_6ms_less_cnt;
49 	int time_6_9ms_cnt;
50 	int time_9_12ms_cnt;
51 	int time_12_15ms_cnt;
52 	int time_15_18ms_cnt;
53 	int time_18_21ms_cnt;
54 	int time_21ms_up_cnt;
55 	u64 time_max_us;
56 	u64 time_total_us;
57 };
58 
59 struct vdec_profile_statistics_s {
60 	bool status;
61 	u64 run_lasttimestamp;
62 	int run_cnt;
63 	u64 cb_lasttimestamp;
64 	int cb_cnt;
65 	u64 decode_first_us;
66 	struct vdec_profile_time_stat_s run2cb_time_stat;
67 	struct vdec_profile_time_stat_s decode_time_stat;
68 };
69 
70 static struct vdec_profile_statistics_s statistics_s[MAX_INSTANCE_MUN];
71 
72 
73 struct vdec_profile_rec_s {
74 	struct vdec_s *vdec;
75 	u64 timestamp;
76 	int event;
77 	int para1;
78 	int para2;
79 };
80 
81 static struct vdec_profile_rec_s recs[PROFILE_REC_SIZE];
82 static const char *event_name[VDEC_PROFILE_MAX_EVENT] = {
83 	"run",
84 	"cb",
85 	"save_input",
86 	"check run ready",
87 	"run ready",
88 	"disconnect",
89 	"dec_work",
90 	"info"
91 };
92 
93 #if 0 /* get time from hardware. */
94 static u64 get_us_time_hw(void)
95 {
96 	u32 lo, hi1, hi2;
97 	int offset = 0;
98 
99 	/* txlx, g12a isa register base is 0x3c00 */
100 	if (get_cpu_major_id() >= MESON_CPU_MAJOR_ID_TXLX)
101 		offset = 0x1600;
102 
103 	do {
104 		hi1 = READ_MPEG_REG(ISA_TIMERE_HI + offset);
105 		lo = READ_MPEG_REG(ISA_TIMERE + offset);
106 		hi2 = READ_MPEG_REG(ISA_TIMERE_HI + offset);
107 	} while (hi1 != hi2);
108 
109 	return (((u64)hi1) << 32) | lo;
110 }
111 #endif
112 
get_us_time_system(void)113 static u64 get_us_time_system(void)
114 {
115 	return div64_u64(local_clock(), 1000);
116 }
117 
vdec_profile_update_alloc_time(struct vdec_profile_time_stat_s * time_stat,u64 startus,u64 endus)118 static void vdec_profile_update_alloc_time(
119 	struct vdec_profile_time_stat_s *time_stat, u64 startus, u64 endus)
120 {
121 	u64 spend_time_us = endus - startus;
122 
123 	if (spend_time_us > 0 && spend_time_us < 100000000) {
124 		if (spend_time_us < 6000)
125 			time_stat->time_6ms_less_cnt++;
126 		else if (spend_time_us < 9000)
127 			time_stat->time_6_9ms_cnt++;
128 		else if (spend_time_us < 12000)
129 			time_stat->time_9_12ms_cnt++;
130 		else if (spend_time_us < 15000)
131 			time_stat->time_12_15ms_cnt++;
132 		else if (spend_time_us < 18000)
133 			time_stat->time_15_18ms_cnt++;
134 		else if (spend_time_us < 21000)
135 			time_stat->time_18_21ms_cnt++;
136 		else
137 			time_stat->time_21ms_up_cnt++;
138 	}
139 
140 	if (spend_time_us > time_stat->time_max_us)
141 		time_stat->time_max_us = spend_time_us;
142 
143 	time_stat->time_total_us += spend_time_us;
144 }
145 
146 
vdec_profile_statistics(struct vdec_s * vdec,int event)147 static void vdec_profile_statistics(struct vdec_s *vdec, int event)
148 {
149 	struct vdec_profile_statistics_s *time_stat = NULL;
150 	u64 timestamp;
151 	int i;
152 
153 	if (vdec->id >= MAX_INSTANCE_MUN)
154 		return;
155 
156 	if (event != VDEC_PROFILE_EVENT_RUN &&
157 			event != VDEC_PROFILE_EVENT_CB)
158 		return;
159 
160 	mutex_lock(&vdec_profile_mutex);
161 
162 	if (dec_time_stat_reset == 1) {
163 		if (event != VDEC_PROFILE_EVENT_RUN) {
164 			mutex_unlock(&vdec_profile_mutex);
165 			return;
166 		}
167 		for (i = 0; i < MAX_INSTANCE_MUN; i++)
168 			memset(&statistics_s[i], 0,
169 				sizeof(struct vdec_profile_statistics_s));
170 		dec_time_stat_reset = 0;
171 	}
172 
173 	time_stat = &statistics_s[vdec->id];
174 	timestamp = get_us_time_system();
175 
176 	if (time_stat->status == false) {
177 		time_stat->decode_first_us = timestamp;
178 		time_stat->status = true;
179 	}
180 
181 	if (event == VDEC_PROFILE_EVENT_RUN) {
182 		time_stat->run_lasttimestamp = timestamp;
183 		time_stat->run_cnt++;
184 	} else if (event == VDEC_PROFILE_EVENT_CB) {
185 		/*run2cb statistics*/
186 		vdec_profile_update_alloc_time(&time_stat->run2cb_time_stat, time_stat->run_lasttimestamp, timestamp);
187 
188 		/*decode statistics*/
189 		if (time_stat->cb_cnt == 0)
190 			vdec_profile_update_alloc_time(&time_stat->decode_time_stat, time_stat->decode_first_us, timestamp);
191 		else
192 			vdec_profile_update_alloc_time(&time_stat->decode_time_stat, time_stat->cb_lasttimestamp, timestamp);
193 
194 		time_stat->cb_lasttimestamp = timestamp;
195 		time_stat->cb_cnt++;
196 	}
197 
198 	mutex_unlock(&vdec_profile_mutex);
199 }
200 
201 
vdec_profile_more(struct vdec_s * vdec,int event,int para1,int para2)202 void vdec_profile_more(struct vdec_s *vdec, int event, int para1, int para2)
203 {
204 	mutex_lock(&vdec_profile_mutex);
205 
206 	recs[rec_wp].vdec = vdec;
207 	recs[rec_wp].timestamp = get_us_time_system();
208 	recs[rec_wp].event = event;
209 	recs[rec_wp].para1 = para1;
210 	recs[rec_wp].para2 = para2;
211 
212 	rec_wp++;
213 	if (rec_wp == PROFILE_REC_SIZE) {
214 		rec_wrapped = true;
215 		rec_wp = 0;
216 	}
217 
218 	mutex_unlock(&vdec_profile_mutex);
219 }
220 EXPORT_SYMBOL(vdec_profile_more);
221 
vdec_profile(struct vdec_s * vdec,int event)222 void vdec_profile(struct vdec_s *vdec, int event)
223 {
224 	ATRACE_COUNTER(vdec->vfm_map_id, event);
225 	vdec_profile_more(vdec, event, 0 , 0);
226 	if (dec_time_stat_flag == 1)
227 		vdec_profile_statistics(vdec, event);
228 }
229 EXPORT_SYMBOL(vdec_profile);
230 
vdec_profile_flush(struct vdec_s * vdec)231 void vdec_profile_flush(struct vdec_s *vdec)
232 {
233 	int i;
234 
235 	if (vdec->id >= MAX_INSTANCE_MUN)
236 			return;
237 
238 	mutex_lock(&vdec_profile_mutex);
239 
240 	for (i = 0; i < PROFILE_REC_SIZE; i++) {
241 		if (recs[i].vdec == vdec)
242 			recs[i].vdec = NULL;
243 	}
244 
245 	memset(&statistics_s[vdec->id], 0, sizeof(struct vdec_profile_statistics_s));
246 
247 	mutex_unlock(&vdec_profile_mutex);
248 }
249 
event_str(int event)250 static const char *event_str(int event)
251 {
252 	if (event < VDEC_PROFILE_MAX_EVENT)
253 		return event_name[event];
254 
255 	return "INVALID";
256 }
257 
vdec_profile_dbg_show(struct seq_file * m,void * v)258 static int vdec_profile_dbg_show(struct seq_file *m, void *v)
259 {
260 	int i, end;
261 	u64 base_timestamp;
262 
263 	mutex_lock(&vdec_profile_mutex);
264 
265 	if (rec_wrapped) {
266 		i = rec_wp;
267 		end = rec_wp;
268 	} else {
269 		i = 0;
270 		end = rec_wp;
271 	}
272 
273 	base_timestamp = recs[i].timestamp;
274 	while (1) {
275 		if ((!rec_wrapped) && (i == end))
276 			break;
277 
278 		if (recs[i].vdec) {
279 			seq_printf(m, "[%s:%d] \t%016llu us : %s (%d,%d)\n",
280 				vdec_device_name_str(recs[i].vdec),
281 				recs[i].vdec->id,
282 				recs[i].timestamp - base_timestamp,
283 				event_str(recs[i].event),
284 				recs[i].para1,
285 				recs[i].para2
286 				);
287 		} else {
288 			seq_printf(m, "[%s:%d] \t%016llu us : %s (%d,%d)\n",
289 				"N/A",
290 				0,
291 				recs[i].timestamp - base_timestamp,
292 				event_str(recs[i].event),
293 				recs[i].para1,
294 				recs[i].para2
295 				);
296 		}
297 		if (++i == PROFILE_REC_SIZE)
298 			i = 0;
299 
300 		if (rec_wrapped && (i == end))
301 			break;
302 	}
303 
304 	mutex_unlock(&vdec_profile_mutex);
305 
306 	return 0;
307 }
308 
time_stat_profile_dbg_show(struct seq_file * m,void * v)309 static int time_stat_profile_dbg_show(struct seq_file *m, void *v)
310 {
311 	int i;
312 
313 	mutex_lock(&vdec_profile_mutex);
314 
315 	for (i = 0; i < MAX_INSTANCE_MUN; i++)
316 	{
317 		if (statistics_s[i].status == false)
318 			continue;
319 
320 		seq_printf(m, "[%d]run_cnt:%d, cb_cnt:%d\n\
321 			\t\t\ttime_total_us:%llu\n\
322 			\t\t\trun2cb time:\n\
323 			\t\t\ttime_max_us:%llu\n\
324 			\t\t\t[%d]run2cb ave_us:%llu\n\
325 			\t\t\ttime_6ms_less_cnt:%d\n\
326 			\t\t\ttime_6_9ms_cnt:%d\n\
327 			\t\t\ttime_9_12ms_cnt:%d\n\
328 			\t\t\ttime_12_15ms_cnt:%d\n\
329 			\t\t\ttime_15_18ms_cnt:%d\n\
330 			\t\t\ttime_18_21ms_cnt:%d\n\
331 			\t\t\ttime_21ms_up_cnt:%d\n\
332 			\t\t\tdecode time:\n\
333 			\t\t\ttime_total_us:%llu\n\
334 			\t\t\ttime_max_us:%llu\n\
335 			\t\t\t[%d]cb2cb ave_us:%llu\n\
336 			\t\t\ttime_6ms_less_cnt:%d\n\
337 			\t\t\ttime_6_9ms_cnt:%d\n\
338 			\t\t\ttime_9_12ms_cnt:%d\n\
339 			\t\t\ttime_12_15ms_cnt:%d\n\
340 			\t\t\ttime_15_18ms_cnt:%d\n\
341 			\t\t\ttime_18_21ms_cnt:%d\n\
342 			\t\t\ttime_21ms_up_cnt:%d\n",
343 			i,
344 			statistics_s[i].run_cnt,
345 			statistics_s[i].cb_cnt,
346 			statistics_s[i].run2cb_time_stat.time_total_us,
347 			statistics_s[i].run2cb_time_stat.time_max_us,
348 			i,
349 			div_u64(statistics_s[i].run2cb_time_stat.time_total_us , statistics_s[i].cb_cnt),
350 			statistics_s[i].run2cb_time_stat.time_6ms_less_cnt,
351 			statistics_s[i].run2cb_time_stat.time_6_9ms_cnt,
352 			statistics_s[i].run2cb_time_stat.time_9_12ms_cnt,
353 			statistics_s[i].run2cb_time_stat.time_12_15ms_cnt,
354 			statistics_s[i].run2cb_time_stat.time_15_18ms_cnt,
355 			statistics_s[i].run2cb_time_stat.time_18_21ms_cnt,
356 			statistics_s[i].run2cb_time_stat.time_21ms_up_cnt,
357 			statistics_s[i].decode_time_stat.time_total_us,
358 			statistics_s[i].decode_time_stat.time_max_us,
359 			i,
360 			div_u64(statistics_s[i].decode_time_stat.time_total_us , statistics_s[i].cb_cnt),
361 			statistics_s[i].decode_time_stat.time_6ms_less_cnt,
362 			statistics_s[i].decode_time_stat.time_6_9ms_cnt,
363 			statistics_s[i].decode_time_stat.time_9_12ms_cnt,
364 			statistics_s[i].decode_time_stat.time_12_15ms_cnt,
365 			statistics_s[i].decode_time_stat.time_15_18ms_cnt,
366 			statistics_s[i].decode_time_stat.time_18_21ms_cnt,
367 			statistics_s[i].decode_time_stat.time_21ms_up_cnt);
368 	}
369 
370 	mutex_unlock(&vdec_profile_mutex);
371 
372 	return 0;
373 }
374 
375 
vdec_profile_dbg_open(struct inode * inode,struct file * file)376 static int vdec_profile_dbg_open(struct inode *inode, struct file *file)
377 {
378 	return single_open(file, vdec_profile_dbg_show, NULL);
379 }
380 
time_stat_profile_dbg_open(struct inode * inode,struct file * file)381 static int time_stat_profile_dbg_open(struct inode *inode, struct file *file)
382 {
383 	return single_open(file, time_stat_profile_dbg_show, NULL);
384 }
385 
386 
387 static const struct file_operations event_dbg_fops = {
388 	.open    = vdec_profile_dbg_open,
389 	.read    = seq_read,
390 	.llseek  = seq_lseek,
391 	.release = single_release,
392 };
393 
394 static const struct file_operations time_stat_dbg_fops = {
395 	.open    = time_stat_profile_dbg_open,
396 	.read    = seq_read,
397 	.llseek  = seq_lseek,
398 	.release = single_release,
399 };
400 
401 
402 #if 0 /*DEBUG_TMP*/
403 static int __init vdec_profile_init_debugfs(void)
404 {
405 	struct dentry *root, *event;
406 
407 	root = debugfs_create_dir("vdec_profile", NULL);
408 	if (IS_ERR(root) || !root)
409 		goto err;
410 
411 	event = debugfs_create_file("event", 0400, root, NULL,
412 			&event_dbg_fops);
413 	if (!event)
414 		goto err_1;
415 
416 	mutex_init(&vdec_profile_mutex);
417 
418 	return 0;
419 
420 err_1:
421 	debugfs_remove(root);
422 err:
423 	pr_err("Can not create debugfs for vdec_profile\n");
424 	return 0;
425 }
426 
427 #endif
428 
vdec_profile_init_debugfs(void)429 int vdec_profile_init_debugfs(void)
430 {
431 	struct dentry *root, *event, *time_stat;
432 
433 	root = debugfs_create_dir("vdec_profile", NULL);
434 	if (IS_ERR(root) || !root)
435 		goto err;
436 
437 	event = debugfs_create_file("event", 0400, root, NULL,
438 			&event_dbg_fops);
439 	if (!event)
440 		goto err_1;
441 
442 	time_stat = debugfs_create_file("time_stat", 0400, root, NULL,
443 			&time_stat_dbg_fops);
444 	if (!time_stat)
445 		goto err_2;
446 
447 	mutex_init(&vdec_profile_mutex);
448 
449 	return 0;
450 
451 err_2:
452 	debugfs_remove(event);
453 err_1:
454 	debugfs_remove(root);
455 err:
456 	pr_err("Can not create debugfs for vdec_profile\n");
457 	return 0;
458 }
459 EXPORT_SYMBOL(vdec_profile_init_debugfs);
460 
vdec_profile_exit_debugfs(void)461 void vdec_profile_exit_debugfs(void)
462 {
463 	debugfs_remove(event);
464 	debugfs_remove(root);
465 }
466 EXPORT_SYMBOL(vdec_profile_exit_debugfs);
467 
468 module_param(dec_time_stat_flag, uint, 0664);
469 
470 module_param(dec_time_stat_reset, uint, 0664);
471 
472 
473 /*module_init(vdec_profile_init_debugfs);*/
474 
475