mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
[kernel] Add RAII profiler object
Added profiler.h which defines classes and macros for defining profiler objects. Also added gdb command j6prof for printing profile data. Added the syscall_profiles profiler class and auto wrapping of syscalls with profile objects. Other changes in this commit: - Made the gdb command `j6threads` argument for specifying a CPU optional. Without an argument, it loops through all CPUs. - Switched to -mcmodel=kernel for kernel code, which makes `call` instructions easier to follow when debugging / looking at disassembly.
This commit is contained in:
50
src/kernel/profiler.h
Normal file
50
src/kernel/profiler.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
/// \file profiler.h
|
||||
/// The kernel profiling interface
|
||||
|
||||
#include <stdint.h>
|
||||
#include <util/hash.h>
|
||||
|
||||
inline uint64_t rdtsc() {
|
||||
uint32_t high, low;
|
||||
asm ( "rdtsc" : "=a" (low), "=d" (high) );
|
||||
return (static_cast<uint64_t>(high) << 32) | low;
|
||||
}
|
||||
|
||||
template<typename PC, size_t ID>
|
||||
class profiler
|
||||
{
|
||||
using class_t = PC;
|
||||
static constexpr size_t id = ID;
|
||||
|
||||
public:
|
||||
profiler(char const * const function = __builtin_FUNCTION()) : m_start(rdtsc()) {
|
||||
static_assert(id < class_t::count, "profiler out of bounds");
|
||||
class_t::call_counts[id]++;
|
||||
class_t::function_names[id] = function;
|
||||
}
|
||||
|
||||
~profiler() {
|
||||
uint64_t stop = rdtsc();
|
||||
class_t::call_durations[id] += (stop - m_start);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t m_start;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct profile_class
|
||||
{
|
||||
static volatile char const * function_names[];
|
||||
static volatile uint64_t call_counts[];
|
||||
static volatile uint64_t call_durations[];
|
||||
};
|
||||
|
||||
#define DECLARE_PROFILE_CLASS(name, size) \
|
||||
struct name : public profile_class<name> { static constexpr size_t count = size; };
|
||||
|
||||
#define DEFINE_PROFILE_CLASS(name) \
|
||||
template<> volatile char const * profile_class<name>::function_names[name::count] = {0}; \
|
||||
template<> volatile uint64_t profile_class<name>::call_counts[name::count] = {0}; \
|
||||
template<> volatile uint64_t profile_class<name>::call_durations[name::count] = {0};
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <j6/types.h>
|
||||
#include <util/counted.h>
|
||||
|
||||
#include "profiler.h"
|
||||
#include "syscalls/helpers.h"
|
||||
|
||||
/*[[[cog code generation
|
||||
@@ -21,6 +22,12 @@ for obj in syscalls.exposes:
|
||||
]]]*/
|
||||
//[[[end]]]
|
||||
|
||||
|
||||
/*[[[cog code generation
|
||||
cog.outl(f'constexpr size_t syscall_count = {len(syscalls.methods)};')
|
||||
]]]*/
|
||||
//[[[end]]]
|
||||
DECLARE_PROFILE_CLASS(syscall_profiles, syscall_count);
|
||||
namespace {
|
||||
enum class req { required, optional, zero_ok };
|
||||
|
||||
@@ -61,6 +68,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_PROFILE_CLASS(syscall_profiles);
|
||||
|
||||
namespace syscalls {
|
||||
|
||||
using util::buffer;
|
||||
@@ -185,6 +194,7 @@ for id, scope, method in syscalls.methods:
|
||||
if "noreturn" in method.options:
|
||||
cog.outl(f""" {name}({", ".join(args)});""")
|
||||
else:
|
||||
cog.outl(f""" profiler<syscall_profiles, {id}> profile {{"{name}"}};""")
|
||||
cog.outl(f""" return {name}({", ".join(args)});""")
|
||||
cog.outl("}")
|
||||
cog.outl("\n")
|
||||
|
||||
Reference in New Issue
Block a user