1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Remotery is a realtime CPU/GPU profiler with a viewer that runs in a web browser.
//! This lib is a [Rust](https://www.rust-lang.org) wrapper around the C API provided by Remotery and the original
//! repo over here https://github.com/Celtoys/Remotery
//!
pub mod error;
mod remotery_ffi;
mod cfixed_string;
use std::ptr;
use std::os::raw::c_void;
use error::RemoteryError;
use cfixed_string::CFixedString;

/// Holds the main instance for Remotery
pub struct Remotery {
    instance: *mut c_void,
}

#[derive(Clone, Copy)]
/// Sample flags to decide how profiling info should be handled
pub enum SampleFlags {
    /// Default behaviour
	Default,
    /// Search parent for same-named samples and merge timing instead of adding a new sample
	Aggregate,
}

impl Remotery {
	/// Creates the global instance (with in the C lib that this code wraps) this code needs to be
	/// called before any of the other code is being called and the instance will be dropped when
	/// it goes out of scope so it's suggested to call this early in the main entry point of your
	/// program (such as ``main``)
	///
	/// # Examples
	///
	/// ```ignore
    /// let _remotery = Remotery::create_global_instance().unwrap_or_else(|e| {
    ///  	panic!(e);
	/// });
	/// ```
	///
    pub fn create_global_instance() -> Result<Remotery, RemoteryError> {
        let mut instance = 0 as *mut c_void;

        let res = unsafe {
            remotery_ffi::_rmt_CreateGlobalInstance(&mut instance)
        };

        if res != 0 {
            return Err(error::get_error(res));
        }

        Ok(Remotery { instance: instance })
    }

    ///
    /// Begin a cpu sample. Notice that this call needs to be paired with ``end_cpu_sample``.
    /// It's also possible to use ```RemoteryScope``` that will call end_cpu_scope when the scop ends.
    ///
	/// # Examples
	/// ```ignore
    /// Remotery::begin_cpu_sample("my_function", SampleFlags::Default);
    /// // some code to profile here
    /// Remotery::end_cpu_sample();
    /// ```
    ///
    pub fn begin_cpu_sample(name: &str, flags: SampleFlags) {
        // TODO: As we send 0 as last parameter which is hash caching this will always recalculate
        // the hash which adds some slight overhead. Would be nice if that could be solved somehow.
        unsafe {
            let temp_str = CFixedString::from_str(name);
            remotery_ffi::_rmt_BeginCPUSample(temp_str.as_ptr(), flags as u32, ptr::null_mut());
        }
    }

    /// Ends a cpu sample. Notice that this needs to be paired with ``begin_cpu_sample`` as seen above.
    pub fn end_cpu_sample() {
        unsafe {
            remotery_ffi::_rmt_EndCPUSample();
        }
    }

    /// Setts the name of the current thread that makes it easier to identify it in the Remotery UI
    ///
    /// # Examples
    ///
    /// ```ignore
    /// Remotery::set_current_thread_name("my_thread_name");
    /// ```
    ///
    pub fn set_current_thread_name(name: &str) {
        unsafe {
            let temp_str = CFixedString::from_str(name);
            remotery_ffi::_rmt_SetCurrentThreadName(temp_str.as_ptr());
        }
    }

    ///
    /// Can be used to log text to the remotery ui
    ///
    pub fn log_text(text: &str) {
        unsafe {
            let temp_str = CFixedString::from_str(text);
            remotery_ffi::_rmt_LogText(temp_str.as_ptr());
        }
    }
}

/// Scopes allows you to profile a bit of code and the end_cpu_sample will be called once it goes out of scope
pub struct RemoteryScope;

impl RemoteryScope {
	///
	/// Begin a new Scope which auto calls ``end_cpu_scope`` once the scope ends
	///
    /// # Examples
    ///
    /// ```ignore
    /// let _scope = RemoteryScope::new("my_function", SampleFlags::Default);
    /// ```
    pub fn new(name: &str, flags: SampleFlags) -> RemoteryScope {
        Remotery::begin_cpu_sample(name, flags);
        RemoteryScope {}
    }
}

impl Drop for RemoteryScope {
    fn drop(&mut self) {
        Remotery::end_cpu_sample()
    }
}

impl Drop for Remotery {
    fn drop(&mut self) {
        if self.instance == ptr::null_mut() {
            return
        }

        unsafe {
            remotery_ffi::_rmt_DestroyGlobalInstance(self.instance);
        }
    }
}