Compare commits
18 Commits
29b2322284
...
6fb8bfefc6
Author | SHA1 | Date |
---|---|---|
|
6fb8bfefc6 | |
|
90acb142df | |
|
cd5fee4165 | |
|
58cc51d80a | |
|
0b85b65739 | |
|
336f3abb94 | |
|
758af7bf49 | |
|
2364c82e2d | |
|
f858647ad1 | |
|
add6bd5fc8 | |
|
632d423764 | |
|
1b5e488b45 | |
|
88ce871058 | |
|
8543903d87 | |
|
88171d0d6e | |
|
57bc0cec52 | |
|
b7d7350bd3 | |
|
877841db24 |
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef RVPROF_H
|
||||||
|
#define RVPROF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not called by instrumented code directly anymore
|
||||||
|
void rvprof_init(const char* output_file);
|
||||||
|
|
||||||
|
// not called by instrumented code directly anymore
|
||||||
|
void rvprof_set_program_name(const char* name);
|
||||||
|
|
||||||
|
// begin profiling a named region
|
||||||
|
void rvprof_region_begin(const char* name);
|
||||||
|
|
||||||
|
// end profiling of a named region
|
||||||
|
void rvprof_region_end(const char* name);
|
||||||
|
|
||||||
|
// not called by instrumented code direclty anymore
|
||||||
|
void rvprof_finalize(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include "rvprof_internal.h"
|
||||||
|
|
||||||
|
static void rvprof_atexit_handler(void){
|
||||||
|
if(g_rvprof.initialized) rvprof_context_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_atexit_handler(void){
|
||||||
|
static int registered = 0;
|
||||||
|
if (!registered){
|
||||||
|
atexit(rvprof_atexit_handler);
|
||||||
|
registered = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rvprof_init(const char* output_file){
|
||||||
|
if (g_rvprof.initialized) return;
|
||||||
|
|
||||||
|
// enable usage of cygnus hooks, disable with RVPROF_DISABLE_HOOKS env variable
|
||||||
|
g_rvprof.config.enable_hooks = 1;
|
||||||
|
// merge regions of same names in output, disable with RVPROF_DISABLE_MERGE env variable
|
||||||
|
g_rvprof.config.merge_regions =1;
|
||||||
|
// set output file name, auto-detected, override with RVPROF_OUTPUT env variable
|
||||||
|
g_rvprof.config.output_filename = NULL;
|
||||||
|
// set program name, auto-detected
|
||||||
|
g_rvprof.config.program_name = NULL;
|
||||||
|
|
||||||
|
char* disable_hooks = getenv("RVPROF_DISABLE_HOOKS");
|
||||||
|
if (disable_hooks && strcmp(disable_hooks, "1") == 0){
|
||||||
|
g_rvprof.config.enable_hooks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* disable_merge = getenv("RVPROF_DISABLE_MERGE");
|
||||||
|
if (disable_merge && strcmp(disable_merge, "1") == 0){
|
||||||
|
g_rvprof.config.merge_regions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* env_output = getenv("RVPROF_OUTPUT");
|
||||||
|
const char* filename;
|
||||||
|
|
||||||
|
// determine output filename
|
||||||
|
if (output_file && strlen(output_file) > 0){
|
||||||
|
filename = output_file;
|
||||||
|
} else if (env_output && strlen(env_output) > 0){
|
||||||
|
filename = env_output;
|
||||||
|
} else {
|
||||||
|
filename = rvprof_utils_generate_output_filename();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_rvprof.output_file = fopen(filename, "w");
|
||||||
|
if(!g_rvprof.output_file) return;
|
||||||
|
|
||||||
|
rvprof_error_t timing_result = rvprof_timing_init();
|
||||||
|
if (timing_result != RVPROF_SUCCESS) return;
|
||||||
|
|
||||||
|
rvprof_symbols_init(g_rvprof.config.program_name); // in case symbol resolution fails, just addresses are printed later
|
||||||
|
|
||||||
|
|
||||||
|
// rest of global state
|
||||||
|
g_rvprof.stack_ptr = -1;
|
||||||
|
g_rvprof.initialized = 1;
|
||||||
|
g_rvprof.auto_initialized = 0;
|
||||||
|
g_rvprof.total_program_time = 0;
|
||||||
|
g_rvprof.total_program_cycles = 0;
|
||||||
|
g_rvprof.total_memory_allocated = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// initialize dynamic arrays with zeros
|
||||||
|
memset(&g_rvprof.regions, 0, sizeof(g_rvprof.regions));
|
||||||
|
memset(&g_rvprof.functions, 0, sizeof(g_rvprof.functions));
|
||||||
|
memset(&g_rvprof.stacks,0,sizeof(g_rvprof.stacks));
|
||||||
|
|
||||||
|
// register atexit handler to automate cleanup
|
||||||
|
register_atexit_handler();
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
#ifndef RVPROF_INTERNAL_H
|
||||||
|
#define RVPROF_INTERNAL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// constants
|
||||||
|
#define INITIAL_FUNCTIONS 128
|
||||||
|
#define INITIAL_STACKS 256
|
||||||
|
#define INITIAL_REGIONS 128
|
||||||
|
#define INITIAL_SYMBOLS 512
|
||||||
|
#define GROWTH_FACTOR 2
|
||||||
|
#define MAX_NAME_LEN 64
|
||||||
|
|
||||||
|
|
||||||
|
// error enum
|
||||||
|
typedef enum {
|
||||||
|
RVPROF_SUCCESS = 0,
|
||||||
|
RVPROF_ERROR_MEMORY = -1,
|
||||||
|
RVPROF_ERROR_IO = -2,
|
||||||
|
RVPROF_ERROR_SYMBOLS = -3,
|
||||||
|
RVPROF_ERROR_INVALID_STATE = -4,
|
||||||
|
RVPROF_ERROR_STACK_OVERFLOW = -5,
|
||||||
|
RVPROF_ERROR_STACK_UNDERFLOW = -6
|
||||||
|
} rvprof_error_t;
|
||||||
|
|
||||||
|
// symbol table entry
|
||||||
|
typedef struct{
|
||||||
|
uintptr_t addr;
|
||||||
|
char name[MAX_NAME_LEN];
|
||||||
|
size_t size;
|
||||||
|
} symbol_entry_t;
|
||||||
|
|
||||||
|
// region stack entry
|
||||||
|
typedef struct {
|
||||||
|
char name[MAX_NAME_LEN];
|
||||||
|
uint64_t start_cycles;
|
||||||
|
uint64_t start_time_ns;
|
||||||
|
int depth;
|
||||||
|
int function_id;
|
||||||
|
int stack_id;
|
||||||
|
uint64_t child_time;
|
||||||
|
uint64_t child_cycles;
|
||||||
|
void* func_addr;
|
||||||
|
} region_t;
|
||||||
|
|
||||||
|
// function stats
|
||||||
|
typedef struct {
|
||||||
|
char name [MAX_NAME_LEN];
|
||||||
|
char caller [MAX_NAME_LEN];
|
||||||
|
uint64_t total_inclusive_time;
|
||||||
|
uint64_t total_exclusive_time;
|
||||||
|
uint64_t total_inclusive_cycles;
|
||||||
|
uint64_t total_exclusive_cycles;
|
||||||
|
uint64_t call_count;
|
||||||
|
int* stack_ids;
|
||||||
|
int num_stack_ids;
|
||||||
|
int max_stack_ids;
|
||||||
|
char** callers;
|
||||||
|
int num_callers;
|
||||||
|
int max_callers;
|
||||||
|
double exclusive_percent;
|
||||||
|
double inclusive_percent;
|
||||||
|
} function_stats_t;
|
||||||
|
|
||||||
|
// stack info
|
||||||
|
typedef struct {
|
||||||
|
char* stack_path;
|
||||||
|
int stid;
|
||||||
|
} stack_info_t;
|
||||||
|
|
||||||
|
// dynamic array structure (could switch to a more sophisticated container + template if we would move to C++ at some point)
|
||||||
|
#define DECLARE_DYNAMIC_ARRAY(type, name) \
|
||||||
|
typedef struct { \
|
||||||
|
type* data; \
|
||||||
|
int size; \
|
||||||
|
int capacity; \
|
||||||
|
} name##_array_t;
|
||||||
|
|
||||||
|
DECLARE_DYNAMIC_ARRAY(region_t, region);
|
||||||
|
DECLARE_DYNAMIC_ARRAY(function_stats_t, function_stats);
|
||||||
|
DECLARE_DYNAMIC_ARRAY(symbol_entry_t, symbol);
|
||||||
|
DECLARE_DYNAMIC_ARRAY(stack_info_t, stack_info);
|
||||||
|
|
||||||
|
// config structure
|
||||||
|
typedef struct {
|
||||||
|
int enable_hooks;
|
||||||
|
int merge_regions;
|
||||||
|
char* output_filename;
|
||||||
|
char* program_name;
|
||||||
|
} rvprof_config_t;
|
||||||
|
|
||||||
|
// global context
|
||||||
|
typedef struct{
|
||||||
|
rvprof_config_t config;
|
||||||
|
|
||||||
|
// cycle counter info
|
||||||
|
int use_cycles;
|
||||||
|
int cycles_avaiable;
|
||||||
|
|
||||||
|
// dynamic arrays
|
||||||
|
region_array_t regions;
|
||||||
|
function_stats_array_t functions;
|
||||||
|
stack_info_array_t stacks;
|
||||||
|
symbol_array_t symbols;
|
||||||
|
|
||||||
|
// state
|
||||||
|
int initialized;
|
||||||
|
int auto_initialized;
|
||||||
|
int symbols_loaded;
|
||||||
|
int stack_ptr;
|
||||||
|
FILE* output_file;
|
||||||
|
|
||||||
|
// statistics
|
||||||
|
uint64_t total_program_time;
|
||||||
|
uint64_t total_program_cycles;
|
||||||
|
size_t total_memory_allocated;
|
||||||
|
} rvprof_context_t;
|
||||||
|
|
||||||
|
|
||||||
|
// ONLY GLOBAL VARIABLE
|
||||||
|
extern rvprof_context_t g_rvprof;
|
||||||
|
|
||||||
|
|
||||||
|
// internal API
|
||||||
|
|
||||||
|
// memory management
|
||||||
|
void* rvprof_malloc(size_t size);
|
||||||
|
void* rvprof_reallovc(void* ptr, size_t old_size, size_t new_size);
|
||||||
|
void rvprof_free(void* ptr, size_t size);
|
||||||
|
|
||||||
|
// dynamic array management
|
||||||
|
int region_array_ensure_capacity(region_array_t* arr, int needed);
|
||||||
|
int function_stats_array_ensure_capacity(function_stats_array_t* arr, int needed);
|
||||||
|
int stack_info_array_ensure_capacity(stack_info_array_t* arr, int needed);
|
||||||
|
int symbol_array_ensure_capacity(symbol_array_t* arr, int needed);
|
||||||
|
|
||||||
|
void region_array_cleanup(region_array_t* arr);
|
||||||
|
void function_stats_array_cleanup(function_stats_array_t* arr);
|
||||||
|
void stack_info_array_cleanup(stack_info_array_t* arr);
|
||||||
|
void symbol_array_cleanup(symbol_array_t* arr);
|
||||||
|
|
||||||
|
// memory operations: fyunction statistics
|
||||||
|
int rvprof_memory_add_stack_id_to_function(int func_id, int stack_id);
|
||||||
|
int rvprof_memory_add_caller_to_function(int func_id, const char* caller);
|
||||||
|
|
||||||
|
// timing
|
||||||
|
rvprof_error_t rvprof_timing_init(void);
|
||||||
|
uint64_t rvprof_timing_get_current(void);
|
||||||
|
uint64_t rvprof_timing_get_cycles(void);
|
||||||
|
double rvprof_timing_to_seconds(uint64_t nanoseconds);
|
||||||
|
int rvprof_timing_test_cycle_counter(void);
|
||||||
|
|
||||||
|
// symbol resolution
|
||||||
|
rvprof_error_t rvprof_symbols_init(const char* program_path);
|
||||||
|
const char* rvprof_symbols_lookup(void* addr);
|
||||||
|
void rvprof_symbols_cleanup(void);
|
||||||
|
|
||||||
|
// function statistics management
|
||||||
|
int rvprof_stats_find_or_create_function(const char* name, const char* caller);
|
||||||
|
int rvprof_stats_get_or_create_stack_id(void);
|
||||||
|
void rvprof_stats_add_stack_id_to_function(int func_id, int stid);
|
||||||
|
void rvprof_stats_add_caller_to_function(int func_id, const char* caller);
|
||||||
|
|
||||||
|
// output
|
||||||
|
rvprof_error_t rvprof_output_generate_report(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue