Skip to content

A lightweight, high-performance profiling library for C applications with minimal overhead. Designed for measuring execution time of code blocks and functions with nanosecond precision using POSIX timers. A lightweight profiling and timing library for C applications. Stack: C, POSIX timers, clock_gettime.

License

Notifications You must be signed in to change notification settings

BaseMax/c-profiler

Repository files navigation

C Profiler

A lightweight, high-performance profiling library for C applications with minimal overhead. Designed for measuring execution time of code blocks and functions with nanosecond precision using POSIX timers.

Features

  • High-Resolution Timing: Uses POSIX clock_gettime with CLOCK_MONOTONIC for nanosecond precision
  • Scoped Timers: Automatic timer cleanup using GCC cleanup attribute
  • Aggregated Statistics: Collect min, max, average, and count across multiple measurements
  • Optional File Logging: Automatic or manual logging to files
  • Minimal Overhead: Efficient implementation with negligible performance impact
  • Easy Integration: Simple macros for drop-in profiling
  • Cross-Platform: Works on any POSIX-compliant system (Linux, macOS, BSD, etc.)

Quick Start

Building the Library

# Build static library and examples
make

# Build shared library
make shared

# Run all examples
make run

# Install to system (requires root)
sudo make install

Basic Usage

#include "profiler.h"

int main(void) {
    profiler_init();
    
    // Manual timer
    profiler_timer_t timer;
    profiler_timer_start(&timer, "my_operation");
    
    // Your code here
    
    profiler_timer_stop(&timer);
    profiler_print_timer(&timer);
    
    profiler_shutdown();
    return 0;
}

API Reference

Initialization and Configuration

void profiler_init(void);
void profiler_shutdown(void);
void profiler_enable(bool enable);
void profiler_set_log_file(const char *filename);
void profiler_close_log_file(void);

Timer Functions

void profiler_timer_start(profiler_timer_t *timer, const char *name);
void profiler_timer_stop(profiler_timer_t *timer);
uint64_t profiler_timer_elapsed_ns(const profiler_timer_t *timer);
double profiler_timer_elapsed_us(const profiler_timer_t *timer);
double profiler_timer_elapsed_ms(const profiler_timer_t *timer);
double profiler_timer_elapsed_s(const profiler_timer_t *timer);

Statistics Functions

void profiler_stats_init(profiler_stats_t *stats, const char *name);
void profiler_stats_add(profiler_stats_t *stats, uint64_t elapsed_ns);
void profiler_stats_print(const profiler_stats_t *stats);
void profiler_stats_log(const profiler_stats_t *stats, FILE *file);
void profiler_stats_reset(profiler_stats_t *stats);

Convenience Macros

PROFILER_SCOPE(name)           // Scoped timer (auto cleanup)
PROFILER_FUNCTION()            // Profile entire function
PROFILER_START(timer, name)    // Start manual timer
PROFILER_STOP(timer)           // Stop manual timer
PROFILER_BLOCK_START(name)     // Start profiled block
PROFILER_BLOCK_END(name)       // End profiled block

Usage Examples

Example 1: Scoped Timers

#include "profiler.h"

void my_function(void) {
    PROFILER_FUNCTION();  // Automatically profiles entire function
    
    // Function code
}

int main(void) {
    profiler_init();
    
    {
        PROFILER_SCOPE(database_query);
        // Code to profile
    }  // Timer automatically stops here
    
    my_function();
    
    profiler_shutdown();
    return 0;
}

Example 2: Statistics Collection

#include "profiler.h"

int main(void) {
    profiler_init();
    
    profiler_stats_t stats;
    profiler_stats_init(&stats, "operation");
    
    for (int i = 0; i < 100; i++) {
        profiler_timer_t timer;
        profiler_timer_start(&timer, "iteration");
        
        // Your code
        
        profiler_timer_stop(&timer);
        profiler_stats_add(&stats, profiler_timer_elapsed_ns(&timer));
    }
    
    profiler_stats_print(&stats);  // Shows min, max, avg, count
    
    profiler_shutdown();
    return 0;
}

