microprofile 0.2.1

microprofile is a small library for profiling and optimizing multithreaded programs.
Documentation
use std::ffi::CString;
use std::os::raw::c_char;
use std::os::raw::c_void;

#[link(name="microprofile")]
extern {
	fn MicroProfileInit();
	fn MicroProfileShutdown();
	pub fn MicroProfileGetToken(sGroup : *const c_char, sName : *const c_char, nColor : u32, TokenType : u32) -> u64;
	pub fn MicroProfileEnter(Token : u64);
	pub fn MicroProfileLeave();
	fn MicroProfileFlip(GpuContext : *const c_void);
	fn MicroProfileStartAutoFlip(nMs : u32);
	fn MicroProfileStopAutoFlip();
	fn MicroProfileDumpFile(pHtml : *const c_char, pCsv : *const c_char, fCpuSpike : f32, fGpuSpike : f32);
	fn MicroProfileDumpFileImmediately(pHtml : *const c_char, pCsv : *const c_char, pGpuContext : *const c_void);
	fn MicroProfileSetEnableAllGroups(enable : i32);
	fn MicroProfileOnThreadCreate(pThreadName: *const c_char);
	fn MicroProfileOnThreadExit();
	fn MicroProfileTick() -> u64;
	fn MicroProfileTicksPerSecondCpu() -> i64;


}

pub fn init()
{
	unsafe
	{
		MicroProfileInit();
	}
}

pub fn shutdown()
{
	unsafe
	{
		MicroProfileShutdown();
	}
}

pub fn flip()
{
	unsafe
	{
		MicroProfileFlip(std::ptr::null());
	}
}

pub fn start_auto_flip(ms : u32)
{
	unsafe
	{
		MicroProfileStartAutoFlip(ms);
	}
}

pub fn stop_auto_flip()
{
	unsafe
	{
		MicroProfileStopAutoFlip();
	}
}

pub fn get_token(group : String, name : String, color : u32) -> u64
{
	let group = CString::new(group).unwrap();
	let name = CString::new(name).unwrap();
	unsafe
	{
		MicroProfileGetToken(group.as_ptr(), name.as_ptr(), color, 0)
	}
}

pub fn enter(token:u64)
{
	unsafe
	{
		MicroProfileEnter(token);
	}
}

pub fn leave()
{
	unsafe
	{
		MicroProfileLeave();
	}
}

pub fn dump_file(html : String, csv : String, cpu_spike : f32, gpu_spike : f32)
{
	let html_len = html.len();
	let csv_len = csv.len();
	let html = CString::new(html).unwrap();
	let csv = CString::new(csv).unwrap();

	unsafe
	{
		let html_bytes = if html_len > 0 { html.as_ptr() } else { std::ptr::null() };
		let csv_bytes = if csv_len > 0 { csv.as_ptr() } else { std::ptr::null() };
		MicroProfileDumpFile(html_bytes, csv_bytes, cpu_spike, gpu_spike);
	}
}

pub fn dump_file_immediately(html : &str, csv : &str)
{
	let html_len = html.len();
	let csv_len = csv.len();
	let html = CString::new(html).unwrap();
	let csv = CString::new(csv).unwrap();

	unsafe
	{
		let html_bytes = if html_len > 0 { html.as_ptr() } else { std::ptr::null() };
		let csv_bytes = if csv_len > 0 { csv.as_ptr() } else { std::ptr::null() };
		MicroProfileDumpFileImmediately(html_bytes, csv_bytes, std::ptr::null());
	}
}

pub fn set_enable_all_groups(enable : bool)
{
	unsafe
	{
		let enable : i32 = if enable { 1 } else { 0 };
		MicroProfileSetEnableAllGroups(enable);
	}
}

pub fn on_thread_create(thread_name : &str)
{
	let thread_name = CString::new(thread_name).unwrap();
	unsafe
	{
		MicroProfileOnThreadCreate(thread_name.as_ptr());
	}
}

pub fn on_thread_exit()
{
	unsafe
	{
		MicroProfileOnThreadExit();
	}
}

pub fn tick() -> u64
{
	unsafe
	{
		MicroProfileTick()
	}	
}

