mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Summary This PR adds `memchr` for some low-hanging performance improvements (namely, in MCP stdio, Ollama streaming, and full message-history newline counts). Codex produced the following release benchmarks: | Operation | Before | After | Speedup | | --- | ---: | ---: | ---: | | MCP 1 MiB chunked line | 2.172 s | 3.984 ms | 545x | | Ollama 1 MiB chunked line | 1.673 s | 2.790 ms | 600x | | Count newlines in 10 MiB history | 132.83 ms | 20.05 ms | 6.6x | With a "real" MCP setup (`ExecutorStdioServerLauncher` started a Python MCP server, completed `initialize`, requested `tools/list`, and deserialized a 1 MiB tool description over newline-delimited stdio), it's about 16x faster end-to-end: | Branch | 50 calls | Per call | | --- | ---: | ---: | | `main` | 862.53 ms | 17.25 ms | | this branch | 53.89 ms | 1.08 ms | `memchr` is already in our dependency tree and extremely widely used for this kind of optimized scanning.
221 lines
7.0 KiB
Rust
221 lines
7.0 KiB
Rust
use super::*;
|
|
use codex_config::types::History;
|
|
use pretty_assertions::assert_eq;
|
|
use std::fs::File;
|
|
use std::io::Write;
|
|
use tempfile::TempDir;
|
|
|
|
#[tokio::test]
|
|
async fn lookup_reads_history_entries() {
|
|
let temp_dir = TempDir::new().expect("create temp dir");
|
|
let history_path = temp_dir.path().join(HISTORY_FILENAME);
|
|
|
|
let entries = vec![
|
|
HistoryEntry {
|
|
session_id: "first-session".to_string(),
|
|
ts: 1,
|
|
text: "first".to_string(),
|
|
},
|
|
HistoryEntry {
|
|
session_id: "second-session".to_string(),
|
|
ts: 2,
|
|
text: "second".to_string(),
|
|
},
|
|
];
|
|
|
|
let mut file = File::create(&history_path).expect("create history file");
|
|
for entry in &entries {
|
|
writeln!(
|
|
file,
|
|
"{}",
|
|
serde_json::to_string(entry).expect("serialize history entry")
|
|
)
|
|
.expect("write history entry");
|
|
}
|
|
|
|
let (log_id, count) = history_metadata_for_file(&history_path).await;
|
|
assert_eq!(count, entries.len());
|
|
|
|
let second_entry = lookup_history_entry(&history_path, log_id, /*offset*/ 1)
|
|
.expect("fetch second history entry");
|
|
assert_eq!(second_entry, entries[1]);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn history_metadata_counts_newlines_across_read_boundaries() {
|
|
let temp_dir = TempDir::new().expect("create temp dir");
|
|
let history_path = temp_dir.path().join(HISTORY_FILENAME);
|
|
let mut contents = vec![b'x'; 3 * HISTORY_READ_BUFFER_SIZE + 1];
|
|
let newline_offsets = [
|
|
0,
|
|
HISTORY_READ_BUFFER_SIZE - 1,
|
|
HISTORY_READ_BUFFER_SIZE,
|
|
2 * HISTORY_READ_BUFFER_SIZE,
|
|
contents.len() - 2,
|
|
];
|
|
for offset in newline_offsets {
|
|
contents[offset] = b'\n';
|
|
}
|
|
std::fs::write(&history_path, contents).expect("write history file");
|
|
|
|
let (_, count) = history_metadata_for_file(&history_path).await;
|
|
|
|
assert_eq!(count, newline_offsets.len());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn lookup_uses_stable_log_id_after_appends() {
|
|
let temp_dir = TempDir::new().expect("create temp dir");
|
|
let history_path = temp_dir.path().join(HISTORY_FILENAME);
|
|
|
|
let initial = HistoryEntry {
|
|
session_id: "first-session".to_string(),
|
|
ts: 1,
|
|
text: "first".to_string(),
|
|
};
|
|
let appended = HistoryEntry {
|
|
session_id: "second-session".to_string(),
|
|
ts: 2,
|
|
text: "second".to_string(),
|
|
};
|
|
|
|
let mut file = File::create(&history_path).expect("create history file");
|
|
writeln!(
|
|
file,
|
|
"{}",
|
|
serde_json::to_string(&initial).expect("serialize initial entry")
|
|
)
|
|
.expect("write initial entry");
|
|
|
|
let (log_id, count) = history_metadata_for_file(&history_path).await;
|
|
assert_eq!(count, 1);
|
|
|
|
let mut append = std::fs::OpenOptions::new()
|
|
.append(true)
|
|
.open(&history_path)
|
|
.expect("open history file for append");
|
|
writeln!(
|
|
append,
|
|
"{}",
|
|
serde_json::to_string(&appended).expect("serialize appended entry")
|
|
)
|
|
.expect("append history entry");
|
|
|
|
let fetched = lookup_history_entry(&history_path, log_id, /*offset*/ 1)
|
|
.expect("lookup appended history entry");
|
|
assert_eq!(fetched, appended);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn append_entry_trims_history_when_beyond_max_bytes() {
|
|
let codex_home = TempDir::new().expect("create temp dir");
|
|
let mut history = History::default();
|
|
let mut config = HistoryConfig::new(codex_home.path(), &history);
|
|
let conversation_id = "conversation-id";
|
|
|
|
let entry_one = "a".repeat(200);
|
|
let entry_two = "b".repeat(200);
|
|
|
|
let history_path = codex_home.path().join("history.jsonl");
|
|
|
|
append_entry(&entry_one, &conversation_id, &config)
|
|
.await
|
|
.expect("write first entry");
|
|
|
|
let first_len = std::fs::metadata(&history_path).expect("metadata").len();
|
|
let limit_bytes = first_len + 10;
|
|
|
|
history.max_bytes = Some(usize::try_from(limit_bytes).expect("limit should fit into usize"));
|
|
config = HistoryConfig::new(codex_home.path(), &history);
|
|
|
|
append_entry(&entry_two, &conversation_id, &config)
|
|
.await
|
|
.expect("write second entry");
|
|
|
|
let contents = std::fs::read_to_string(&history_path).expect("read history");
|
|
|
|
let entries = contents
|
|
.lines()
|
|
.map(|line| serde_json::from_str::<HistoryEntry>(line).expect("parse entry"))
|
|
.collect::<Vec<HistoryEntry>>();
|
|
|
|
assert_eq!(
|
|
entries.len(),
|
|
1,
|
|
"only one entry left because entry_one should be evicted"
|
|
);
|
|
assert_eq!(entries[0].text, entry_two);
|
|
assert!(std::fs::metadata(&history_path).expect("metadata").len() <= limit_bytes);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn append_entry_trims_history_to_soft_cap() {
|
|
let codex_home = TempDir::new().expect("create temp dir");
|
|
let mut history = History::default();
|
|
let mut config = HistoryConfig::new(codex_home.path(), &history);
|
|
let conversation_id = "conversation-id";
|
|
|
|
let short_entry = "a".repeat(200);
|
|
let long_entry = "b".repeat(400);
|
|
|
|
let history_path = codex_home.path().join("history.jsonl");
|
|
|
|
append_entry(&short_entry, &conversation_id, &config)
|
|
.await
|
|
.expect("write first entry");
|
|
|
|
let short_entry_len = std::fs::metadata(&history_path).expect("metadata").len();
|
|
|
|
append_entry(&long_entry, &conversation_id, &config)
|
|
.await
|
|
.expect("write second entry");
|
|
|
|
let two_entry_len = std::fs::metadata(&history_path).expect("metadata").len();
|
|
|
|
let long_entry_len = two_entry_len
|
|
.checked_sub(short_entry_len)
|
|
.expect("second entry length should be larger than first entry length");
|
|
|
|
history.max_bytes = Some(
|
|
usize::try_from((2 * long_entry_len) + (short_entry_len / 2))
|
|
.expect("max bytes should fit into usize"),
|
|
);
|
|
config = HistoryConfig::new(codex_home.path(), &history);
|
|
|
|
append_entry(&long_entry, &conversation_id, &config)
|
|
.await
|
|
.expect("write third entry");
|
|
|
|
let contents = std::fs::read_to_string(&history_path).expect("read history");
|
|
|
|
let entries = contents
|
|
.lines()
|
|
.map(|line| serde_json::from_str::<HistoryEntry>(line).expect("parse entry"))
|
|
.collect::<Vec<HistoryEntry>>();
|
|
|
|
assert_eq!(entries.len(), 1);
|
|
assert_eq!(entries[0].text, long_entry);
|
|
|
|
let pruned_len = std::fs::metadata(&history_path).expect("metadata").len();
|
|
let max_bytes = config.max_bytes.expect("max bytes should be configured") as u64;
|
|
|
|
assert!(pruned_len <= max_bytes);
|
|
|
|
let soft_cap_bytes = ((max_bytes as f64) * HISTORY_SOFT_CAP_RATIO)
|
|
.floor()
|
|
.clamp(1.0, max_bytes as f64) as u64;
|
|
let len_without_first = 2 * long_entry_len;
|
|
|
|
assert!(
|
|
len_without_first <= max_bytes,
|
|
"dropping only the first entry would satisfy the hard cap"
|
|
);
|
|
assert!(
|
|
len_without_first > soft_cap_bytes,
|
|
"soft cap should require more aggressive trimming than the hard cap"
|
|
);
|
|
|
|
assert_eq!(pruned_len, long_entry_len);
|
|
assert!(pruned_len <= soft_cap_bytes.max(long_entry_len));
|
|
}
|