3个版本 (1个稳定版本)
新 1.0.3 | 2024年8月21日 |
---|---|
0.2.0 | 2024年8月15日 |
0.1.0 | 2024年8月15日 |
#90 in 机器学习
每月下载 338 次
用于 2 crate
49KB
1K SLoC
为sched_ext调度器提供统计传输库
sched_ext 是Linux内核特性,它使得在BPF中实现内核线程调度器并动态加载它们成为可能。
此库提供了一个简单的方法来定义统计信息并通过UNIX域套接字访问它们。虽然此库是为SCX调度器开发的,但它可以在其他地方使用,唯一的假设是默认的UNIX域套接字路径,该路径可以被覆盖。
统计信息定义为结构体。一个统计信息结构体可以包含以下字段
-
数字 - i32, u32, i64, u64, f64。
-
字符串。
-
包含允许字段的结构体。
-
Vec
和BTreeMap
包含上述内容。
以下内容来自 examples/stats_defs.rs.h
#[derive(Clone, Debug, Serialize, Deserialize, Stats)]
#[stat(desc = "domain statistics", _om_prefix="d_", _om_label="domain_name")]
struct DomainStats {
pub name: String,
#[stat(desc = "an event counter")]
pub events: u64,
#[stat(desc = "a gauge number")]
pub pressure: f64,
}
#[derive(Clone, Debug, Serialize, Deserialize, Stats)]
#[stat(desc = "cluster statistics", top)]
struct ClusterStats {
pub name: String,
#[stat(desc = "update timestamp")]
pub at: u64,
#[stat(desc = "some bitmap we want to report", _om_skip)]
pub bitmap: Vec<u32>,
#[stat(desc = "domain statistics")]
pub doms_dict: BTreeMap<usize, DomainStats>,
}
scx_stats_derive::Stats
是生成所需一切的 derive 宏,包括统计元数据。stat 结构体和字段属性允许添加注释。以下属性目前被定义
结构和字段属性
- desc: 描述。
仅结构体属性
- top: 标记默认报告的最顶层统计结构体。用于通用工具在处理元数据时找到起点。
此外,可以在结构和字段上添加以“_”开头的任意用户属性。它们收集到包含的结构体或字段的“user”字典中。当此类用户属性的值未指定时,默认赋值为字符串“true”。例如,scripts/scxstats_to_openmetrics.py 识别以下用户属性
-
_om_prefix
: 将值加到字段名前形成唯一的OpenMetrics度量名称。 -
_om_label
: 标签用于区分字典的不同成员。此字段属性指定字典字段的标签名称。 -
_om_skip
:并非所有字段都适合翻译成OpenMetrics。这个无值字段属性标记了要跳过的字段。
examples/stats_defs.rs.h
展示了如何使用上述属性。有关实际用法,请参阅scx_layered。
请注意,scx_stats依赖于serde
和serde_json
,并且每个统计结构都必须派生Serialize
和Deserialize
。
通过UNIX域套接字提供上述结构的统计服务器可以启动如下:
let _server = ScxStatsServer::new()
.set_path(&path)
.add_stats_meta(ClusterStats::meta())
.add_stats_meta(DomainStats::meta())
.add_stats("top", Box::new(move |_| stats.to_json()))
.launch()
.unwrap();
scx_stats::Meta::meta()
trait函数由每个统计结构的scx_stats::Meta
derive宏自动实现。将它们添加到统计服务器中,可以实现不需要统计结构定义的通用客户端,例如将统计传递到另一个框架,如OpenMetrics。
top
是未指定特定目标时的默认统计报告,应始终添加到服务器中。闭包应返回serde_json::Value
。请注意,scx_stats::ToJson
自动将.to_json()
添加到实现了scx_stats::Meta
和serde::Serialize
的结构的结构体中。
上面的代码将启动监听于@path
的统计服务器。请注意,当_server
变量被丢弃时,服务器将关闭。客户端也非常简单。取自examples/client.rs
let mut client = ScxStatsClient::new().set_path(path).connect().unwrap();
上面的代码创建了一个客户端实例。让我们查询统计信息
let resp = client.request::<ClusterStats>("stat", vec![]);
println!("{:#?}", &resp);
上面的代码等同于查询top
目标
println!("\n===== Requesting \"stat\" with \"target\"=\"top\":");
let resp = client.request::<ClusterStats>("stat", vec![("target".into(), "top".into())]);
println!("{:#?}", &resp);
如果将("args", BTreeMap<String, String>)
作为@args
向量的部分传递,则将BTreeMap
作为参数传递到服务器端的处理闭包。
当实现没有访问统计结构定义的通用客户端时,元数据会很有用
println!("\n===== Requesting \"stats_meta\" but receiving with serde_json::Value:");
let resp = client.request::<serde_json::Value>("stats_meta", vec![]).unwrap();
println!("{}", serde_json::to_string_pretty(&resp).unwrap());
对于此示例,输出将如下所示
{
"ClusterStats": {
"desc": "cluster statistics",
"fields": {
"at": {
"datum": "u64",
"desc": "update timestamp"
},
"bitmap": {
"array": "u64",
"desc": "some bitmap we want to report",
"user": {
"_om_skip": "true"
}
},
"doms_dict": {
"desc": "domain statistics",
"dict": {
"datum": {
"struct": "DomainStats"
},
"key": "u64"
}
},
"name": {
"datum": "string"
}
},
"name": "ClusterStats",
"top": "true"
},
"DomainStats": {
"desc": "domain statistics",
"fields": {
"events": {
"datum": "u64",
"desc": "an event counter"
},
"name": {
"datum": "string"
},
"pressure": {
"datum": "float",
"desc": "a gauge number"
}
},
"name": "DomainStats",
"user": {
"_om_label": "domain_name",
"_om_prefix": "d_"
}
}
}
UNIX域套接字上用于通信的协议是基于行的,每行包含一个json,非常简单。使用examples/client
运行,并将RUST_LOG=trace
设置为查看通过线缆发送的内容
> cargo run --example server -- ~/tmp/socket
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/examples/server /home/htejun/tmp/socket`
Server listening. Run `client "/home/htejun/tmp/socket"`.
Use `socat - UNIX-CONNECT:"/home/htejun/tmp/socket"` for raw connection.
Press any key to exit.
$ RUST_LOG=trace cargo run --example client -- ~/tmp/socket
...
===== Requesting "stats" but receiving with serde_json::Value:
2024-08-15T22:13:23.769Z TRACE [scx_stats::client] Sending: {"req":"stats","args":{"target":"top"}}
2024-08-15T22:13:23.769Z TRACE [scx_stats::client] Received: {"errno":0,"args":{"resp":{"at":12345,"bitmap":[3735928559,3203391149],"doms_dict":{"0":{"events":1234,"name":"domain 0","pressure":1.234},"3":{"events":5678,"name":"domain 3","pressure":5.678}},"name":"test cluster"}}}
Ok(
Object {
"at": Number(12345),
"bitmap": Array [
Number(3735928559),
Number(3203391149),
],
"doms_dict": Object {
"0": Object {
"events": Number(1234),
"name": String("domain 0"),
"pressure": Number(1.234),
},
"3": Object {
"events": Number(5678),
"name": String("domain 3"),
"pressure": Number(5.678),
},
},
"name": String("test cluster"),
},
依赖项
~1-2MB
~41K SLoC