#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(clippy::enum_variant_names)] pub(crate) enum Label {
DecodeStep,
DecodeCbCommit,
DecodeCbWait,
DecodeHostScalarRead,
DecodeGrammarMask,
DecodeSample,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum SignpostMode {
Auto,
Always,
}
impl SignpostMode {
pub(crate) const ENV_VAR: &'static str = "LATTICE_SIGNPOST_MODE";
pub(crate) fn from_env_value(value: Option<&str>) -> Self {
match value {
Some("always") => SignpostMode::Always,
_ => SignpostMode::Auto,
}
}
#[cfg_attr(not(all(feature = "signpost", target_os = "macos")), allow(dead_code))]
fn from_process_env() -> Self {
let value = std::env::var(Self::ENV_VAR).ok();
Self::from_env_value(value.as_deref())
}
#[cfg_attr(not(all(feature = "signpost", target_os = "macos")), allow(dead_code))]
fn category(self) -> &'static str {
match self {
SignpostMode::Auto => "DynamicTracing",
SignpostMode::Always => "decode",
}
}
}
#[cfg(all(feature = "signpost", target_os = "macos"))]
mod imp {
use super::Label;
use std::ffi::{CString, c_char, c_void};
use std::sync::OnceLock;
#[allow(non_camel_case_types)]
type os_log_t = *mut c_void;
#[allow(non_camel_case_types)]
type os_signpost_id_t = u64;
const OS_SIGNPOST_INTERVAL_BEGIN: u8 = 1;
const OS_SIGNPOST_INTERVAL_END: u8 = 2;
unsafe extern "C" {
fn os_log_create(subsystem: *const c_char, category: *const c_char) -> os_log_t;
fn os_signpost_id_generate(log: os_log_t) -> os_signpost_id_t;
fn os_signpost_enabled(log: os_log_t) -> bool;
static __dso_handle: c_void;
fn _os_signpost_emit_with_name_impl(
dso: *const c_void,
log: os_log_t,
signpost_type: u8,
spid: os_signpost_id_t,
name: *const c_char,
format: *const c_char,
buf: *mut u8,
size: u32,
);
}
macro_rules! oslogstring {
($name:ident, $s:literal) => {
#[used]
#[unsafe(link_section = "__TEXT,__oslogstring,cstring_literals")]
static $name: [u8; $s.len() + 1] = {
let src = $s.as_bytes();
let mut buf = [0u8; $s.len() + 1];
let mut i = 0;
while i < src.len() {
buf[i] = src[i];
i += 1;
}
buf
};
};
}
oslogstring!(NAME_DECODE_STEP, "decode.step");
oslogstring!(NAME_DECODE_CB_COMMIT, "decode.cb_commit");
oslogstring!(NAME_DECODE_CB_WAIT, "decode.cb_wait");
oslogstring!(NAME_DECODE_HOST_SCALAR_READ, "decode.host_scalar_read");
oslogstring!(NAME_DECODE_GRAMMAR_MASK, "decode.grammar_mask");
oslogstring!(NAME_DECODE_SAMPLE, "decode.sample");
oslogstring!(EMPTY_FORMAT, "");
impl Label {
fn name_ptr(self) -> *const c_char {
let bytes: &'static [u8] = match self {
Label::DecodeStep => &NAME_DECODE_STEP,
Label::DecodeCbCommit => &NAME_DECODE_CB_COMMIT,
Label::DecodeCbWait => &NAME_DECODE_CB_WAIT,
Label::DecodeHostScalarRead => &NAME_DECODE_HOST_SCALAR_READ,
Label::DecodeGrammarMask => &NAME_DECODE_GRAMMAR_MASK,
Label::DecodeSample => &NAME_DECODE_SAMPLE,
};
bytes.as_ptr().cast()
}
}
fn create_log(category: &str) -> usize {
let subsystem = CString::new("ai.lattice.inference").expect("static subsystem string");
let category = CString::new(category).expect("signpost category string has no NUL byte");
unsafe { os_log_create(subsystem.as_ptr(), category.as_ptr()) as usize }
}
fn decode_log() -> os_log_t {
static LOG: OnceLock<usize> = OnceLock::new();
let ptr =
*LOG.get_or_init(|| create_log(super::SignpostMode::from_process_env().category()));
ptr as os_log_t
}
fn emit_unchecked(
log: os_log_t,
signpost_type: u8,
spid: os_signpost_id_t,
name: *const c_char,
) {
let mut buf: [u8; 2] = [0, 0];
unsafe {
_os_signpost_emit_with_name_impl(
&__dso_handle as *const c_void,
log,
signpost_type,
spid,
name,
EMPTY_FORMAT.as_ptr().cast(),
buf.as_mut_ptr(),
buf.len() as u32,
);
}
}
pub struct Interval {
state: Option<(os_log_t, os_signpost_id_t, Label)>,
}
impl Interval {
pub fn begin(label: Label) -> Self {
let log = decode_log();
if !unsafe { os_signpost_enabled(log) } {
return Interval { state: None };
}
let spid = unsafe { os_signpost_id_generate(log) };
emit_unchecked(log, OS_SIGNPOST_INTERVAL_BEGIN, spid, label.name_ptr());
Interval {
state: Some((log, spid, label)),
}
}
pub fn not_recording() -> Self {
Interval { state: None }
}
}
impl Drop for Interval {
fn drop(&mut self) {
if let Some((log, spid, label)) = self.state {
emit_unchecked(log, OS_SIGNPOST_INTERVAL_END, spid, label.name_ptr());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn always_mode_category_is_enabled_with_no_tool_attached() {
let log = create_log("decode") as os_log_t;
assert!(
unsafe { os_signpost_enabled(log) },
"ordinary category must report enabled even with no tool attached \
(mode=always exists precisely so the xcrun xctrace CLI path observes it)"
);
}
#[test]
fn auto_mode_category_is_idle_inert_with_no_tool_attached() {
let log = create_log("DynamicTracing") as os_log_t;
assert!(
!unsafe { os_signpost_enabled(log) },
"DynamicTracing category must report disabled with no tool attached \
(round 3's idle-inertness property, preserved as the default mode)"
);
}
}
}
#[cfg(not(all(feature = "signpost", target_os = "macos")))]
mod imp {
use super::Label;
pub struct Interval;
impl Interval {
#[inline(always)]
pub fn begin(_label: Label) -> Self {
Interval
}
#[inline(always)]
pub fn not_recording() -> Self {
Interval
}
}
}
pub(crate) use imp::Interval;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Scope {
Decode,
NotDecode,
}
#[inline(always)]
pub(crate) fn interval(label: Label) -> Interval {
Interval::begin(label)
}
#[inline(always)]
pub(crate) fn interval_in(scope: Scope, label: Label) -> Interval {
match scope {
Scope::Decode => Interval::begin(label),
Scope::NotDecode => Interval::not_recording(),
}
}
#[cfg(test)]
pub(crate) mod recorder {
use super::{Label, Scope};
use std::cell::RefCell;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Event {
Begin(Label),
End(Label),
}
thread_local! {
static LOG: RefCell<Vec<Event>> = const { RefCell::new(Vec::new()) };
}
pub(crate) fn clear() {
LOG.with(|log| log.borrow_mut().clear());
}
pub(crate) fn events() -> Vec<Event> {
LOG.with(|log| log.borrow().clone())
}
pub(crate) struct RecordingInterval(Option<Label>);
impl RecordingInterval {
pub(crate) fn begin(label: Label) -> Self {
LOG.with(|log| log.borrow_mut().push(Event::Begin(label)));
RecordingInterval(Some(label))
}
pub(crate) fn begin_in(scope: Scope, label: Label) -> Self {
match scope {
Scope::Decode => Self::begin(label),
Scope::NotDecode => RecordingInterval(None),
}
}
}
impl Drop for RecordingInterval {
fn drop(&mut self) {
if let Some(label) = self.0 {
LOG.with(|log| log.borrow_mut().push(Event::End(label)));
}
}
}
}
#[cfg(test)]
mod tests {
use super::Label;
use super::Scope;
use super::SignpostMode;
use super::interval;
use super::recorder::{Event, RecordingInterval};
#[test]
fn signpost_mode_from_env_value() {
assert_eq!(SignpostMode::from_env_value(None), SignpostMode::Auto);
assert_eq!(SignpostMode::from_env_value(Some("")), SignpostMode::Auto);
assert_eq!(
SignpostMode::from_env_value(Some("auto")),
SignpostMode::Auto
);
assert_eq!(
SignpostMode::from_env_value(Some("Always")),
SignpostMode::Auto
);
assert_eq!(
SignpostMode::from_env_value(Some("bogus")),
SignpostMode::Auto
);
assert_eq!(
SignpostMode::from_env_value(Some("always")),
SignpostMode::Always
);
}
#[test]
fn signpost_mode_category_mapping() {
assert_eq!(SignpostMode::Auto.category(), "DynamicTracing");
assert_eq!(SignpostMode::Always.category(), "decode");
}
#[test]
fn interval_guard_compiles_and_drops_cleanly() {
let _guard = interval(Label::DecodeStep);
{
let _nested = interval(Label::DecodeCbCommit);
}
}
#[test]
fn nested_intervals_emit_begin_end_in_order() {
super::recorder::clear();
{
let _outer = RecordingInterval::begin(Label::DecodeStep);
{
let _inner = RecordingInterval::begin(Label::DecodeCbCommit);
}
}
assert_eq!(
super::recorder::events(),
vec![
Event::Begin(Label::DecodeStep),
Event::Begin(Label::DecodeCbCommit),
Event::End(Label::DecodeCbCommit),
Event::End(Label::DecodeStep),
]
);
}
#[test]
fn decode_sample_label_records_begin_end_pair() {
super::recorder::clear();
{
let _guard = RecordingInterval::begin(Label::DecodeSample);
}
assert_eq!(
super::recorder::events(),
vec![
Event::Begin(Label::DecodeSample),
Event::End(Label::DecodeSample)
]
);
}
#[test]
fn scope_discriminator_silences_non_decode_and_records_decode() {
super::recorder::clear();
{
let _not_decode = RecordingInterval::begin_in(Scope::NotDecode, Label::DecodeStep);
}
assert_eq!(
super::recorder::events(),
vec![],
"Scope::NotDecode must record nothing"
);
super::recorder::clear();
{
let _decode = RecordingInterval::begin_in(Scope::Decode, Label::DecodeStep);
}
assert_eq!(
super::recorder::events(),
vec![
Event::Begin(Label::DecodeStep),
Event::End(Label::DecodeStep)
],
"Scope::Decode must record the begin/end pair"
);
}
}