blob: cdbc3ad1a5a991ae52c09f0bb48d117eb7c0713f [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
*/
/**
* @file libkshark-configio.c
* @brief Json Configuration I/O.
*/
// C
#ifndef _GNU_SOURCE
/** Use GNU C Library. */
#define _GNU_SOURCE
#endif // _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
// KernelShark
#include "libkshark.h"
#include "libkshark-model.h"
#include "libkshark-plugin.h"
#include "libkshark-tepdata.h"
static struct json_object *kshark_json_config_alloc(const char *type)
{
json_object *jobj, *jtype;
jobj = json_object_new_object();
jtype = json_object_new_string(type);
if (!jobj || !jtype)
goto fail;
/* Set the type of this Json document. */
json_object_object_add(jobj, "type", jtype);
return jobj;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jobj);
json_object_put(jtype);
return NULL;
}
/**
* @brief Allocate kshark_config_doc and set its format.
*
* @param format: Input location for the Configuration format identifier.
* Currently only Json and String formats are supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* free() to free the object.
*/
struct kshark_config_doc *
kshark_config_alloc(enum kshark_config_formats format)
{
struct kshark_config_doc *doc;
switch (format) {
case KS_CONFIG_AUTO:
case KS_CONFIG_JSON:
case KS_CONFIG_STRING:
doc = malloc(sizeof(*doc));
if (!doc)
goto fail;
doc->format = format;
doc->conf_doc = NULL;
return doc;
default:
fprintf(stderr, "Document format %d not supported\n",
format);
}
return NULL;
fail:
fprintf(stderr, "Failed to allocate memory for kshark_config_doc.\n");
return NULL;
}
/**
* @brief Create an empty Configuration document and set its format and type.
*
* @param type: String describing the type of the document,
* e.g. "kshark.config.record" or "kshark.config.filter".
* @param format: Input location for the Configuration format identifier.
* Currently only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_config_new(const char *type, enum kshark_config_formats format)
{
struct kshark_config_doc *doc = NULL;
if (format == KS_CONFIG_AUTO)
format = KS_CONFIG_JSON;
switch (format) {
case KS_CONFIG_JSON:
doc = kshark_config_alloc(format);
if (doc) {
doc->conf_doc = kshark_json_config_alloc(type);
if (!doc->conf_doc) {
free(doc);
doc = NULL;
}
}
break;
case KS_CONFIG_STRING:
doc = kshark_config_alloc(format);
break;
default:
fprintf(stderr, "Document format %d not supported\n",
format);
return NULL;
}
return doc;
}
/**
* @brief Free the Configuration document.
*
* @param conf: Input location for the kshark_config_doc instance. It is safe
* to pass a NULL value.
*/
void kshark_free_config_doc(struct kshark_config_doc *conf)
{
if (!conf)
return;
switch (conf->format) {
case KS_CONFIG_JSON:
json_object_put(conf->conf_doc);
break;
case KS_CONFIG_STRING:
free(conf->conf_doc);
break;
}
free(conf);
}
/**
* @brief Use an existing Json document to create a new KernelShark
* Configuration document.
*
* @param jobj: Input location for the json_object instance.
*
* @returns shark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *kshark_json_to_conf(struct json_object *jobj)
{
struct kshark_config_doc *conf = kshark_config_alloc(KS_CONFIG_JSON);
if (conf)
conf->conf_doc = jobj;
return conf;
}
/**
* @brief Use an existing string to create a new KernelShark Configuration
* document.
*
* @param val: Input location for the string.
*
* @returns shark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *kshark_string_to_conf(const char* val)
{
struct kshark_config_doc *conf;
char *str;
conf = kshark_config_alloc(KS_CONFIG_STRING);
if (conf) {
if (asprintf(&str, "%s", val) > 0) {
conf->conf_doc = str;
} else {
fprintf(stderr,
"Failed to allocate string conf. doc.\n");
free(conf);
conf = NULL;
}
}
return conf;
}
/**
* @brief Add a field to a KernelShark Configuration document.
*
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
* @param key: The name of the field.
* @param val: Input location for the kshark_config_doc to be added. Currently
* only Json and String formats are supported. Pass KS_CONFIG_AUTO
* if you want "val" to have the same fornat as "conf". Upon
* calling this function, the ownership of "val" transfers to
* "conf".
*
* @returns True on success, otherwise False.
*/
bool kshark_config_doc_add(struct kshark_config_doc *conf,
const char *key,
struct kshark_config_doc *val)
{
struct json_object *jobj = NULL;
if (!conf || !val)
return false;
if (val->format == KS_CONFIG_AUTO)
val->format = conf->format;
switch (conf->format) {
case KS_CONFIG_JSON:
switch (val->format) {
case KS_CONFIG_JSON:
json_object_object_add(conf->conf_doc, key,
val->conf_doc);
break;
case KS_CONFIG_STRING:
jobj = json_object_new_string(val->conf_doc);
if (!jobj)
goto fail;
json_object_object_add(conf->conf_doc, key, jobj);
break;
default:
fprintf(stderr, "Value format %d not supported\n",
val->format);
return false;
}
free(val);
break;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jobj);
return false;
}
static bool get_jval(struct kshark_config_doc *conf,
const char *key, void **val)
{
return json_object_object_get_ex(conf->conf_doc, key,
(json_object **) val);
}
/**
* @brief Get the KernelShark Configuration document associate with a given
* field name.
*
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
* @param key: The name of the field.
* @param val: Output location for the kshark_config_doc instance containing
* the field. Currently only Json and String formats are supported.
*
* @returns True, if the key exists, otherwise False.
*/
bool kshark_config_doc_get(struct kshark_config_doc *conf,
const char *key,
struct kshark_config_doc *val)
{
struct kshark_config_doc *tmp;
if (!conf || !val)
return false;
if (val->format == KS_CONFIG_AUTO)
val->format = conf->format;
switch (conf->format) {
case KS_CONFIG_JSON:
switch (val->format) {
case KS_CONFIG_JSON:
json_object_put(val->conf_doc);
if (!get_jval(conf, key, &val->conf_doc))
goto not_found;
return true;
case KS_CONFIG_STRING:
tmp = kshark_config_alloc(KS_CONFIG_AUTO);
if (!tmp)
goto fail;
if (!get_jval(conf, key, &tmp->conf_doc))
goto not_found;
val->conf_doc =
(char *) json_object_get_string(tmp->conf_doc);
free(tmp);
return true;
default:
fprintf(stderr, "Value format %d not supported\n",
val->format);
return false;
}
break;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
return true;
fail:
fprintf(stderr, "Failed to get config. document <%s>.\n", key);
not_found:
return false;
}
/**
* @brief Create an empty Record Configuration document. The type description
* is set to "kshark.config.record".
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_record_config_new(enum kshark_config_formats format)
{
return kshark_config_new("kshark.config.record", format);
}
/**
* @brief Create an empty Data Stream Configuration document. The type
* description is set to "kshark.config.stream".
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_stream_config_new(enum kshark_config_formats format)
{
return kshark_config_new("kshark.config.stream", format);
}
/**
* @brief Create an empty Filter Configuration document. The type description
* is set to "kshark.config.filter".
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_filter_config_new(enum kshark_config_formats format)
{
return kshark_config_new("kshark.config.filter", format);
}
/**
* @brief Create an empty Session Configuration document. The type description
* is set to "kshark.config.filter".
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_session_config_new(enum kshark_config_formats format)
{
return kshark_config_new("kshark.config.session", format);
}
/**
* @brief Create an empty Text Configuration document. The Text Configuration
* documents do not use type descriptions.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use free()
* to free the object.
*/
struct kshark_config_doc *kshark_string_config_alloc(void)
{
return kshark_config_alloc(KS_CONFIG_STRING);
}
static void json_del_if_exist(struct json_object *jobj, const char *key)
{
struct json_object *temp;
if (json_object_object_get_ex(jobj, key, &temp))
json_object_object_del(jobj, key);
}
static bool kshark_json_type_check(struct json_object *jobj, const char *type)
{
struct json_object *jtype;
const char *type_str;
if (!json_object_object_get_ex(jobj, "type", &jtype))
return false;
type_str = json_object_get_string(jtype);
if (strcmp(type_str, type) != 0)
return false;
return true;
}
/**
* @brief Check the type of a Configuration document and compare with an
* expected value.
*
* @param conf: Input location for the kshark_config_doc instance.
* @param type: Input location for the expected value of the Configuration
* document type, e.g. "kshark.config.record" or
* "kshark.config.filter".
*
* @returns True, if the document has the expected type, otherwise False.
*/
bool kshark_type_check(struct kshark_config_doc *conf, const char *type)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_json_type_check(conf->conf_doc, type);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_trace_file_to_json(const char *file, const char *name,
struct json_object *jobj)
{
struct json_object *jfile_name, *jbuffer_name, *jtime;
char abs_path[FILENAME_MAX];
struct stat st;
if (!file || !jobj)
return false;
if (stat(file, &st) != 0) {
fprintf(stderr, "Unable to find file %s\n", file);
return false;
}
if (!realpath(file, abs_path)) {
fprintf(stderr, "Unable to get absolute pathname for %s\n",
file);
return false;
}
jfile_name = json_object_new_string(abs_path);
jbuffer_name = json_object_new_string(name);
jtime = json_object_new_int64(st.st_mtime);
if (!jfile_name || !jtime)
goto fail;
json_object_object_add(jobj, "file", jfile_name);
json_object_object_add(jobj, "name", jbuffer_name);
json_object_object_add(jobj, "time", jtime);
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jobj);
json_object_put(jfile_name);
json_object_put(jtime);
return false;
}
/**
* @brief Record the name of a trace data file and its timestamp into a
* Configuration document.
*
* @param file: The name of the file.
* @param name: The name of the data buffer.
* @param format: Input location for the Configuration format identifier.
* Currently only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_export_trace_file(const char *file, const char *name,
enum kshark_config_formats format)
{
/* Create a new Configuration document. */
struct kshark_config_doc *conf =
kshark_config_new("kshark.config.data", format);
if (!conf)
return NULL;
switch (format) {
case KS_CONFIG_JSON:
kshark_trace_file_to_json(file, name, conf->conf_doc);
return conf;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return NULL;
}
}
static bool kshark_trace_file_from_json(const char **file, const char **name,
const char *type,
struct json_object *jobj)
{
struct json_object *jfile_name, *jbuffer_name, *jtime;
const char *file_str, *name_str;
struct stat st;
char *header;
int64_t time;
bool type_OK = true;
if (!jobj)
return false;
if (type) {
/* Make sure that the condition document has a correct type. */
type_OK = false;
if (asprintf(&header, "kshark.config.%s", type) >= 0)
type_OK = kshark_json_type_check(jobj, header);
}
if (!type_OK ||
!json_object_object_get_ex(jobj, "file", &jfile_name) ||
!json_object_object_get_ex(jobj, "name", &jbuffer_name) ||
!json_object_object_get_ex(jobj, "time", &jtime)) {
fprintf(stderr,
"Failed to retrieve data file from json_object.\n");
return false;
}
file_str = json_object_get_string(jfile_name);
name_str = json_object_get_string(jbuffer_name);
time = json_object_get_int64(jtime);
if (stat(file_str, &st) != 0) {
fprintf(stderr, "Unable to find file %s\n", file_str);
return false;
}
if (st.st_mtime != time) {
fprintf(stderr, "Timestamp mismatch! (%" PRIu64 "!=%li)\nFile %s\n",
time, st.st_mtime, file_str);
return false;
}
*file = file_str;
*name = name_str;
return true;
}
/* Quiet warnings over documenting simple structures */
//! @cond Doxygen_Suppress
#define TOP_BUFF_NAME "top buffer"
//! @endcond
/**
* @brief Read the name of a trace data file and its timestamp from a
* Configuration document and check if such a file exists.
* If the file exists, open it.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns The Id number of the data stream associated with the loaded file on
* success, otherwise -1. "conf" has the ownership over the returned
* string.
*/
int kshark_import_trace_file(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf)
{
const char *file = NULL, *name = NULL;
int sd = -1;
switch (conf->format) {
case KS_CONFIG_JSON:
if (kshark_trace_file_from_json(&file, &name, "data",
conf->conf_doc)) {
if (strcmp(name, KS_UNNAMED) == 0 ||
strcmp(name, TOP_BUFF_NAME) == 0) {
sd = kshark_open(kshark_ctx, file);
} else {
int sd_top;
sd_top = kshark_tep_find_top_stream(kshark_ctx,
file);
if (sd_top < 0) {
/*
* The "top" steam (buffer) has to be
* initialized first.
*/
sd_top = kshark_open(kshark_ctx, file);
}
if (sd_top >= 0)
sd = kshark_tep_open_buffer(kshark_ctx,
sd_top,
name);
if (sd >= 0)
kshark_tep_handle_plugins(kshark_ctx, sd);
}
}
break;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
break;
}
return sd;
}
static bool kshark_plugin_to_json(struct kshark_plugin_list *plugin,
struct json_object *jobj)
{
struct json_object *jname = json_object_new_string(plugin->name);
if (!kshark_trace_file_to_json(plugin->file, plugin->name, jobj) ||
!jname) {
json_object_put(jname);
return false;
}
json_object_object_add(jobj, "name", jname);
return true;
}
/**
* @brief Record the name of a plugin's obj file and its timestamp into a
* Configuration document.
*
* @param plugin: The plugin to be expected.
* @param format: Input location for the Configuration format identifier.
* Currently only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_export_plugin_file(struct kshark_plugin_list *plugin,
enum kshark_config_formats format)
{
/* Create a new Configuration document. */
struct kshark_config_doc *conf =
kshark_config_new("kshark.config.library", format);
if (!conf)
return NULL;
switch (format) {
case KS_CONFIG_JSON:
kshark_plugin_to_json(plugin, conf->conf_doc);
return conf;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return NULL;
}
}
static bool kshark_all_plugins_to_json(struct kshark_context *kshark_ctx,
struct json_object *jobj)
{
struct kshark_plugin_list *plugin = kshark_ctx->plugins;
struct json_object *jfile, *jlist;
jlist = json_object_new_array();
if (!jlist)
return false;
while (plugin) {
jfile = json_object_new_object();
if (!kshark_trace_file_to_json(plugin->file, plugin->name, jfile))
goto fail;
json_object_array_add(jlist, jfile);
plugin = plugin->next;
}
json_object_object_add(jobj, "obj. files", jlist);
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jobj);
json_object_put(jlist);
return false;
}
/**
* @brief Record the current list of registered plugins into a
* Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param format: Input location for the Configuration format identifier.
* Currently only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_export_all_plugins(struct kshark_context *kshark_ctx,
enum kshark_config_formats format)
{
struct kshark_config_doc *conf =
kshark_config_new("kshark.config.plugins", KS_CONFIG_JSON);
if (!conf)
return NULL;
switch (format) {
case KS_CONFIG_JSON:
kshark_all_plugins_to_json(kshark_ctx, conf->conf_doc);
return conf;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return NULL;
}
}
static bool kshark_plugin_from_json(struct kshark_context *kshark_ctx,
struct json_object *jobj)
{
const char *file, *name;
if (!kshark_trace_file_from_json(&file, &name, NULL, jobj)) {
fprintf(stderr, "Failed to import plugin!\n");
return false;
}
return !!(long) kshark_register_plugin(kshark_ctx, name, file);
}
static bool kshark_all_plugins_from_json(struct kshark_context *kshark_ctx,
struct json_object *jobj)
{
struct json_object *jlist = NULL, *jfile = NULL;
int i, n_plugins;
if (!kshark_ctx || !jobj)
return false;
if (!kshark_json_type_check(jobj, "kshark.config.plugins") ||
!json_object_object_get_ex(jobj, "obj. files", &jlist) ||
json_object_get_type(jlist) != json_type_array)
goto fail;
n_plugins = json_object_array_length(jlist);
for (i = 0; i < n_plugins; ++i) {
jfile = json_object_array_get_idx(jlist, i);
if (!jfile)
goto fail;
kshark_plugin_from_json(kshark_ctx, jfile);
}
return true;
fail:
json_object_put(jfile);
json_object_put(jlist);
return false;
}
/**
* @brief Load the list of registered plugins from a Configuration
* document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if plugins have been loaded. If the configuration
* document contains no data or in a case of an error, the function
* returns False.
*/
bool kshark_import_all_plugins(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_all_plugins_from_json(kshark_ctx,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static void kshark_stream_plugins_to_json(struct kshark_data_stream *stream,
struct json_object *jobj)
{
struct kshark_dpi_list *plugin = stream->plugins;
struct json_object *jlist, *jplg;
bool active;
jlist = json_object_new_array();
while (plugin) {
jplg = json_object_new_array();
json_object_array_add(jplg,
json_object_new_string(plugin->interface->name));
active = plugin->status & KSHARK_PLUGIN_ENABLED;
json_object_array_add(jplg, json_object_new_boolean(active));
json_object_array_add(jlist, jplg);
plugin = plugin->next;
}
json_object_object_add(jobj, "registered", jlist);
}
/**
* @brief Record the current list of plugins registered for a given Data
* stream into a Configuration document.
*
* @param stream: Input location for a Trace data stream pointer.
* @param format: Input location for the Configuration format identifier.
* Currently only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_export_stream_plugins(struct kshark_data_stream *stream,
enum kshark_config_formats format)
{
struct kshark_config_doc *conf =
kshark_config_new("kshark.config.plugins", KS_CONFIG_JSON);
if (!conf)
return NULL;
switch (format) {
case KS_CONFIG_JSON:
kshark_stream_plugins_to_json(stream, conf->conf_doc);
return conf;
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return NULL;
}
}
static bool kshark_stream_plugins_from_json(struct kshark_context *kshark_ctx,
struct kshark_data_stream *stream,
struct json_object *jobj)
{
struct json_object *jlist, *jplg, *jname, *jstatus;
struct kshark_plugin_list *plugin;
struct kshark_dpi_list *dpi_list;
struct kshark_dpi *dpi;
int i, n_plugins;
bool active;
jlist = jplg = jname = jstatus = NULL;
if (!kshark_ctx || !stream || !jobj)
return false;
if (!kshark_json_type_check(jobj, "kshark.config.plugins") ||
!json_object_object_get_ex(jobj, "registered", &jlist) ||
json_object_get_type(jlist) != json_type_array)
goto fail;
n_plugins = json_object_array_length(jlist);
for (i = 0; i < n_plugins; ++i) {
jplg = json_object_array_get_idx(jlist, i);
if (!jplg ||
json_object_get_type(jplg) != json_type_array ||
json_object_array_length(jplg) != 2)
goto fail;
jname = json_object_array_get_idx(jplg, 0);
jstatus = json_object_array_get_idx(jplg, 1);
if (!jname || !jstatus)
goto fail;
plugin = kshark_find_plugin_by_name(kshark_ctx->plugins,
json_object_get_string(jname));
if (plugin) {
active = json_object_get_boolean(jstatus);
dpi = plugin->process_interface;
dpi_list = kshark_register_plugin_to_stream(stream, dpi,
active);
kshark_handle_dpi(stream, dpi_list, KSHARK_PLUGIN_INIT);
}
}
return true;
fail:
json_object_put(jplg);
json_object_put(jlist);
return false;
}
/**
* @brief Load the list of registered plugins for a given Data
* stream from a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param stream: Input location for a Trace data stream pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if plugins have been loaded. If the configuration
* document contains no data or in a case of an error, the function
* returns False.
*/
bool kshark_import_stream_plugins(struct kshark_context *kshark_ctx,
struct kshark_data_stream *stream,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_stream_plugins_from_json(kshark_ctx, stream,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_model_to_json(struct kshark_trace_histo *histo,
struct json_object *jobj)
{
struct json_object *jrange, *jmin, *jmax, *jn_bins;
if (!histo || !jobj)
return false;
jrange = json_object_new_array();
jmin = json_object_new_int64(histo->min);
jmax = json_object_new_int64(histo->max);
jn_bins = json_object_new_int(histo->n_bins);
if (!jrange || !jmin || !jmax || !jn_bins)
goto fail;
json_object_array_put_idx(jrange, 0, jmin);
json_object_array_put_idx(jrange, 1, jmax);
json_object_object_add(jobj, "range", jrange);
json_object_object_add(jobj, "bins", jn_bins);
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jobj);
json_object_put(jrange);
json_object_put(jmin);
json_object_put(jmax);
json_object_put(jn_bins);
return false;
}
/**
* @brief Record the current configuration of the Vis. model into a
* Configuration document.
*
* @param histo: Input location for the Vis. model descriptor.
* @param format: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* free() to free the object.
*/
struct kshark_config_doc *
kshark_export_model(struct kshark_trace_histo *histo,
enum kshark_config_formats format)
{
/* Create a new Configuration document. */
struct kshark_config_doc *conf =
kshark_config_new("kshark.config.model", format);
if (!conf)
return NULL;
switch (format) {
case KS_CONFIG_JSON:
kshark_model_to_json(histo, conf->conf_doc);
return conf;
default:
fprintf(stderr, "Document format %d not supported\n",
format);
return NULL;
}
}
static bool kshark_model_from_json(struct kshark_trace_histo *histo,
struct json_object *jobj)
{
struct json_object *jrange, *jmin, *jmax, *jn_bins;
uint64_t min, max;
int n_bins;
if (!histo || !jobj)
return false;
if (!kshark_json_type_check(jobj, "kshark.config.model") ||
!json_object_object_get_ex(jobj, "range", &jrange) ||
!json_object_object_get_ex(jobj, "bins", &jn_bins) ||
json_object_get_type(jrange) != json_type_array ||
json_object_array_length(jrange) != 2)
goto fail;
jmin = json_object_array_get_idx(jrange, 0);
jmax = json_object_array_get_idx(jrange, 1);
if (!jmin || !jmax)
goto fail;
min = json_object_get_int64(jmin);
max = json_object_get_int64(jmax);
n_bins = json_object_get_int(jn_bins);
ksmodel_set_bining(histo, n_bins, min, max);
if (histo->data && histo->data_size)
ksmodel_fill(histo, histo->data, histo->data_size);
return true;
fail:
fprintf(stderr, "Failed to load event filter from json_object.\n");
return false;
}
/**
* @brief Load the configuration of the Vis. model from a Configuration
* document.
*
* @param histo: Input location for the Vis. model descriptor.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if the model has been loaded. If the model configuration
* document contains no data or in a case of an error, the function
* returns False.
*/
bool kshark_import_model(struct kshark_trace_histo *histo,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_model_from_json(histo, conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_event_filter_to_json(struct kshark_data_stream *stream,
enum kshark_filter_type filter_type,
const char *filter_name,
struct json_object *jobj)
{
json_object *jfilter_data, *jname;
struct kshark_hash_id *filter;
char *name_str;
int i, *ids;
filter = kshark_get_filter(stream, filter_type);
if (!filter)
return false;
jname = NULL;
/*
* If this Json document already contains a description of the filter,
* delete this description.
*/
json_del_if_exist(jobj, filter_name);
/* Get the array of Ids to be fitered. */
ids = kshark_hash_ids(filter);
if (!ids)
return true;
/* Create a Json array and fill the Id values into it. */
jfilter_data = json_object_new_array();
if (!jfilter_data)
goto fail;
for (i = 0; i < filter->count; ++i) {
name_str = kshark_event_from_id(stream->stream_id,
ids[i]);
if (name_str) {
jname = json_object_new_string(name_str);
if (!jname)
goto fail;
json_object_array_add(jfilter_data, jname);
}
}
free(ids);
/* Add the array of Ids to the filter config document. */
json_object_object_add(jobj, filter_name, jfilter_data);
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jfilter_data);
json_object_put(jname);
free(ids);
return false;
}
/**
* @brief Record the current configuration of an Event Id filter into a
* Configuration document.
*
* @param stream: Input location for a Trace data stream pointer.
* @param filter_type: Identifier of the filter.
* @param filter_name: The name of the filter to show up in the Json document.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True on success, otherwise False.
*/
bool kshark_export_event_filter(struct kshark_data_stream *stream,
enum kshark_filter_type filter_type,
const char *filter_name,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_event_filter_to_json(stream, filter_type,
filter_name,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static int kshark_event_filter_from_json(struct kshark_data_stream *stream,
enum kshark_filter_type filter_type,
const char *filter_name,
struct json_object *jobj)
{
int i, length, event_id, count = 0;
struct kshark_hash_id *filter;
json_object *jfilter, *jevent;
const char *name_str;
filter = kshark_get_filter(stream, filter_type);
if (!filter)
return 0;
/*
* Use the name of the filter to find the array of events associated
* with this filter. Notice that the filter config document may
* contain no data for this particular filter.
*/
if (!json_object_object_get_ex(jobj, filter_name, &jfilter))
return 0;
if (!kshark_json_type_check(jobj, "kshark.config.filter") ||
json_object_get_type(jfilter) != json_type_array)
goto fail;
/* Set the filter. */
length = json_object_array_length(jfilter);
for (i = 0; i < length; ++i) {
jevent = json_object_array_get_idx(jfilter, i);
name_str = json_object_get_string(jevent);
event_id = kshark_find_event_id(stream, name_str);
if (event_id < 0)
continue;
kshark_hash_id_add(filter, event_id);
count++;
}
if (count != length)
count = -count;
return count;
fail:
fprintf(stderr, "Failed to load event filter from json_object.\n");
kshark_hash_id_clear(filter);
return 0;
}
/**
* @brief Load from Configuration document the configuration of an Event Id filter.
*
* @param stream: Input location for a Trace data stream pointer.
* @param filter_type: Identifier of the filter.
* @param filter_name: The name of the filter as showing up in the Config.
* document.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns The total number of events added to the filter. If not all events
* listed in the input configuration have been added successfully,
* the returned number is negative.
*/
int kshark_import_event_filter(struct kshark_data_stream *stream,
enum kshark_filter_type filter_type,
const char *filter_name,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_event_filter_from_json(stream, filter_type,
filter_name,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return 0;
}
}
static bool kshark_filter_array_to_json(struct kshark_hash_id *filter,
const char *filter_name,
struct json_object *jobj)
{
json_object *jfilter_data, *jpid = NULL;
int i, *ids;
/*
* If this Json document already contains a description of the filter,
* delete this description.
*/
json_del_if_exist(jobj, filter_name);
/* Get the array of Ids to be filtered. */
ids = kshark_hash_ids(filter);
if (!ids)
return true;
/* Create a Json array and fill the Id values into it. */
jfilter_data = json_object_new_array();
if (!jfilter_data)
goto fail;
for (i = 0; i < filter->count; ++i) {
jpid = json_object_new_int(ids[i]);
if (!jpid)
goto fail;
json_object_array_add(jfilter_data, jpid);
}
free(ids);
/* Add the array of Ids to the filter config document. */
json_object_object_add(jobj, filter_name, jfilter_data);
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jfilter_data);
json_object_put(jpid);
free(ids);
return false;
}
/**
* @brief Record the current configuration of a simple Id filter into a
* Configuration document.
*
* @param filter: Input location for an Id filter.
* @param filter_name: The name of the filter to show up in the Json document.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True on success, otherwise False.
*/
bool kshark_export_filter_array(struct kshark_hash_id *filter,
const char *filter_name,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_filter_array_to_json(filter, filter_name,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_filter_array_from_json(struct kshark_hash_id *filter,
const char *filter_name,
struct json_object *jobj)
{
json_object *jfilter, *jpid;
int i, length;
/*
* Use the name of the filter to find the array of events associated
* with this filter. Notice that the filter config document may
* contain no data for this particular filter.
*/
if (!json_object_object_get_ex(jobj, filter_name, &jfilter))
return false;
if (!kshark_json_type_check(jobj, "kshark.config.filter") ||
json_object_get_type(jfilter) != json_type_array)
goto fail;
/* Set the filter. */
length = json_object_array_length(jfilter);
for (i = 0; i < length; ++i) {
jpid = json_object_array_get_idx(jfilter, i);
if (!jpid)
goto fail;
kshark_hash_id_add(filter, json_object_get_int(jpid));
}
return true;
fail:
fprintf(stderr, "Failed to load task filter from json_object.\n");
return false;
}
/**
* @brief Load from Configuration document the configuration of a simple
* Id filter.
*
* @param filter: Input location for an Id filter.
* @param filter_name: The name of the filter as showing up in the Config.
* document.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a filter has been loaded. If the filter configuration
* document contains no data for this particular filter or in a case
* of an error, the function returns False.
*/
bool kshark_import_filter_array(struct kshark_hash_id *filter,
const char *filter_name,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_filter_array_from_json(filter, filter_name,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_adv_filters_to_json(struct kshark_data_stream *stream,
struct json_object *jobj)
{
json_object *jfilter_data, *jevent, *jname, *jfilter;
char *filter_str;
int *events, i;
jevent = jname = jfilter = NULL;
/*
* If this Json document already contains a description of the model,
* delete this description.
*/
json_del_if_exist(jobj, KS_ADV_EVENT_FILTER_NAME);
if (!kshark_tep_filter_is_set(stream))
return true;
/* Create a Json array and fill the Id values into it. */
jfilter_data = json_object_new_array();
if (!jfilter_data)
goto fail;
events = kshark_get_all_event_ids(stream);
if (!events)
return false;
for (i = 0; i < stream->n_events; ++i) {
filter_str = kshark_tep_filter_make_string(stream, events[i]);
if (!filter_str)
continue;
jevent = json_object_new_object();
jname = json_object_new_string(kshark_event_from_id(stream->stream_id,
events[i]));
jfilter = json_object_new_string(filter_str);
if (!jevent || !jname || !jfilter)
goto fail;
json_object_object_add(jevent, "name", jname);
json_object_object_add(jevent, "condition", jfilter);
json_object_array_add(jfilter_data, jevent);
}
/* Add the array of advanced filters to the filter config document. */
json_object_object_add(jobj, KS_ADV_EVENT_FILTER_NAME, jfilter_data);
return true;
fail:
fprintf(stderr, "Failed to allocate memory for json_object.\n");
json_object_put(jfilter_data);
json_object_put(jevent);
json_object_put(jname);
json_object_put(jfilter);
return false;
}
/**
* @brief Record the current configuration of the advanced filter into a
* Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Adv. Filter
* Configuration document will be created.
*
* @returns True on success, otherwise False.
*/
bool kshark_export_adv_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc **conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
if (!stream)
return false;
if (!kshark_is_tep(stream)) {
/* Nothing to export. */
return true;
}
if (!*conf)
*conf = kshark_filter_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
switch ((*conf)->format) {
case KS_CONFIG_JSON:
return kshark_adv_filters_to_json(stream,
(*conf)->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
(*conf)->format);
return false;
}
}
static bool kshark_adv_filters_from_json(struct kshark_data_stream *stream,
struct json_object *jobj)
{
json_object *jfilter, *jname, *jcond;
int i, length, n, ret = 0;
char *filter_str = NULL;
/*
* Use the name of the filter to find the array of events associated
* with this filter. Notice that the filter config document may
* contain no data for this particular filter.
*/
if (!json_object_object_get_ex(jobj, KS_ADV_EVENT_FILTER_NAME,
&jfilter))
return false;
if (!kshark_json_type_check(jobj, "kshark.config.filter") ||
json_object_get_type(jfilter) != json_type_array)
goto fail;
/* Set the filter. */
length = json_object_array_length(jfilter);
for (i = 0; i < length; ++i) {
jfilter = json_object_array_get_idx(jfilter, i);
if (!json_object_object_get_ex(jfilter, "name", &jname) ||
!json_object_object_get_ex(jfilter, "condition", &jcond))
goto fail;
n = asprintf(&filter_str, "%s:%s",
json_object_get_string(jname),
json_object_get_string(jcond));
if (n <= 0) {
filter_str = NULL;
goto fail;
}
ret = kshark_tep_add_filter_str(stream, filter_str);
if (ret < 0)
goto fail;
}
return true;
fail:
fprintf(stderr, "Failed to laod Advanced filters.\n");
free(filter_str);
return false;
}
/**
* @brief Load from Configuration document the configuration of the advanced
* filter.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a filter has been loaded. If the filter configuration
* document contains no data for the Adv. filter or in a case of
* an error, the function returns False.
*/
bool kshark_import_adv_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc *conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
if (!stream)
return false;
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_adv_filters_from_json(stream,
conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_user_mask_to_json(struct kshark_context *kshark_ctx,
struct json_object *jobj)
{
json_object *jmask;
uint8_t mask;
mask = kshark_ctx->filter_mask;
jmask = json_object_new_int((int) mask);
if (!jmask)
return false;
/* Add the mask to the filter config document. */
json_object_object_add(jobj, KS_USER_FILTER_MASK_NAME, jmask);
return true;
}
/**
* @brief Record the current value of the the user-specified filter mask into
* a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Adv. Filter
* Configuration document will be created.
*
* @returns True on success, otherwise False.
*/
bool kshark_export_user_mask(struct kshark_context *kshark_ctx,
struct kshark_config_doc **conf)
{
if (!*conf)
*conf = kshark_filter_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
switch ((*conf)->format) {
case KS_CONFIG_JSON:
return kshark_user_mask_to_json(kshark_ctx, (*conf)->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
(*conf)->format);
return false;
}
}
static bool kshark_user_mask_from_json(struct kshark_context *kshark_ctx,
struct json_object *jobj)
{
json_object *jmask;
uint8_t mask;
if (!kshark_json_type_check(jobj, "kshark.config.filter"))
return false;
/*
* Use the name of the filter to find the value of the filter maks.
* Notice that the filter config document may contain no data for
* the mask.
*/
if (!json_object_object_get_ex(jobj, KS_USER_FILTER_MASK_NAME,
&jmask))
return false;
mask = json_object_get_int(jmask);
kshark_ctx->filter_mask = mask;
return true;
}
/**
* @brief Load from Configuration document the value of the user-specified
* filter mask.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a mask has been loaded. If the filter configuration
* document contains no data for the mask or in a case of an error,
* the function returns False.
*/
bool kshark_import_user_mask(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_user_mask_from_json(kshark_ctx, conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_calib_array_from_json(struct kshark_context *kshark_ctx,
int sd, struct json_object *jobj)
{
json_object *jcalib_argv, *jcalib;
int64_t *calib_argv = NULL;
int i, calib_length;
if (!json_object_object_get_ex(jobj, "calib. array", &jcalib_argv) ||
json_object_get_type(jcalib_argv) != json_type_array)
return false;
calib_length = json_object_array_length(jcalib_argv);
if (!calib_length)
return false;
calib_argv = calloc(calib_length, sizeof(*calib_argv));
for (i = 0; i < calib_length; ++i) {
jcalib = json_object_array_get_idx(jcalib_argv, i);
calib_argv[i] = json_object_get_int64(jcalib);
}
kshark_ctx->stream[sd]->calib = kshark_offset_calib;
kshark_ctx->stream[sd]->calib_array = calib_argv;
kshark_ctx->stream[sd]->calib_array_size = calib_length;
return true;
}
/**
* @brief Load from Configuration document the value of the time calibration
* constants into a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Configuration
* document will be created.
*
* @returns True on success, otherwise False.
*/
bool kshark_import_calib_array(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_calib_array_from_json(kshark_ctx, sd, conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static bool kshark_calib_array_to_json(struct kshark_context *kshark_ctx,
int sd, struct json_object *jobj)
{
json_object *jval = NULL, *jcalib = NULL;
struct kshark_data_stream *stream;
stream = kshark_get_data_stream(kshark_ctx, sd);
if (!stream || !stream->calib_array_size)
goto fail;
jcalib = json_object_new_array();
if (!jcalib)
goto fail;
for (size_t i = 0; i < stream->calib_array_size; ++i) {
jval = json_object_new_int64(stream->calib_array[i]);
if (!jval)
goto fail;
json_object_array_add(jcalib, jval);
}
/* Add the mask to the filter config document. */
json_object_object_add(jobj, "calib. array", jcalib);
return true;
fail:
json_object_put(jval);
json_object_put(jcalib);
return false;
}
/**
* @brief Record the current values of the time calibration constants into
* a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Configuration
* document will be created.
*
* @returns True on success, otherwise False.
*/
bool kshark_export_calib_array(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc **conf)
{
if (!*conf)
*conf = kshark_stream_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
switch ((*conf)->format) {
case KS_CONFIG_JSON:
return kshark_calib_array_to_json(kshark_ctx, sd,
(*conf)->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
(*conf)->format);
return false;
}
}
/**
* @brief Record the current configuration of "show task" and "hide task"
* filters into a Json document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Filter
* Configuration document will be created.
*
* @returns True, if a filter has been recorded. If both filters contain
* no Id values or in a case of an error, the function returns False.
*/
bool kshark_export_all_event_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc **conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
bool ret;
if (!stream)
return false;
if (!*conf)
*conf = kshark_filter_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
/* Save a filter only if it contains Id values. */
ret = true;
if (kshark_this_filter_is_set(stream->show_event_filter))
ret &= kshark_export_event_filter(stream,
KS_SHOW_EVENT_FILTER,
KS_SHOW_EVENT_FILTER_NAME,
*conf);
if (kshark_this_filter_is_set(stream->hide_event_filter))
ret &= kshark_export_event_filter(stream,
KS_HIDE_EVENT_FILTER,
KS_HIDE_EVENT_FILTER_NAME,
*conf);
return ret;
}
/**
* @brief Record the current configuration of "show task" and "hide task"
* filters into a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Filter
* Configuration document will be created.
*
* @returns True, if a filter has been recorded. If both filters contain
* no Id values or in a case of an error, the function returns False.
*/
bool kshark_export_all_task_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc **conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
bool ret;
if (!stream)
return false;
if (!*conf)
*conf = kshark_filter_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
/* Save a filter only if it contains Id values. */
ret = true;
if (kshark_this_filter_is_set(stream->show_task_filter))
ret &= kshark_export_filter_array(stream->show_task_filter,
KS_SHOW_TASK_FILTER_NAME,
*conf);
if (kshark_this_filter_is_set(stream->hide_task_filter))
ret &= kshark_export_filter_array(stream->hide_task_filter,
KS_HIDE_TASK_FILTER_NAME,
*conf);
return ret;
}
/**
* @brief Record the current configuration of "show cpu" and "hide cpu"
* filters into a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Filter
* Configuration document will be created.
*
* @returns True, if a filter has been recorded. If both filters contain
* no Id values or in a case of an error, the function returns False.
*/
bool kshark_export_all_cpu_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc **conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
bool ret;
if (!stream)
return false;
if (!*conf)
*conf = kshark_filter_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
/* Save a filter only if it contains Id values. */
ret = true;
if (kshark_this_filter_is_set(stream->show_cpu_filter))
ret &= kshark_export_filter_array(stream->show_cpu_filter,
KS_SHOW_CPU_FILTER_NAME,
*conf);
if (kshark_this_filter_is_set(stream->hide_cpu_filter))
ret &= kshark_export_filter_array(stream->hide_cpu_filter,
KS_HIDE_CPU_FILTER_NAME,
*conf);
return ret;
}
/**
* @brief Load from a Configuration document the configuration of "show event"
* and "hide event" filters.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a filter has been loaded. If the filter configuration
* document contains no data for any event filter or in a case
* of an error, the function returns False.
*/
bool kshark_import_all_event_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc *conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
bool ret = false;
if (!stream)
return false;
ret |= kshark_import_event_filter(stream,
KS_HIDE_EVENT_FILTER,
KS_HIDE_EVENT_FILTER_NAME,
conf);
ret |= kshark_import_event_filter(stream,
KS_SHOW_EVENT_FILTER,
KS_SHOW_EVENT_FILTER_NAME,
conf);
return ret;
}
/**
* @brief Load from Configuration document the configuration of "show task"
* and "hide task" filters.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a filter has been loaded. If the filter configuration
* document contains no data for any task filter or in a case of an
* error, the function returns False.
*/
bool kshark_import_all_task_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc *conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
bool ret = false;
if (!stream)
return false;
ret |= kshark_import_filter_array(stream->hide_task_filter,
KS_HIDE_TASK_FILTER_NAME,
conf);
ret |= kshark_import_filter_array(stream->show_task_filter,
KS_SHOW_TASK_FILTER_NAME,
conf);
return ret;
}
/**
* @brief Load from Configuration document the configuration of "show cpu"
* and "hide cpu" filters.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a filter has been loaded. If the filter configuration
* document contains no data for any cpu filter or in a case of an
* error, the function returns False.
*/
bool kshark_import_all_cpu_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc *conf)
{
struct kshark_data_stream *stream =
kshark_get_data_stream(kshark_ctx, sd);
bool ret = false;
if (!stream)
return false;
ret |= kshark_import_filter_array(stream->hide_cpu_filter,
KS_HIDE_CPU_FILTER_NAME,
conf);
ret |= kshark_import_filter_array(stream->show_cpu_filter,
KS_SHOW_CPU_FILTER_NAME,
conf);
return ret;
}
/**
* @brief Create a Filter Configuration document containing the current
* configuration of all filters.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param format: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_export_all_filters(struct kshark_context *kshark_ctx, int sd,
enum kshark_config_formats format)
{
/* Create a new Configuration document. */
struct kshark_config_doc *conf =
kshark_filter_config_new(format);
/* Save a filter only if it contains Id values. */
if (!conf ||
!kshark_export_all_event_filters(kshark_ctx, sd, &conf) ||
!kshark_export_all_task_filters(kshark_ctx, sd, &conf) ||
!kshark_export_all_cpu_filters(kshark_ctx, sd, &conf) ||
!kshark_export_user_mask(kshark_ctx, &conf) ||
!kshark_export_adv_filters(kshark_ctx, sd, &conf)) {
kshark_free_config_doc(conf);
return NULL;
}
return conf;
}
/**
* @brief Load from a Configuration document the configuration of all filters.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True, if a filter has been loaded. If the filter configuration
* document contains no data for any filter or in a case of an error,
* the function returns False.
*/
bool kshark_import_all_filters(struct kshark_context *kshark_ctx, int sd,
struct kshark_config_doc *conf)
{
bool ret;
ret = kshark_import_all_task_filters(kshark_ctx, sd, conf);
ret |= kshark_import_all_cpu_filters(kshark_ctx, sd, conf);
ret |= kshark_import_all_event_filters(kshark_ctx, sd, conf);
ret |= kshark_import_user_mask(kshark_ctx, conf);
ret |= kshark_import_adv_filters(kshark_ctx, sd, conf);
return ret;
}
/**
* @brief Create a Data Stream Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param sd: Data stream identifier.
* @param format: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns kshark_config_doc instance on success, otherwise NULL. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *
kshark_export_dstream(struct kshark_context *kshark_ctx, int sd,
enum kshark_config_formats format)
{
struct kshark_config_doc *file_conf, *filter_conf, *sd_conf, *plg_conf;
struct kshark_config_doc *dstream_conf;
struct kshark_data_stream *stream;
stream = kshark_get_data_stream(kshark_ctx, sd);
if (!stream)
return NULL;
/* Create new Configuration documents. */
dstream_conf = kshark_stream_config_new(format);
sd_conf = kshark_config_alloc(KS_CONFIG_JSON);
sd_conf->conf_doc = json_object_new_int(sd);
filter_conf = kshark_export_all_filters(kshark_ctx, sd, format);
if (kshark_is_tep(stream) && kshark_tep_is_top_stream(stream))
file_conf = kshark_export_trace_file(stream->file,
TOP_BUFF_NAME,
format);
else
file_conf = kshark_export_trace_file(stream->file,
stream->name,
format);
plg_conf = kshark_export_stream_plugins(stream, format);
if (!dstream_conf ||
!sd_conf ||
!filter_conf ||
!file_conf ||
!plg_conf)
goto fail;
kshark_config_doc_add(dstream_conf, "stream id", sd_conf);
kshark_config_doc_add(dstream_conf, "data", file_conf);
kshark_config_doc_add(dstream_conf, "filters", filter_conf);
kshark_config_doc_add(dstream_conf, "plugins", plg_conf);
if (stream->calib_array_size)
kshark_export_calib_array(kshark_ctx, sd, &dstream_conf);
return dstream_conf;
fail:
kshark_free_config_doc(dstream_conf);
kshark_free_config_doc(filter_conf);
kshark_free_config_doc(file_conf);
kshark_free_config_doc(plg_conf);
kshark_free_config_doc(sd_conf);
return NULL;
}
/**
* @brief Load Data Stream from a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns The Stream Id on the loaded Data Stream on success, otherwise a
* negative error code.
*/
int kshark_import_dstream(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf)
{
struct kshark_config_doc *file_conf, *filter_conf, *plg_conf;
struct kshark_data_stream *stream;
bool ret = false;
int sd = -EFAULT;
if (!kshark_type_check(conf, "kshark.config.stream"))
return sd;
file_conf = kshark_config_alloc(KS_CONFIG_JSON);
filter_conf = kshark_config_alloc(KS_CONFIG_JSON);
plg_conf = kshark_config_alloc(KS_CONFIG_JSON);
if (!file_conf || !filter_conf || !plg_conf) {
fprintf(stderr,
"Failed to allocate memory for Json document.\n");
goto free;
}
if (kshark_config_doc_get(conf, "data", file_conf) &&
kshark_config_doc_get(conf, "filters", filter_conf) &&
kshark_config_doc_get(conf, "plugins", plg_conf)) {
sd = kshark_import_trace_file(kshark_ctx, file_conf);
if (sd < 0) {
fprintf(stderr,
"Failed to import data file form Json document.\n");
goto free;
}
stream = kshark_ctx->stream[sd];
kshark_import_calib_array(kshark_ctx, sd, conf);
ret = kshark_import_all_filters(kshark_ctx, sd,
filter_conf);
if (!ret) {
fprintf(stderr,
"Failed to import filters form Json document.\n");
kshark_close(kshark_ctx, sd);
sd = -EFAULT;
goto free;
}
ret = kshark_import_stream_plugins(kshark_ctx, stream, plg_conf);
if (!ret) {
fprintf(stderr,
"Failed to import stream plugins form Json document.\n");
kshark_close(kshark_ctx, sd);
sd = -EFAULT;
goto free;
}
}
free:
/* Free only the kshark_config_doc objects. */
free(file_conf);
free(filter_conf);
free(plg_conf);
return sd;
}
static bool
kshark_export_all_dstreams_to_json(struct kshark_context *kshark_ctx,
struct json_object *jobj)
{
int *stream_ids = kshark_all_streams(kshark_ctx);
struct kshark_config_doc *dstream_conf;
struct json_object *jall_streams;
json_del_if_exist(jobj, KS_DSTREAMS_NAME);
jall_streams = json_object_new_array();
for (int i = 0; i < kshark_ctx->n_streams; ++i) {
dstream_conf = kshark_export_dstream(kshark_ctx, stream_ids[i],
KS_CONFIG_JSON);
if (!dstream_conf)
goto fail;
json_object_array_put_idx(jall_streams, i, dstream_conf->conf_doc);
/* Free only the kshark_config_doc object. */
free(dstream_conf);
}
free(stream_ids);
json_object_object_add(jobj, KS_DSTREAMS_NAME, jall_streams);
return true;
fail:
json_object_put(jall_streams);
free(stream_ids);
return false;
}
/**
* @brief Record the current configuration for all Data Streams into a Json
* document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported. If NULL, a new Configuration
* document will be created.
*
* @returns True on success, otherwise False.
*/
bool kshark_export_all_dstreams(struct kshark_context *kshark_ctx,
struct kshark_config_doc **conf)
{
if (!*conf)
*conf = kshark_session_config_new(KS_CONFIG_JSON);
if (!*conf)
return false;
switch ((*conf)->format) {
case KS_CONFIG_JSON:
return kshark_export_all_dstreams_to_json(kshark_ctx,
(*conf)->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
(*conf)->format);
return false;
}
}
static ssize_t
kshark_import_all_dstreams_from_json(struct kshark_context *kshark_ctx,
struct json_object *jobj,
struct kshark_entry ***data_rows)
{
struct kshark_config_doc dstream_conf;
json_object *jall_streams, *jstream;
int sd, i, length;
if (!json_object_object_get_ex(jobj, KS_DSTREAMS_NAME, &jall_streams) ||
json_object_get_type(jall_streams) != json_type_array)
return -EFAULT;
length = json_object_array_length(jall_streams);
if (!length)
return -EFAULT;
dstream_conf.format = KS_CONFIG_JSON;
for (i = 0; i < length; ++i) {
jstream = json_object_array_get_idx(jall_streams, i);
dstream_conf.conf_doc = jstream;
sd = kshark_import_dstream(kshark_ctx, &dstream_conf);
if (sd < 0)
return -EFAULT;
}
return kshark_load_all_entries(kshark_ctx, data_rows);
}
/**
* @brief Load all Data Streams from a Configuration document.
*
* @param kshark_ctx: Input location for session context pointer.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
* @param data_rows: Output location for the trace data. The user is
* responsible for freeing the elements of the outputted
* array.
*
* @returns The size of the outputted data in the case of success, or a
* negative error code on failure.
*/
ssize_t kshark_import_all_dstreams(struct kshark_context *kshark_ctx,
struct kshark_config_doc *conf,
struct kshark_entry ***data_rows)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_import_all_dstreams_from_json(kshark_ctx,
conf->conf_doc,
data_rows);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return -EFAULT;
}
}
static bool kshark_save_json_file(const char *file_name,
struct json_object *jobj)
{
int flags;
/* Save the file in a human-readable form. */
flags = JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY;
if (json_object_to_file_ext(file_name, jobj, flags) == 0)
return true;
return false;
}
/**
* @brief Save a Configuration document into a file.
*
* @param file_name: The name of the file.
* @param conf: Input location for the kshark_config_doc instance. Currently
* only Json format is supported.
*
* @returns True on success, otherwise False.
*/
bool kshark_save_config_file(const char *file_name,
struct kshark_config_doc *conf)
{
switch (conf->format) {
case KS_CONFIG_JSON:
return kshark_save_json_file(file_name, conf->conf_doc);
default:
fprintf(stderr, "Document format %d not supported\n",
conf->format);
return false;
}
}
static struct json_object *kshark_open_json_file(const char *file_name,
const char *type)
{
struct json_object *jobj, *var;
const char *type_var;
jobj = json_object_from_file(file_name);
if (!jobj)
return NULL;
/* Get the type of the document. */
if (!json_object_object_get_ex(jobj, "type", &var))
goto fail;
type_var = json_object_get_string(var);
if (strcmp(type, type_var) != 0)
goto fail;
return jobj;
fail:
/* The document has a wrong type. */
fprintf(stderr, "Failed to open Json file %s.\n", file_name);
fprintf(stderr, "The document has a wrong type.\n");
json_object_put(jobj);
return NULL;
}
static const char *get_ext(const char *filename)
{
const char *dot = strrchr(filename, '.');
if(!dot)
return "unknown";
return dot + 1;
}
/**
* @brief Open for read a Configuration file and check if it has the
* expected type.
*
* @param file_name: The name of the file. Currently only Json files are
* supported.
* @param type: String describing the expected type of the document,
* e.g. "kshark.config.record" or "kshark.config.filter".
*
* @returns kshark_config_doc instance on success, or NULL on failure. Use
* kshark_free_config_doc() to free the object.
*/
struct kshark_config_doc *kshark_open_config_file(const char *file_name,
const char *type)
{
struct kshark_config_doc *conf = NULL;
if (strcmp(get_ext(file_name), "json") == 0) {
struct json_object *jobj =
kshark_open_json_file(file_name, type);
if (jobj) {
conf = malloc(sizeof(*conf));
conf->conf_doc = jobj;
conf->format = KS_CONFIG_JSON;
}
}
return conf;
}