vblank: add server ttrace information
[platform/core/uifw/libtdm.git] / src / tdm_monitor_server.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #include "tdm_private.h"
37
38 #define TDM_DBG_SERVER_ARGS_MAX         32
39
40 /* LCOV_EXCL_START */
41 static void _tdm_monitor_server_usage(char *app_name, char *reply, int *len);
42
43 static void
44 _tdm_monitor_server_query(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
45 {
46         tdm_display_lock(dpy);
47         tdm_helper_get_display_information(dpy, reply, len);
48         tdm_display_unlock(dpy);
49 }
50
51 static void
52 _tdm_monitor_server_protocol_trace(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
53 {
54         int enable;
55
56         if (argc < 3) {
57                 _tdm_monitor_server_usage(argv[0], reply, len);
58                 return;
59         }
60
61         enable = atoi(argv[2]);
62
63         tdm_event_loop_trace_enable(dpy, enable);
64
65         TDM_SNPRINTF(reply, len, "protocol trace: '%s'\n", (enable) ? "enabled" : "disabled");
66 }
67
68 static void
69 _tdm_monitor_server_dpms(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
70 {
71         tdm_output *output;
72         int output_idx, dpms_value;
73         char *arg;
74         char *end;
75         tdm_error ret;
76
77         if (argc < 3) {
78                 _tdm_monitor_server_usage(argv[0], reply, len);
79                 return;
80         }
81
82         arg = argv[2];
83         output_idx = strtol(arg, &end, 10);
84         if (*end != ':') {
85                 TDM_SNPRINTF(reply, len, "failed: no onoff value\n");
86                 return;
87         }
88
89         arg = end + 1;
90         dpms_value = strtol(arg, &end, 10);
91
92         output = tdm_display_get_output(dpy, output_idx, &ret);
93         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
94
95         ret = tdm_output_set_dpms(output, dpms_value);
96         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
97
98         TDM_SNPRINTF(reply, len, "done: DPMS %s\n", tdm_dpms_str(dpms_value));
99 }
100
101 static void
102 _tdm_monitor_server_ttrace(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
103 {
104         int output_id = 0;
105         char *end;
106         tdm_error ret;
107
108         if (argc < 3) {
109                 _tdm_monitor_server_usage(argv[0], reply, len);
110                 return;
111         }
112
113         if (argv[3])
114                 output_id = strtol(argv[3], &end, 10);
115
116         ret = tdm_display_enable_ttrace(dpy, argv[2], output_id, reply, len);
117         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
118 }
119
120 static void
121 _tdm_monitor_server_debug(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
122 {
123         int level;
124         char *arg;
125         char *end;
126
127         if (argc < 3) {
128                 _tdm_monitor_server_usage(argv[0], reply, len);
129                 return;
130         }
131
132         arg = argv[2];
133         level = strtol(arg, &end, 10);
134
135         tdm_log_set_debug_level(level);
136         TDM_SNPRINTF(reply, len, "debug level: %d\n", level);
137
138         if (*end == '@') {
139                 char *arg = end + 1;
140
141                 tdm_display_enable_debug_module((const char *)arg);
142
143                 TDM_SNPRINTF(reply, len, "debugging... '%s'\n", arg);
144         }
145 }
146
147 static void
148 _tdm_monitor_server_log_path(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
149 {
150         static int old_stdout = -1;
151         char fd_name[TDM_PATH_LEN];
152         char *path;
153
154         if (argc < 3) {
155                 _tdm_monitor_server_usage(argv[0], reply, len);
156                 return;
157         }
158
159         if (old_stdout == -1)
160                 old_stdout = dup(STDOUT_FILENO);
161
162         path = argv[2];
163         TDM_DBG_RETURN_IF_FAIL(path != NULL);
164
165         tdm_log_enable_dlog(0);
166
167         if (!strncmp(path, "dlog", 4)) {
168                 tdm_log_enable_dlog(1);
169                 goto done;
170         } else if (!strncmp(path, "console", 7))
171                 snprintf(fd_name, TDM_PATH_LEN, "/proc/%d/fd/1", pid);
172         else {
173                 if (path[0] == '/')
174                         snprintf(fd_name, TDM_PATH_LEN, "%s", path);
175                 else {
176                         if (cwd)
177                                 snprintf(fd_name, TDM_PATH_LEN, "%s/%s", cwd, path);
178                         else
179                                 snprintf(fd_name, TDM_PATH_LEN, "%s", path);
180                 }
181                 tdm_log_enable_color(0);
182         }
183
184         if (tdm_display_enable_path((const char*)fd_name) != TDM_ERROR_NONE) {
185                 TDM_SNPRINTF(reply, len, "failed: '%s'\n", path);
186                 return;
187         }
188
189 done:
190         TDM_SNPRINTF(reply, len, "log path: '%s'\n", path);
191 }
192
193 static void
194 _tdm_monitor_server_choose_commit_per_vblank_mode(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
195 {
196         int output_idx;
197         int mode;
198         char *arg;
199         char *end;
200         tdm_error err;
201
202         /* TODO: do we have to provide an ability to choose commit_per_vblank mode outside? */
203
204         if (argc < 4) {
205                 _tdm_monitor_server_usage(argv[0], reply, len);
206                 return;
207         }
208
209         arg = argv[2];
210         output_idx = strtol(arg, &end, 10);
211
212         arg = argv[3];
213         mode = strtol(arg, &end, 10);
214
215         err = tdm_output_choose_commit_per_vblank_mode(tdm_display_get_output(dpy, output_idx, NULL), mode);
216         if (err != TDM_ERROR_NONE) {
217                 TDM_SNPRINTF(reply, len, "an error: output_idx or mode is wrong\n");
218                 return;
219         }
220
221         TDM_SNPRINTF(reply, len, "the mode's been set\n");
222 }
223
224 static void
225 _tdm_monitor_server_fps(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
226 {
227         int enable;
228         char *arg;
229         char *end;
230
231         if (argc < 3) {
232                 _tdm_monitor_server_usage(argv[0], reply, len);
233                 return;
234         }
235
236         arg = argv[2];
237         enable = strtol(arg, &end, 10);
238
239         tdm_display_enable_fps(dpy, enable);
240
241         TDM_SNPRINTF(reply, len, "%s to print fps\n", (enable) ? "enable" : "disable");
242 }
243
244 static void
245 _tdm_monitor_server_vblank_list(unsigned int pid, char *cwd, int argc, char *argv[],
246                                                                 char *reply, int *len, tdm_display *dpy)
247 {
248         tdm_vblank_get_vblank_list_information(dpy, reply, len);
249 }
250
251 static void
252 _tdm_monitor_server_vblank_fps(unsigned int pid, char *cwd, int argc, char *argv[],
253                                                            char *reply, int *len, tdm_display *dpy)
254 {
255         unsigned int target_pid, fps;
256         char *arg;
257         char *end;
258         char name[TDM_NAME_LEN];
259         tdm_error ret;
260
261         if (argc < 3) {
262                 _tdm_monitor_server_usage(argv[0], reply, len);
263                 return;
264         }
265
266         arg = argv[2];
267         target_pid = strtol(arg, &end, 10);
268
269         if (*end == ',') {
270                 arg = end + 1;
271                 end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
272         } else {
273                 strncpy(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1);
274                 name[TDM_NAME_LEN - 1] = '\0';
275         }
276
277         if (*end != '@') {
278                 TDM_SNPRINTF(reply, len, "failed: no fps value\n");
279                 return;
280         }
281
282         arg = end + 1;
283         fps = strtol(arg, &end, 10);
284
285         ret = tdm_vblank_set_client_vblank_fps(target_pid, name, fps);
286         if (ret != TDM_ERROR_NONE) {
287                 TDM_SNPRINTF(reply, len, "can't set '%u' fps to '%s' client vblank(PID:%u)\n", fps, name, target_pid);
288                 return;
289         }
290
291         TDM_SNPRINTF(reply, len, "success: '%u' fps for '%s' client vblank(PID:%u)\n", fps, name, target_pid);
292 }
293
294 static void
295 _tdm_monitor_server_global_fps(unsigned int pid, char *cwd, int argc, char *argv[],
296                                                            char *reply, int *len, tdm_display *dpy)
297 {
298         unsigned int fps;
299         char *arg;
300         char *end;
301         tdm_error ret;
302
303         if (argc < 3) {
304                 _tdm_monitor_server_usage(argv[0], reply, len);
305                 return;
306         }
307
308         arg = argv[2];
309         fps = strtol(arg, &end, 10);
310
311         if (fps > 0)
312                 ret = tdm_vblank_enable_global_fps(1, fps);
313         else
314                 ret = tdm_vblank_enable_global_fps(0, 0);
315
316         if (ret != TDM_ERROR_NONE) {
317                 TDM_SNPRINTF(reply, len, "can't set '%u' fps to global fps\n", fps);
318                 return;
319         }
320
321         TDM_SNPRINTF(reply, len, "success: '%u' global fps\n", fps);
322 }
323
324 static void
325 _tdm_monitor_server_prop(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
326 {
327         tdm_output *output;
328         tdm_output *layer = NULL;
329         int output_idx, layer_idx = -1;
330         int cnt, i, done = 0;
331         tdm_value value;
332         char temp[TDM_PATH_LEN];
333         char *prop_name;
334         char *arg;
335         char *end;
336         tdm_error ret;
337         const tdm_prop *props;
338
339         if (argc < 3) {
340                 _tdm_monitor_server_usage(argv[0], reply, len);
341                 return;
342         }
343
344         snprintf(temp, TDM_PATH_LEN, "%s", argv[2]);
345         arg = temp;
346
347         output_idx = strtol(arg, &end, 10);
348         if (*end == ',') {
349                 arg = end + 1;
350                 layer_idx = strtol(arg, &end, 10);
351         }
352
353         if (*end != ':') {
354                 TDM_SNPRINTF(reply, len, "failed: no prop_name\n");
355                 return;
356         }
357
358         arg = end + 1;
359         prop_name = strtok_r(arg, ",", &end);
360         if (!prop_name) {
361                 TDM_SNPRINTF(reply, len, "failed: get prop_name by strtok_r\n");
362                 return;
363         }
364
365         if (*end == '\0') {
366                 TDM_SNPRINTF(reply, len, "failed: no value\n");
367                 return;
368         }
369
370         arg = strtok_r(NULL, TDM_DELIM, &end);
371         if (!arg) {
372                 TDM_SNPRINTF(reply, len, "failed: get arg by strtok_r\n");
373                 return;
374         }
375         value.u32 = strtol(arg, &end, 10);
376
377         output = tdm_display_get_output(dpy, output_idx, &ret);
378         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
379
380         if (layer_idx != -1) {
381                 layer = tdm_output_get_layer(output, layer_idx, &ret);
382                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && layer != NULL);
383         }
384
385         if (layer) {
386                 ret = tdm_layer_get_available_properties(layer, &props, &cnt);
387                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
388
389                 for (i = 0; i < cnt; i++) {
390                         if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
391                                 ret = tdm_layer_set_property(layer, props[i].id, value);
392                                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
393                                 done = 1;
394                                 break;
395                         }
396                 }
397         } else {
398                 ret = tdm_output_get_available_properties(output, &props, &cnt);
399                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
400
401                 for (i = 0; i < cnt; i++) {
402                         if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
403                                 ret = tdm_output_set_property(output, props[i].id, value);
404                                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
405                                 done = 1;
406                                 break;
407                         }
408                 }
409         }
410
411         if (done)
412                 TDM_SNPRINTF(reply, len, "done: %s:%d \n", prop_name, value.u32);
413         else
414                 TDM_SNPRINTF(reply, len, "no '%s' propperty \n", prop_name);
415 }
416
417 static void
418 _tdm_monitor_server_dump(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
419 {
420         if (argc < 3) {
421                 _tdm_monitor_server_usage(argv[0], reply, len);
422                 return;
423         }
424
425         tdm_display_enable_dump(dpy, (const char*)argv[2], reply, len);
426 }
427
428 static void
429 _tdm_monitor_server_punch(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
430 {
431         char *arg, *end;
432         unsigned int output_id, layer_id;
433         tdm_output *output;
434         tdm_layer *layer;
435         tbm_surface_h buffer;
436
437         arg = argv[2];
438
439         output_id = strtol(arg, &end, 10);
440         output = tdm_display_get_output(dpy, output_id, NULL);
441         if (!output) {
442                 TDM_SNPRINTF(reply, len, "not found output\n");
443                 return;
444         }
445         if (*end != ',') {
446                 TDM_SNPRINTF(reply, len, "not found ',<layer_idx>'\n");
447                 return;
448         }
449
450         arg = end + 1;
451         layer_id = strtol(arg, &end, 10);
452         layer = tdm_output_get_layer(output, layer_id, NULL);
453         if (!layer) {
454                 TDM_SNPRINTF(reply, len, "not found layer\n");
455                 return;
456         }
457
458         buffer = tdm_layer_get_displaying_buffer(layer, NULL);
459         if (!buffer) {
460                 TDM_SNPRINTF(reply, len, "not found buffer\n");
461                 return;
462         }
463
464         if (*end == ':') {
465                 tdm_pos pos = {0,};
466
467                 arg = end + 1;
468                 pos.w = strtol(arg, &end, 10);
469                 TDM_EXIT_IF_FAIL(*end == 'x');
470                 arg = end + 1;
471                 pos.h = strtol(arg, &end, 10);
472                 if (*end == '+') {
473                         arg = end + 1;
474                         pos.x = strtol(arg, &end, 10);
475                         TDM_EXIT_IF_FAIL(*end == '+');
476                         arg = end + 1;
477                         pos.y = strtol(arg, &end, 10);
478                 }
479
480                 tdm_helper_clear_buffer_pos(buffer, &pos);
481         } else
482                 tdm_helper_clear_buffer(buffer);
483 }
484
485 static struct {
486         const char *opt;
487         void (*func)(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy);
488         const char *desc;
489         const char *arg;
490         const char *ex;
491 } option_proc[] = {
492         {
493                 "info", _tdm_monitor_server_query,
494                 "show tdm output, layer information", NULL, NULL
495         },
496         {
497                 "trace", _tdm_monitor_server_protocol_trace,
498                 "enable/disable the wl protocol",
499                 "<enable>",
500                 "0 or 1"
501         },
502         {
503                 "dpms", _tdm_monitor_server_dpms,
504                 "set output dpms", "<output_idx>:<dpms>", "0:3 or 0:0"
505         },
506         {
507                 "ttrace", _tdm_monitor_server_ttrace,
508                 "enable/disable ttrace (module: none,vsync,client_vblank,server_vblank,vblank,layer,pp,capture,all",
509                 "<module>[@<output_idx>]",
510                 NULL
511         },
512         {
513                 "debug", _tdm_monitor_server_debug,
514                 "set the debug level and modules(module: none, mutex, buffer, thread, vblank)",
515                 "<level>[@<module1>[,<module2>]]",
516                 NULL
517         },
518         {
519                 "log_path", _tdm_monitor_server_log_path,
520                 "set the log path (console,dlog,filepath)",
521                 "<path>",
522                 "console"
523         },
524         {
525                 "choose_commit_per_vblank_mode", _tdm_monitor_server_choose_commit_per_vblank_mode,
526                 "choose a commit_per_vblank mode for the output",
527                 "<output_idx> <mode>",
528                 "0 1 or 1 2 or 2 0"
529         },
530         {
531                 "fps", _tdm_monitor_server_fps,
532                 "enable/disable to print fps",
533                 "<enable>",
534                 "0 or 1"
535         },
536         {
537                 "vblank_list", _tdm_monitor_server_vblank_list,
538                 "print the client vblank list",
539                 NULL,
540                 NULL
541         },
542         {
543                 "vblank_fps", _tdm_monitor_server_vblank_fps,
544                 "set the client vblank fps for the given process ID and client vblank name",
545                 "<pid>[,<vblank_name>]@<fps>",
546                 NULL
547         },
548         {
549                 "global_fps", _tdm_monitor_server_global_fps,
550                 "set the global vblank fps for the entire system",
551                 "<fps>",
552                 NULL
553         },
554         {
555                 "prop", _tdm_monitor_server_prop,
556                 "set the property of a output or a layer",
557                 "<output_idx>[,<layer_idx>]:<prop_name>,<value>",
558                 NULL
559         },
560         {
561                 "dump", _tdm_monitor_server_dump,
562                 "dump buffers (type: none, layer, pp, capture, current)\n"
563                 "\t\t  layer, pp, capture - start to dump buffers of layer, pp, capture\n"
564                 "\t\t  none               - stop to dump buffers\n"
565                 "\t\t  current            - dump the current buffer of all layers",
566                 "<object_type1>[,<object_type2>[,...]][@<directory_path>]",
567                 NULL
568         },
569         {
570                 "punch", _tdm_monitor_server_punch,
571                 "punch a layer",
572                 "<output_idx>,<layer_idx>[:<w>x<h>[+<x>+<y>]]",
573                 NULL
574         },
575 };
576
577 static void
578 _tdm_monitor_server_usage(char *app_name, char *reply, int *len)
579 {
580         int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
581         int i;
582
583         TDM_SNPRINTF(reply, len, "usage: %s \n\n", app_name);
584
585         for (i = 0; i < opt_size; i++) {
586                 TDM_SNPRINTF(reply, len, "\t-%s\t%s\n", option_proc[i].opt, option_proc[i].desc);
587                 if (option_proc[i].arg)
588                         TDM_SNPRINTF(reply, len, "\t\t  %s\n", option_proc[i].arg);
589                 if (option_proc[i].ex)
590                         TDM_SNPRINTF(reply, len, "\t\t  ex) %s\n", option_proc[i].ex);
591                 TDM_SNPRINTF(reply, len, "\n");
592         }
593 }
594
595 static void
596 _tdm_monitor_server_command(unsigned int pid, char *cwd, tdm_display *dpy, int argc, char *argv[], char *reply, int *len)
597 {
598         int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
599         int i;
600
601         if (argc < 2) {
602                 _tdm_monitor_server_usage(argv[0], reply, len);
603                 return;
604         }
605
606         for (i = 0; i < opt_size; i++) {
607                 if (argv[1][0] == '-' && !strncmp(argv[1] + 1, option_proc[i].opt, 32)) {
608                         if (option_proc[i].func) {
609                                 option_proc[i].func(pid, cwd, argc, argv, reply, len, dpy);
610                                 return;
611                         } else {
612                                 TDM_SNPRINTF(reply, len, "'%s' not implemented.\n", argv[1]);
613                                 return;
614                         }
615                 }
616         }
617
618         _tdm_monitor_server_usage(argv[0], reply, len);
619         return;
620 }
621
622
623 INTERN void
624 tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len)
625 {
626         unsigned int pid;
627         char cwd[1024];
628         int argc = 0;
629         char *argv[TDM_DBG_SERVER_ARGS_MAX] = {0,};
630         char temp[1024];
631         char *arg;
632         char *end = NULL, *e;
633
634         snprintf(temp, sizeof(temp), "%s", options);
635
636         arg = strtok_r(temp, " ", &end);
637         if (!arg) {
638                 TDM_SNPRINTF(reply, len, "no pid for tdm-monitor");
639                 return;
640         }
641         pid = strtol(arg, &e, 10);
642
643         arg = strtok_r(NULL, " ", &end);
644         if (!arg) {
645                 TDM_SNPRINTF(reply, len, "no cwd for tdm-monitor");
646                 return;
647         }
648         snprintf(cwd, sizeof(cwd), "%s", arg);
649
650         TDM_DBG("pid(%d) cwd(%s)", pid, cwd);
651
652         argv[argc] = strtok_r(NULL, " ", &end);
653         while (argv[argc]) {
654                 argc++;
655                 if (argc == TDM_DBG_SERVER_ARGS_MAX) {
656                         TDM_SNPRINTF(reply, len, "too many arguments for tdm-monitor");
657                         break;
658                 }
659                 argv[argc] = strtok_r(NULL, " ", &end);
660         }
661
662         _tdm_monitor_server_command(pid, cwd, dpy, argc, argv, reply, len);
663 }
664 /* LCOV_EXCL_STOP */