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