Add diagnostic interface 75/256575/2
authorKonrad Kuchciak <k.kuchciak@samsung.com>
Wed, 7 Apr 2021 09:49:10 +0000 (11:49 +0200)
committerKonrad Kuchciak <k.kuchciak@samsung.com>
Wed, 7 Apr 2021 11:29:31 +0000 (13:29 +0200)
Change-Id: Ifdfef48b301c0bc50ea061d9d073aa06f95b38ec

Makefile
src/diagnostic_dump.c [new file with mode: 0644]
src/diagnostic_dump.h [new file with mode: 0644]
src/process.c
src/process.h
src/stability-monitor.c

index 0240f52..43e50ec 100644 (file)
--- 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 (file)
index 0000000..ee9590e
--- /dev/null
@@ -0,0 +1,174 @@
+#include <diagnostics.h>
+#include <string.h>
+#include <getopt.h>
+
+#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 <number>       Dump only process with given pid\n"
+            "  -t, --type <module>      Dump only specified module, ex. cpu, mem, io or fd\n"
+            "  -l, --last <sec>         Dump data from last <sec> 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(&params_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 (file)
index 0000000..804d2ba
--- /dev/null
@@ -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
index 94cd2c3..392ec45 100644 (file)
@@ -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;
index 329c3b5..4574450 100644 (file)
@@ -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);
index 0bf2bf1..8fafb4c 100644 (file)
@@ -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 */