From: Konrad Kuchciak Date: Wed, 7 Apr 2021 09:49:10 +0000 (+0200) Subject: Add diagnostic interface X-Git-Tag: submit/tizen/20210409.081821~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=90260bcb979fdad237d8836ccc62c840406102ea;p=platform%2Fcore%2Fsystem%2Fstability-monitor.git Add diagnostic interface Change-Id: Ifdfef48b301c0bc50ea061d9d073aa06f95b38ec --- diff --git a/Makefile b/Makefile index 0240f52..43e50ec 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ src = \ src/dbus.c \ src/limit.c \ src/action.c \ + src/diagnostic_dump.c \ src/raw_data.c \ src/raw_data_providers/proc_tsm.c \ src/data_source.c \ diff --git a/src/diagnostic_dump.c b/src/diagnostic_dump.c new file mode 100644 index 0000000..ee9590e --- /dev/null +++ b/src/diagnostic_dump.c @@ -0,0 +1,174 @@ +#include +#include +#include + +#include "log.h" +#include "process.h" +#include "data_source.h" +#include "utils.h" + +struct dump_options { + int fd; + int pid; + long last; + char *type; + unsigned long long request_time; +}; + +static void dump_help(struct dump_options *opt) +{ + dprintf(opt->fd, + "Options:\n" + " -p, --pid Dump only process with given pid\n" + " -t, --type Dump only specified module, ex. cpu, mem, io or fd\n" + " -l, --last Dump data from last seconds\n" + " -h, --help Dump this help message\n"); +} + +static void dump_process_data(struct proc_info *process, struct dump_options *opt) +{ + struct data_source *ds; + struct smpl_container *sample_container; + struct sample_s *sample; + int foreground = process_is_foreground(process); + double sample_offset; + + dprintf(opt->fd, "%s (%d)\n", process->name, process->pid); + + /* Iterate over data sources */ + for (int j = 0; j < data_sources_get_n(); j++) { + ds = &(process->data_sources[j]); + + /* Skip if type doesn't match */ + if (opt->type && strncmp(opt->type, ds->param_name, strlen(opt->type)) != 0) + continue; + + dprintf(opt->fd, "\t%s\n", ds->param_name); + + /* Iterate over samples */ + sample_container = foreground ? &(ds->data_fg) : &(ds->data_bg); + list_for_each_entry(sample, &sample_container->samples, node) { + sample_offset = (opt->request_time - sample->measure_time) * 1.0 / USEC_PER_SEC; + if (sample_offset < opt->last) + dprintf(opt->fd, "\t\t%s (+%.3fs)\n", smpl2str(sample), sample_offset); + } + } +} + +static int parse_params(char **params, int params_size, struct dump_options *opt) +{ + static struct option long_options[] = { + {"pid", required_argument, NULL, 'p'}, + {"type", required_argument, NULL, 't'}, + {"last", required_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, + {} + }; + int c; + char **params_ex; + + /* Insert additional parameter at the begining of the array for getopt to work */ + params_ex = alloca((params_size + 1) * sizeof(char*)); + memcpy(¶ms_ex[1], params, params_size * sizeof(char*)); + params_ex[0] = 0; + + optind = 0; + while ((c = getopt_long_only(params_size + 1, params_ex, "p:t:l:h", long_options, NULL)) >= 0) { + switch (c) { + case 'p': + opt->pid = atoi(optarg); + break; + + case 't': + if (opt->type) + free(opt->type); + + opt->type = strdup(optarg); + if (!opt->type) { + _E("Unable to allocate memory"); + return -ENOMEM; + } + break; + + case 'l': + opt->last = strtol(optarg, NULL, 10); + break; + + case 'h': + dump_help(opt); + return -ECANCELED; + + default: + return -EINVAL; + } + } + + return 0; +} + +static void data_request_cb(diagnostics_data_h data, char **params, int params_size, diagnostics_ctx_h ctx, void *user_data) +{ + struct proc_info *process, *next; + struct list_head *process_table = process_table_get(); + struct dump_options opt; + int ret; + + opt.fd = -1; + opt.pid = 0; + opt.type = NULL; + opt.request_time = time_now(); + opt.last = opt.request_time / USEC_PER_SEC; + + ret = diagnostics_data_get_fd(data, &opt.fd); + if (ret) { + _E("Unable to get file descriptor to write data: %d", ret); + goto cleanup; + } + + ret = parse_params(params, params_size, &opt); + if (ret) { + if (ret != -ECANCELED) + _E("Unable to parse data request parameters: %d", ret); + goto cleanup; + } + + if (opt.pid) { + /* Dump one process */ + process = process_get_by_pid(opt.pid); + if (!process) { + _E("No such process: %d", opt.pid); + goto cleanup; + } + + dump_process_data(process, &opt); + } else { + /* Dump all processes */ + for (int i = 0; i < HASH_TABLE_SIZE; i++) + list_for_each_entry_safe(process, next, &process_table[i], node) + dump_process_data(process, &opt); + } + +cleanup: + if (opt.type) + free(opt.type); + diagnostics_data_destroy(data); +} + +int diagnostic_dump_init(void) +{ + int ret; + + ret = diagnostics_set_client_id("org.tizen.stability-monitor"); + if (ret) { + _E("Unable to set diagnostic client id: %d", ret); + return ret; + } + + ret = diagnostics_set_data_request_cb(data_request_cb, NULL); + if (ret) { + _E("Unable to set data request cb: %d", ret); + return ret; + } + + return 0; +} diff --git a/src/diagnostic_dump.h b/src/diagnostic_dump.h new file mode 100644 index 0000000..804d2ba --- /dev/null +++ b/src/diagnostic_dump.h @@ -0,0 +1,24 @@ +/* + * This file is part of stability-monitor + * + * Copyright © 2021 Samsung Electronics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DIAGNOSTIC_DUMP_H +#define DIAGNOSTIC_DUMP_H + +int diagnostic_dump_init(void); + +#endif // DIAGNOSTIC_DUMP_H diff --git a/src/process.c b/src/process.c index 94cd2c3..392ec45 100644 --- a/src/process.c +++ b/src/process.c @@ -32,8 +32,6 @@ #include "process.h" -#define HASH_TABLE_SIZE 200 - /* List of all processes and their current state */ static struct list_head process_table[HASH_TABLE_SIZE]; static void process_cleanup(struct proc_info *process); @@ -54,6 +52,11 @@ static void process_table_add(struct proc_info *process) list_add(&process->node, &process_table[hash(process->pid)]); } +struct list_head *process_table_get() +{ + return process_table; +} + int process_create_info(int pid, int ppid, struct proc_info **process) { struct proc_info *p; diff --git a/src/process.h b/src/process.h index 329c3b5..4574450 100644 --- a/src/process.h +++ b/src/process.h @@ -25,6 +25,7 @@ #include "limit.h" #define STATE_HEADER_EVERY_N_MSG 20 +#define HASH_TABLE_SIZE 200 enum proc_class { PROC_CLASS_FG_NATIVE_APP, @@ -69,6 +70,7 @@ struct proc_info { }; void process_table_init(); +struct list_head *process_table_get(); int process_create_info(int pid, int ppid, struct proc_info **process); int process_update_info(struct proc_info *process, int *status); void process_copy_settings(struct proc_info *src, struct proc_info *dst); diff --git a/src/stability-monitor.c b/src/stability-monitor.c index 0bf2bf1..8fafb4c 100644 --- a/src/stability-monitor.c +++ b/src/stability-monitor.c @@ -31,6 +31,7 @@ #include "dbus.h" #include "raw_data.h" #include "data_source.h" +#include "diagnostic_dump.h" #define USER_CONFIG_DIR "/etc/stability-monitor.d" @@ -262,6 +263,12 @@ static int setup(GMainLoop *loop) return -1; } + ret = diagnostic_dump_init(); + if (ret) { + _E("Unable to initialize diagnostic dump module: %d", ret); + return -1; + } + process_table_init(); /* Schedule periodic processing */