summaryrefslogtreecommitdiff
path: root/profiler/src/lib.rs
blob: d23ad24bc5d2f7d90ec6fc936201564da7aa3715 (plain)
use std::sync::OnceLock;

use alligator_console::{ConsoleLogger, ConsoleMessage};
use chrono::{DateTime, Utc};
use scopeguard::ScopeGuard;

static GLOBAL_PROFILER: OnceLock<Profiler> = OnceLock::new();

struct Profiler {
	logger: ConsoleLogger,
	start_time: DateTime<Utc>,
}

impl Profiler {
	fn new(logger: ConsoleLogger) -> Self {
		Self {
			logger,
			start_time: Utc::now(),
		}
	}

	fn current_timestamp(&self) -> i64 {
		Utc::now()
			.signed_duration_since(DateTime::UNIX_EPOCH)
			.num_microseconds()
			.unwrap_or(i64::MAX)
	}

	fn finish_frame(&self) {
		self.logger.send(ConsoleMessage::FrameTime {
			timestamp: self.current_timestamp(),
		})
	}

	fn start_scope(&self, scope_name: String) {
		self.logger.send(ConsoleMessage::ScopeStart {
			scope_name,
			timestamp: self.current_timestamp(),
		})
	}

	fn end_scope(&self) {
		self.logger.send(ConsoleMessage::ScopeEnd {
			timestamp: self.current_timestamp(),
		})
	}
}

pub fn set_profiler(logger: ConsoleLogger) {
	GLOBAL_PROFILER.get_or_init(|| Profiler::new(logger));
}

pub fn finish_frame() {
	GLOBAL_PROFILER.get().unwrap().finish_frame();
}

pub fn start_scope(scope_name: impl AsRef<str>) {
	GLOBAL_PROFILER
		.get()
		.unwrap()
		.start_scope(scope_name.as_ref().to_string());
}

pub fn end_scope() {
	GLOBAL_PROFILER.get().unwrap().end_scope();
}

pub fn profile_scope(scope_name: impl AsRef<str>) -> ScopeGuard<(), impl FnOnce(())> {
	start_scope(scope_name);
	scopeguard::guard((), |_| end_scope())
}

#[macro_export]
macro_rules! scope {
	($scope_name: expr) => {
		let _profiling_scope = $crate::profile_scope($scope_name);
	};
	() => {
		let _profiling_scope = $crate::profile_scope("unnamed scope");
	};
}

#[macro_export]
macro_rules! function_name {
	() => {{
		fn f() {}
		fn type_name_of<T>(_: T) -> &'static str {
			std::any::type_name::<T>()
		}
		type_name_of(f)
			.split("::")
			.filter(|&part| part != "f")
			.collect::<Vec<&str>>()
			.join("::")
	}};
}

#[macro_export]
macro_rules! profile_function {
	() => {
		$crate::scope!($crate::function_name!());
	};
}