pub fn ticks_per_second_cpu() -> u64
{
	unsafe
	{
		MicroProfileTicksPerSecondCpu() as u64
	}
}

pub fn ticks_to_seconds(ticks : u64) -> f32
{
	let per_second = ticks_per_second_cpu();
	let seconds : f32 = ticks as f32 / per_second as f32;
	seconds
}

pub struct MicroProfileDroppable
{
}

impl Drop for MicroProfileDroppable
{
	fn drop(&mut self)
	{
		unsafe
		{
			MicroProfileLeave();
		}
	}
}

#[cfg(not(feature = "disabled"))]
#[macro_export] 
macro_rules! scope {
	($group_name:expr, $scope_name:expr, $color:expr) => {
		{
			static mut TOKEN : u64 = 0;
			static INIT: std::sync::Once = std::sync::Once::new();
			unsafe{
				INIT.call_once(||{
					let group = std::ffi::CString::new($group_name).unwrap();
					let scope = std::ffi::CString::new($scope_name).unwrap();
					TOKEN = $crate::MicroProfileGetToken(group.as_ptr(), scope.as_ptr(), $color, 0);;
				});
				$crate::MicroProfileEnter(TOKEN);	
			}
		}
		let _scope = $crate::MicroProfileDroppable{};
	};
	($group_name:expr, $scope_name:expr) => {
		scope!($group_name, $scope_name, 0);
	}
}

#[cfg(feature = "disabled")]
#[macro_export] 
macro_rules! scope {
	($group_name:expr, $scope_name:expr, $color:expr) => {
	};
	($group_name:expr, $scope_name:expr) => {
	}
}



#[cfg(not(feature = "disabled"))]
#[macro_export] 
macro_rules! init { () => { $crate::init(); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! init { () => { } }

#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! flip { () => { $crate::flip(); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! flip { () => { } }

#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! shutdown { () => { $crate::shutdown(); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! shutdown { () => { } }

#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! start_auto_flip { ($delay_in_ms:expr) => { $crate::start_auto_flip($delay_in_ms); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! start_auto_flip { ($delay_in_ms:expr) => { } }

#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! stop_auto_flip { () => { $crate::stop_auto_flip(); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! stop_auto_flip { () => { } }

#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! on_thread_exit { () => { $crate::on_thread_exit(); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! on_thread_exit { () => { } }


#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! on_thread_create { ($name:expr) => { $crate::on_thread_create($name); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! on_thread_create { ($name:expr) => { } }


#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! set_enable_all_groups { ($enabled:expr) => { $crate::set_enable_all_groups($enabled); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! set_enable_all_groups { ($enabled:expr) => { } }


#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! dump_file { ($html:expr, $csv:expr, $cpu_spike:expr, $gpu_spike:expr) => { $crate::dump_file($html, $csv, $cpu_spike, $gpu_spike); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! dump_file { ($html:expr, $csv:expr, $cpu_spike:expr, $gpu_spike:expr) => { } }


#[cfg(not(feature = "disabled"))]
#[macro_export]
macro_rules! dump_file_immediately { ($html:expr, $csv:expr) => { $crate::dump_file_immediately($html, $csv); } }
#[cfg(feature = "disabled")]
#[macro_export]
macro_rules! dump_file_immediately { ($html:expr, $csv:expr) => { } }


#[cfg(test)]
mod tests {
	fn run_test()
	{
		crate::scope!("foo", "fisk");
		for _ in 0..10
		{
			crate::scope!("foo", "bar", 0xff00ff00);
			crate::scope!("foo", "fest");
			for _ in 0..10
			{
				crate::scope!("foo", "baz");
				std::thread::sleep(std::time::Duration::new(0, 1_000_000_000u32 /100));
			}
		}
	}
    #[test]
	fn basic() {
		crate::init!();
		crate::set_enable_all_groups!(true);
		crate::start_auto_flip!(20);
		run_test();
		crate::dump_file_immediately!("foo.html", "");
		crate::dump_file_immediately!("", "foo.csv");
		crate::stop_auto_flip!();
		crate::shutdown!();
	}
}