diff --git a/Cargo.lock b/Cargo.lock index 420ae4de5..9debaf06a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -531,6 +540,7 @@ dependencies = [ "group", "jubjub", "libc", + "metrics", "rand_core", "subtle", "tracing", @@ -566,6 +576,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + [[package]] name = "memoffset" version = "0.5.6" @@ -575,6 +591,30 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metrics" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e285601dcfb9f3a8f37a7093b9956a0df730b50848c8ac0117406aff06c851" +dependencies = [ + "metrics-macros", + "proc-macro-hack", +] + +[[package]] +name = "metrics-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ac60cd4d3a869fd39d57baf0ed7f79fb677580d8d6655c4330d4f1126bc27b" +dependencies = [ + "lazy_static", + "proc-macro-hack", + "proc-macro2", + "quote", + "regex", + "syn", +] + [[package]] name = "num-bigint" version = "0.3.2" @@ -649,6 +689,12 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + [[package]] name = "proc-macro2" version = "1.0.24" @@ -737,7 +783,10 @@ version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", + "thread_local", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7286fdb4d..fc84bb68e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,9 @@ zcash_primitives = "0.5" zcash_proofs = "0.5" ed25519-zebra = "2.0.0" +# Metrics +metrics = "0.14.2" + # Temporary workaround for https://github.com/myrrlyn/funty/issues/3 funty = "=1.1.0" diff --git a/src/rust/include/rust/metrics.h b/src/rust/include/rust/metrics.h new file mode 100644 index 000000000..ca753f071 --- /dev/null +++ b/src/rust/include/rust/metrics.h @@ -0,0 +1,159 @@ +// Copyright (c) 2020 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#ifndef ZCASH_RUST_INCLUDE_RUST_METRICS_H +#define ZCASH_RUST_INCLUDE_RUST_METRICS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct MetricsCallsite; +typedef struct MetricsCallsite MetricsCallsite; + +/// Creates a metrics callsite. +/// +/// You should usually call one of the helper macros such as `MetricsCounter` +/// instead of calling this directly. +/// +/// This MUST ONLY be called to assign a `static MetricsCallsite*`, and all +/// string arguments MUST be static `const char*` constants, and MUST be valid +/// UTF-8. +MetricsCallsite* metrics_callsite(const char* name); + +/// Increments a counter. +/// +/// Counters represent a single monotonic value, which means the value can only +/// be incremented, not decremented, and always starts out with an initial value +/// of zero. +void metrics_increment_counter(const MetricsCallsite* callsite, uint64_t value); + +/// Updates a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always +/// starts out with an initial value of zero. +void metrics_update_gauge(const MetricsCallsite* callsite, double value); + +/// Increments a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always +/// starts out with an initial value of zero. +void metrics_increment_gauge(const MetricsCallsite* callsite, double value); + +/// Decrements a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always +/// starts out with an initial value of zero. +void metrics_decrement_gauge(const MetricsCallsite* callsite, double value); + +/// Records a histogram. +/// +/// Histograms measure the distribution of values for a given set of +/// measurements, and start with no initial values. +void metrics_record_histogram(const MetricsCallsite* callsite, double value); + +#ifdef __cplusplus +} +#endif + +// +// Helper macros +// + +#ifdef __cplusplus +// Constructs a metrics callsite. +// +// The 'static constexpr' hack ensures that name is a compile-time constant +// with static storage duration. The output of this macro MUST be stored as a +// static MetricsCallsite*. +#define M_CALLSITE(name) ([&] { \ + static constexpr const char* _m_name = name; \ + return metrics_callsite(_m_name); \ +}()) +#else +// Constructs a metrics callsite. +// +// name MUST be a static constant, and the output of this macro MUST be stored +// as a static MetricsCallsite*. +#define M_CALLSITE(name) \ + metrics_callsite(name) +#endif + +// +// Metrics +// + +/// Increments a counter. +/// +/// Counters represent a single monotonic value, which means the value can only +/// be incremented, not decremented, and always starts out with an initial value +/// of zero. +/// +/// name MUST be a static constant, and MUST be a valid UTF-8 string. +#define MetricsCounter(name, value) \ + do { \ + static MetricsCallsite* CALLSITE = M_CALLSITE(name); \ + metrics_increment_counter(CALLSITE, value); \ + } while (0) + +/// Increments a counter by one. +/// +/// Counters represent a single monotonic value, which means the value can only +/// be incremented, not decremented, and always starts out with an initial value +/// of zero. +/// +/// name MUST be a static constant, and MUST be a valid UTF-8 string. +#define MetricsIncrementCounter(name) MetricsCounter(name, 1) + +/// Updates a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always +/// starts out with an initial value of zero. +/// +/// name MUST be a static constant, and MUST be a valid UTF-8 string. +#define MetricsGauge(name, value) \ + do { \ + static MetricsCallsite* CALLSITE = M_CALLSITE(name); \ + metrics_update_gauge(CALLSITE, value); \ + } while (0) + +/// Increments a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always +/// starts out with an initial value of zero. +/// +/// name MUST be a static constant, and MUST be a valid UTF-8 string. +#define MetricsIncrementGauge(name, value) \ + do { \ + static MetricsCallsite* CALLSITE = M_CALLSITE(name); \ + metrics_increment_gauge(CALLSITE, value); \ + } while (0) + +/// Decrements a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always +/// starts out with an initial value of zero. +/// +/// name MUST be a static constant, and MUST be a valid UTF-8 string. +#define MetricsDecrementGauge(name, value) \ + do { \ + static MetricsCallsite* CALLSITE = M_CALLSITE(name); \ + metrics_decrement_gauge(CALLSITE, value); \ + } while (0) + +/// Records a histogram. +/// +/// Histograms measure the distribution of values for a given set of +/// measurements, and start with no initial values. +/// +/// name MUST be a static constant, and MUST be a valid UTF-8 string. +#define MetricsHistogram(name, value) \ + do { \ + static MetricsCallsite* CALLSITE = M_CALLSITE(name); \ + metrics_record_histogram(CALLSITE, value); \ + } while (0) + +#endif // ZCASH_RUST_INCLUDE_RUST_METRICS_H diff --git a/src/rust/src/metrics_ffi.rs b/src/rust/src/metrics_ffi.rs new file mode 100644 index 000000000..111c72345 --- /dev/null +++ b/src/rust/src/metrics_ffi.rs @@ -0,0 +1,64 @@ +use libc::{c_char, c_double}; +use metrics::{try_recorder, GaugeValue, Key, KeyData}; +use std::ffi::CStr; + +pub struct FfiCallsite { + key_data: KeyData, +} + +#[no_mangle] +pub extern "C" fn metrics_callsite(name: *const c_char) -> *mut FfiCallsite { + let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap(); + Box::into_raw(Box::new(FfiCallsite { + key_data: KeyData::from_name(name), + })) +} + +#[no_mangle] +pub extern "C" fn metrics_increment_counter(callsite: *const FfiCallsite, value: u64) { + if let Some(recorder) = try_recorder() { + let callsite = unsafe { callsite.as_ref().unwrap() }; + recorder.increment_counter(Key::Borrowed(&callsite.key_data), value); + } +} + +#[no_mangle] +pub extern "C" fn metrics_update_gauge(callsite: *const FfiCallsite, value: c_double) { + if let Some(recorder) = try_recorder() { + let callsite = unsafe { callsite.as_ref().unwrap() }; + recorder.update_gauge( + Key::Borrowed(&callsite.key_data), + GaugeValue::Absolute(value), + ); + } +} + +#[no_mangle] +pub extern "C" fn metrics_increment_gauge(callsite: *const FfiCallsite, value: c_double) { + if let Some(recorder) = try_recorder() { + let callsite = unsafe { callsite.as_ref().unwrap() }; + recorder.update_gauge( + Key::Borrowed(&callsite.key_data), + GaugeValue::Increment(value), + ); + } +} + +#[no_mangle] +pub extern "C" fn metrics_decrement_gauge(callsite: *const FfiCallsite, value: c_double) { + if let Some(recorder) = try_recorder() { + let callsite = unsafe { callsite.as_ref().unwrap() }; + recorder.update_gauge( + Key::Borrowed(&callsite.key_data), + GaugeValue::Decrement(value), + ); + } +} + +#[no_mangle] +pub extern "C" fn metrics_record_histogram(callsite: *const FfiCallsite, value: c_double) { + if let Some(recorder) = try_recorder() { + let callsite = unsafe { callsite.as_ref().unwrap() }; + recorder.record_histogram(Key::Borrowed(&callsite.key_data), value); + } +} diff --git a/src/rust/src/rustzcash.rs b/src/rust/src/rustzcash.rs index 677011a6b..9994995d2 100644 --- a/src/rust/src/rustzcash.rs +++ b/src/rust/src/rustzcash.rs @@ -63,6 +63,7 @@ use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree} mod blake2b; mod ed25519; +mod metrics_ffi; mod tracing_ffi; #[cfg(test)]