// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include "osnoise.h"
#include "utils.h"
/*
* osnoise_get_cpus - return the original "osnoise/cpus" content
*
* It also saves the value to be restored.
*/
char *osnoise_get_cpus(struct osnoise_context *context)
{
if (context->curr_cpus)
return context->curr_cpus;
if (context->orig_cpus)
return context->orig_cpus;
context->orig_cpus = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL);
/*
* The error value (NULL) is the same for tracefs_instance_file_read()
* and this functions, so:
*/
return context->orig_cpus;
}
/*
* osnoise_set_cpus - configure osnoise to run on *cpus
*
* "osnoise/cpus" file is used to set the cpus in which osnoise/timerlat
* will run. This function opens this file, saves the current value,
* and set the cpus passed as argument.
*/
int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
{
char *orig_cpus = osnoise_get_cpus(context);
char buffer[1024];
int retval;
if (!orig_cpus)
return -1;
context->curr_cpus = strdup(cpus);
if (!context->curr_cpus)
return -1;
snprintf(buffer, 1024, "%s\n", cpus);
debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus);
retval = tracefs_instance_file_write(NULL, "osnoise/cpus", buffer);
if (retval < 0) {
free(context->curr_cpus);
context->curr_cpus = NULL;
return -1;
}
return 0;
}
/*
* osnoise_restore_cpus - restore the original "osnoise/cpus"
*
* osnoise_set_cpus() saves the original data for the "osnoise/cpus"
* file. This function restore the original config it was previously
* modified.
*/
void osnoise_restore_cpus(struct osnoise_context *context)
{
int retval;
if (!context->orig_cpus)
return;
if (!context->curr_cpus)
return;
/* nothing to do? */
if (!strcmp(context->orig_cpus, context->curr_cpus))
goto out_done;
debug_msg("restoring cpus to %s", context->orig_cpus);
retval = tracefs_instance_file_write(NULL, "osnoise/cpus", context->orig_cpus);
if (retval < 0)
err_msg("could not restore original osnoise cpus\n");
out_done:
free(context->curr_cpus);
context->curr_cpus = NULL;
}
/*
* osnoise_put_cpus - restore cpus config and cleanup data
*/
void osnoise_put_cpus(struct osnoise_context *context)
{
osnoise_restore_cpus(context);
if (!context->orig_cpus)
return;
free(context->orig_cpus);
context->orig_cpus = NULL;
}
/*
* osnoise_read_ll_config - read a long long value from a config
*
* returns -1 on error.
*/
static long long osnoise_read_ll_config(char *rel_path)
{
long long retval;
char *buffer;
buffer = tracefs_instance_file_read(NULL, rel_path, NULL);
if (!buffer)
return -1;
/* get_llong_from_str returns -1 on error */
retval = get_llong_from_str(buffer);
debug_msg("reading %s returned %lld\n", rel_path, retval);
free(buffer);
return retval;
}
/*
* osnoise_write_ll_config - write a long long value to a config in rel_path
*
* returns -1 on error.
*/
static long long osnoise_write_ll_config(char *rel_path, long long value)
{
char buffer[BUFF_U64_STR_SIZE];
long long retval;
snprintf(buffer, sizeof(buffer), "%lld\n", value);
debug_msg("setting %s to %lld\n", rel_path, value);
retval = tracefs_instance_file_write(NULL, rel_path, buffer);
return retval;
}
/*
* osnoise_get_runtime - return the original "osnoise/runtime_us" value
*
* It also saves the value to be restored.
*/
unsigned long long osnoise_get_runtime(struct osnoise_context *context)
{
long long runtime_us;
if (context->runtime_us != OSNOISE_TIME_INIT_VAL)
return context->runtime_us;
if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
return context->orig_runtime_us;
runtime_us = osnoise_read_ll_config("osnoise/runtime_us");
if (runtime_us < 0)
goto out_err;
context->orig_runtime_us