Example 3: File Logging

#include "profiler.h"

int main(void) {
    profiler_init();
    
    // Enable automatic logging
    profiler_set_log_file("profiler.log");
    
    {
        PROFILER_SCOPE(operation);
        // Code automatically logged
    }
    
    profiler_shutdown();  // Closes log file
    return 0;
}

Example 4: Performance Comparison

#include "profiler.h"

void algorithm_a(void) {
    PROFILER_FUNCTION();
    // Implementation A
}

void algorithm_b(void) {
    PROFILER_FUNCTION();
    // Implementation B
}

int main(void) {
    profiler_init();
    
    algorithm_a();  // Prints: [PROFILER] algorithm_a: X.XXX ms
    algorithm_b();  // Prints: [PROFILER] algorithm_b: X.XXX ms
    
    profiler_shutdown();
    return 0;
}

Building and Testing

Build Options

# Build static library (default)
make static

# Build shared library
make shared

# Build all examples
make examples

# Build specific example
make example1_basic

# Clean build artifacts
make clean

# Clean everything including logs
make distclean

Running Examples

# Run individual examples
./example1_basic
./example2_scoped
./example3_stats
./example4_logging
./example5_comprehensive

# Run all examples
make run

Integration into Your Project

Option 1: Static Library

# Build the library
make static

# Compile your program
gcc -o myapp myapp.c libprofiler.a -lrt

Option 2: Shared Library

# Build the shared library
make shared

# Compile your program
gcc -o myapp myapp.c -L. -lprofiler -lrt

Option 3: Direct Inclusion

# Include profiler.c directly in your build
gcc -o myapp myapp.c profiler.c -lrt

Performance Overhead

The profiler is designed for minimal overhead:

  • Timer start/stop: ~50-100 nanoseconds (typical)
  • Statistics update: ~10-20 nanoseconds (typical)
  • Disabled profiler: near-zero overhead (checks single boolean flag)

You can disable profiling at runtime without recompiling:

profiler_enable(false);  // Disable profiling
// ... code runs without profiling
profiler_enable(true);   // Re-enable profiling

Platform Requirements

  • POSIX-compliant OS: Linux, macOS, BSD, Unix, etc.
  • C11 compiler: GCC 4.7+, Clang 3.1+, or compatible
  • librt: Required for clock_gettime on some platforms

Advanced Features

Custom Time Units

profiler_timer_t timer;
profiler_timer_start(&timer, "operation");
// ... code ...
profiler_timer_stop(&timer);

printf("Time: %lu ns\n", profiler_timer_elapsed_ns(&timer));
printf("Time: %.3f us\n", profiler_timer_elapsed_us(&timer));
printf("Time: %.3f ms\n", profiler_timer_elapsed_ms(&timer));
printf("Time: %.3f s\n", profiler_timer_elapsed_s(&timer));

Conditional Profiling

#ifdef ENABLE_PROFILING
    PROFILER_SCOPE(my_code);
#endif
    // Your code here

Nested Profiling

void outer_function(void) {
    PROFILER_FUNCTION();
    
    {
        PROFILER_SCOPE(inner_operation_1);
        // Code
    }
    
    {
        PROFILER_SCOPE(inner_operation_2);
        // Code
    }
}

Examples Provided

  1. example1_basic.c: Basic timer usage
  2. example2_scoped.c: Scoped timers and automatic cleanup
  3. example3_stats.c: Statistics collection and aggregation
  4. example4_logging.c: File logging functionality
  5. example5_comprehensive.c: Real-world performance analysis

License

MIT License - Copyright (c) 2025 Max Base

See LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Author

Max Base

Stack

  • C11
  • POSIX Timers (clock_gettime)
  • CLOCK_MONOTONIC for high-resolution timing

About

A lightweight, high-performance profiling library for C applications with minimal overhead. Designed for measuring execution time of code blocks and functions with nanosecond precision using POSIX timers. A lightweight profiling and timing library for C applications. Stack: C, POSIX timers, clock_gettime.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published