Line data Source code
1 : use std::collections::HashMap;
2 : use std::io::BufReader;
3 :
4 : use camino::Utf8PathBuf;
5 : use clap::Parser;
6 : use itertools::Itertools as _;
7 : use pageserver_api::key::{CompactKey, Key};
8 : use pageserver_api::models::PageTraceEvent;
9 : use pageserver_api::reltag::RelTag;
10 :
11 : /// Parses a page trace (as emitted by the `page_trace` timeline API), and outputs stats.
12 : #[derive(Parser)]
13 : pub(crate) struct PageTraceCmd {
14 : /// Trace input file.
15 0 : path: Utf8PathBuf,
16 : }
17 :
18 0 : pub(crate) fn main(cmd: &PageTraceCmd) -> anyhow::Result<()> {
19 0 : let mut file = BufReader::new(std::fs::OpenOptions::new().read(true).open(&cmd.path)?);
20 0 : let mut events: Vec<PageTraceEvent> = Vec::new();
21 : loop {
22 0 : match bincode::deserialize_from(&mut file) {
23 0 : Ok(event) => events.push(event),
24 0 : Err(err) => {
25 0 : if let bincode::ErrorKind::Io(ref err) = *err {
26 0 : if err.kind() == std::io::ErrorKind::UnexpectedEof {
27 0 : break;
28 0 : }
29 0 : }
30 0 : return Err(err.into());
31 : }
32 : }
33 : }
34 :
35 0 : let mut reads_by_relation: HashMap<RelTag, i64> = HashMap::new();
36 0 : let mut reads_by_key: HashMap<CompactKey, i64> = HashMap::new();
37 :
38 0 : for event in events {
39 0 : let key = Key::from_compact(event.key);
40 0 : let reltag = RelTag {
41 0 : spcnode: key.field2,
42 0 : dbnode: key.field3,
43 0 : relnode: key.field4,
44 0 : forknum: key.field5,
45 0 : };
46 0 :
47 0 : *reads_by_relation.entry(reltag).or_default() += 1;
48 0 : *reads_by_key.entry(event.key).or_default() += 1;
49 0 : }
50 :
51 0 : let multi_read_keys = reads_by_key
52 0 : .into_iter()
53 0 : .filter(|(_, count)| *count > 1)
54 0 : .sorted_by_key(|(key, count)| (-*count, *key))
55 0 : .collect_vec();
56 0 :
57 0 : println!("Multi-read keys: {}", multi_read_keys.len());
58 0 : for (key, count) in multi_read_keys {
59 0 : println!(" {key}: {count}");
60 0 : }
61 :
62 0 : let reads_by_relation = reads_by_relation
63 0 : .into_iter()
64 0 : .sorted_by_key(|(rel, count)| (-*count, *rel))
65 0 : .collect_vec();
66 0 :
67 0 : println!("Reads by relation:");
68 0 : for (reltag, count) in reads_by_relation {
69 0 : println!(" {reltag}: {count}");
70 0 : }
71 :
72 0 : Ok(())
73 0 : }
|