micromegas_analytics/
time.rs1use std::sync::Arc;
2
3use anyhow::Result;
4use chrono::{DateTime, TimeDelta, Utc};
5use datafusion::scalar::ScalarValue;
6use micromegas_telemetry::types::block::BlockMetadata;
7
8use crate::metadata::ProcessMetadata;
9
10const NANOS_PER_SEC: f64 = 1000.0 * 1000.0 * 1000.0;
11
12pub use micromegas_telemetry::time_range::TimeRange;
13
14pub fn make_time_converter_from_block_meta(
16 process: &ProcessMetadata,
17 block: &BlockMetadata,
18) -> Result<ConvertTicks> {
19 if process.tsc_frequency > 0 {
20 return ConvertTicks::from_meta_data(
22 process.start_ticks,
23 process.start_time.timestamp_nanos_opt().unwrap_or_default(),
24 process.tsc_frequency,
25 );
26 }
27 let delta_time = block.end_time - process.start_time;
28 let nb_seconds = delta_time.num_nanoseconds().unwrap_or_default() as f64 / 1_000_000_000.0;
29 let ticks_per_second = block.end_ticks as f64 / nb_seconds;
30 ConvertTicks::from_meta_data(
31 process.start_ticks,
32 process.start_time.timestamp_nanos_opt().unwrap_or_default(),
33 ticks_per_second.round() as i64,
34 )
35}
36
37pub fn make_time_converter_from_latest_timing(
41 process: &ProcessMetadata,
42 last_block_end_ticks: i64,
43 last_block_end_time: chrono::DateTime<chrono::Utc>,
44) -> Result<ConvertTicks> {
45 if process.tsc_frequency > 0 {
46 return ConvertTicks::from_meta_data(
48 process.start_ticks,
49 process.start_time.timestamp_nanos_opt().unwrap_or_default(),
50 process.tsc_frequency,
51 );
52 }
53 let delta_time = last_block_end_time - process.start_time;
55 let nb_seconds = delta_time.num_nanoseconds().unwrap_or_default() as f64 / 1_000_000_000.0;
56 let ticks_per_second = last_block_end_ticks as f64 / nb_seconds;
57 ConvertTicks::from_meta_data(
58 process.start_ticks,
59 process.start_time.timestamp_nanos_opt().unwrap_or_default(),
60 ticks_per_second.round() as i64,
61 )
62}
63
64#[derive(Debug, Clone)]
66pub struct ConvertTicks {
67 tick_offset: i64,
68 process_start_ns: i64,
69 frequency: i64, inv_tsc_frequency_ns: f64,
71 inv_tsc_frequency_ms: f64,
72}
73
74impl ConvertTicks {
75 pub fn from_meta_data(start_ticks: i64, process_start_ns: i64, frequency: i64) -> Result<Self> {
76 if frequency <= 0 {
77 anyhow::bail!("invalid frequency")
78 }
79 Ok(Self {
80 tick_offset: start_ticks,
81 process_start_ns,
82 frequency,
83 inv_tsc_frequency_ns: get_tsc_frequency_inverse_ns(frequency),
84 inv_tsc_frequency_ms: get_tsc_frequency_inverse_ms(frequency),
85 })
86 }
87
88 pub fn get_frequency(&self) -> i64 {
90 self.frequency
91 }
92
93 pub fn to_ticks(&self, delta: TimeDelta) -> i64 {
95 let mut seconds = delta.num_seconds() as f64;
96 seconds += delta.subsec_nanos() as f64 / NANOS_PER_SEC;
97 let freq = self.frequency as f64;
98 (seconds * freq).round() as i64
99 }
100
101 pub fn ticks_to_nanoseconds(&self, ticks: i64) -> i64 {
103 let delta = (ticks - self.tick_offset) as f64;
104 let ns_since_process_start = (delta * self.inv_tsc_frequency_ns).round() as i64;
105 self.process_start_ns + ns_since_process_start
106 }
107
108 pub fn delta_ticks_to_time(&self, delta: i64) -> DateTime<Utc> {
110 let ns_since_process_start = (delta as f64 * self.inv_tsc_frequency_ns).round() as i64;
111 DateTime::from_timestamp_nanos(self.process_start_ns + ns_since_process_start)
112 }
113
114 pub fn delta_ticks_to_ns(&self, delta: i64) -> i64 {
116 let ns_since_process_start = (delta as f64 * self.inv_tsc_frequency_ns).round() as i64;
117 self.process_start_ns + ns_since_process_start
118 }
119
120 pub fn delta_ticks_to_ms(&self, delta_ticks: i64) -> f64 {
122 let delta = delta_ticks as f64;
123 delta * self.inv_tsc_frequency_ms
124 }
125
126 pub fn time_to_delta_ticks(&self, time: DateTime<Utc>) -> i64 {
128 self.to_ticks(time - DateTime::from_timestamp_nanos(self.process_start_ns))
129 }
130}
131
132#[allow(clippy::cast_precision_loss)]
134pub fn get_tsc_frequency_inverse_ms(tsc_frequency: i64) -> f64 {
135 1000.0 / tsc_frequency as f64
136}
137
138#[allow(clippy::cast_precision_loss)]
140pub fn get_tsc_frequency_inverse_ns(tsc_frequency: i64) -> f64 {
141 NANOS_PER_SEC / tsc_frequency as f64
142}
143
144pub fn datetime_to_scalar(v: DateTime<Utc>) -> ScalarValue {
146 lazy_static::lazy_static! {
147 static ref UTC_OFFSET: Arc<str> = Arc::from("+00:00");
148 }
149 ScalarValue::TimestampNanosecond(v.timestamp_nanos_opt(), Some(UTC_OFFSET.clone()))
150}