mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-26 23:25:55 -05:00
benchmark camera page, fix broken schema
This page was noticeably slower than necessary because the recording_cover index wasn't actually covering the query. Both the schema for new databases and the upgrade query were broken (and not even in the same way). No new schema version to correct this, at least for now. I'll probably have another reason to change the schema soon anyway and can throw this in.
This commit is contained in:
parent
3314673b8f
commit
da4e439b9c
@ -72,11 +72,15 @@ pub fn run(tx: &rusqlite::Transaction) -> Result<(), Error> {
|
||||
check (composite_id >> 32 = camera_id)
|
||||
);
|
||||
create index recording_cover on recording (
|
||||
camera_id,
|
||||
start_time_90k,
|
||||
duration_90k,
|
||||
video_samples,
|
||||
video_sync_samples,
|
||||
video_sample_entry_id,
|
||||
sample_file_bytes
|
||||
sample_file_bytes,
|
||||
run_offset,
|
||||
flags
|
||||
);
|
||||
create table recording_playback (
|
||||
composite_id integer primary key references recording (composite_id),
|
||||
|
41
src/mp4.rs
41
src/mp4.rs
@ -1709,48 +1709,13 @@ mod tests {
|
||||
mod bench {
|
||||
extern crate test;
|
||||
|
||||
use db;
|
||||
use hyper;
|
||||
use hyper::header;
|
||||
use recording::{self, TIME_UNITS_PER_SEC};
|
||||
use http_entity;
|
||||
use self::test::Bencher;
|
||||
use std::str;
|
||||
use super::tests::create_mp4_from_db;
|
||||
use testutil::{self, TestDb, TEST_CAMERA_ID};
|
||||
#[cfg(feature="nightly")] use uuid::Uuid;
|
||||
|
||||
fn add_dummy_recordings_to_db(db: &db::Database) {
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(include_bytes!("testdata/video_sample_index.bin"));
|
||||
let mut db = db.lock();
|
||||
let video_sample_entry_id = db.insert_video_sample_entry(1920, 1080, &[0u8; 100]).unwrap();
|
||||
const START_TIME: recording::Time = recording::Time(1430006400i64 * TIME_UNITS_PER_SEC);
|
||||
const DURATION: recording::Duration = recording::Duration(5399985);
|
||||
let mut recording = db::RecordingToInsert{
|
||||
camera_id: TEST_CAMERA_ID,
|
||||
sample_file_bytes: 30104460,
|
||||
flags: 0,
|
||||
time: START_TIME .. (START_TIME + DURATION),
|
||||
local_time_delta: recording::Duration(0),
|
||||
video_samples: 1800,
|
||||
video_sync_samples: 60,
|
||||
video_sample_entry_id: video_sample_entry_id,
|
||||
sample_file_uuid: Uuid::nil(),
|
||||
video_index: data,
|
||||
sample_file_sha1: [0; 20],
|
||||
run_offset: 0,
|
||||
};
|
||||
let mut tx = db.tx().unwrap();
|
||||
tx.bypass_reservation_for_testing = true;
|
||||
for _ in 0..60 {
|
||||
tx.insert_recording(&recording).unwrap();
|
||||
recording.time.start += DURATION;
|
||||
recording.time.end += DURATION;
|
||||
recording.run_offset += 1;
|
||||
}
|
||||
tx.commit().unwrap();
|
||||
}
|
||||
use testutil::{self, TestDb};
|
||||
|
||||
/// An HTTP server for benchmarking.
|
||||
/// It's used as a singleton via `lazy_static!` for two reasons:
|
||||
@ -1779,7 +1744,7 @@ mod bench {
|
||||
let url = hyper::Url::parse(
|
||||
format!("http://{}:{}/", addr.ip(), addr.port()).as_str()).unwrap();
|
||||
let db = TestDb::new();
|
||||
add_dummy_recordings_to_db(&db.db);
|
||||
testutil::add_dummy_recordings_to_db(&db.db, 60);
|
||||
let mp4 = create_mp4_from_db(db.db.clone(), db.dir.clone(), 0, 0, false);
|
||||
let p = mp4.initial_sample_byte_pos;
|
||||
use std::thread::spawn;
|
||||
@ -1853,7 +1818,7 @@ mod bench {
|
||||
fn mp4_construction(b: &mut Bencher) {
|
||||
testutil::init();
|
||||
let db = TestDb::new();
|
||||
add_dummy_recordings_to_db(&db.db);
|
||||
testutil::add_dummy_recordings_to_db(&db.db, 60);
|
||||
b.iter(|| {
|
||||
create_mp4_from_db(db.db.clone(), db.dir.clone(), 0, 0, false);
|
||||
});
|
||||
|
@ -148,8 +148,11 @@ create index recording_cover on recording (
|
||||
-- to consult the underlying row.
|
||||
duration_90k,
|
||||
video_samples,
|
||||
video_sync_samples,
|
||||
video_sample_entry_id,
|
||||
sample_file_bytes
|
||||
sample_file_bytes,
|
||||
run_offset,
|
||||
flags
|
||||
);
|
||||
|
||||
-- Large fields for a recording which are not needed when simply listing all
|
||||
|
@ -47,7 +47,7 @@ use uuid::Uuid;
|
||||
static INIT: sync::Once = sync::ONCE_INIT;
|
||||
|
||||
lazy_static! {
|
||||
static ref TEST_CAMERA_UUID: Uuid =
|
||||
pub static ref TEST_CAMERA_UUID: Uuid =
|
||||
Uuid::parse_str("ce2d9bc2-0cd3-4204-9324-7b5ccb07183c").unwrap();
|
||||
}
|
||||
|
||||
@ -150,3 +150,37 @@ impl TestDb {
|
||||
row.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// For benchmarking
|
||||
#[cfg(feature="nightly")]
|
||||
pub fn add_dummy_recordings_to_db(db: &db::Database, num: usize) {
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(include_bytes!("testdata/video_sample_index.bin"));
|
||||
let mut db = db.lock();
|
||||
let video_sample_entry_id = db.insert_video_sample_entry(1920, 1080, &[0u8; 100]).unwrap();
|
||||
const START_TIME: recording::Time = recording::Time(1430006400i64 * TIME_UNITS_PER_SEC);
|
||||
const DURATION: recording::Duration = recording::Duration(5399985);
|
||||
let mut recording = db::RecordingToInsert{
|
||||
camera_id: TEST_CAMERA_ID,
|
||||
sample_file_bytes: 30104460,
|
||||
flags: 0,
|
||||
time: START_TIME .. (START_TIME + DURATION),
|
||||
local_time_delta: recording::Duration(0),
|
||||
video_samples: 1800,
|
||||
video_sync_samples: 60,
|
||||
video_sample_entry_id: video_sample_entry_id,
|
||||
sample_file_uuid: Uuid::nil(),
|
||||
video_index: data,
|
||||
sample_file_sha1: [0; 20],
|
||||
run_offset: 0,
|
||||
};
|
||||
let mut tx = db.tx().unwrap();
|
||||
tx.bypass_reservation_for_testing = true;
|
||||
for _ in 0..num {
|
||||
tx.insert_recording(&recording).unwrap();
|
||||
recording.time.start += DURATION;
|
||||
recording.time.end += DURATION;
|
||||
recording.run_offset += 1;
|
||||
}
|
||||
tx.commit().unwrap();
|
||||
}
|
||||
|
53
src/web.rs
53
src/web.rs
@ -539,7 +539,6 @@ impl Handler {
|
||||
impl server::Handler for Handler {
|
||||
fn handle(&self, req: server::Request, res: server::Response) {
|
||||
let (path, query) = get_path_and_query(&req.uri);
|
||||
error!("path={:?}, query={:?}", path, query);
|
||||
let res = match decode_path(path) {
|
||||
Path::CamerasList => self.list_cameras(&req, res),
|
||||
Path::Camera(uuid) => self.camera(uuid, query, &req, res),
|
||||
@ -597,3 +596,55 @@ mod tests {
|
||||
Segments::parse("1-5.26-42").unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature="nightly"))]
|
||||
mod bench {
|
||||
extern crate test;
|
||||
|
||||
use hyper;
|
||||
use self::test::Bencher;
|
||||
use std::str;
|
||||
use testutil::{self, TestDb};
|
||||
|
||||
struct Server {
|
||||
base_url: String,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
fn new() -> Server {
|
||||
let mut listener = hyper::net::HttpListener::new("127.0.0.1:0").unwrap();
|
||||
use hyper::net::NetworkListener;
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let server = hyper::Server::new(listener);
|
||||
let url = format!("http://{}:{}", addr.ip(), addr.port());
|
||||
let db = TestDb::new();
|
||||
testutil::add_dummy_recordings_to_db(&db.db, 1440);
|
||||
::std::thread::spawn(move || {
|
||||
let h = super::Handler::new(db.db.clone(), db.dir.clone());
|
||||
let _ = server.handle(h);
|
||||
});
|
||||
Server{base_url: url}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SERVER: Server = { Server::new() };
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn serve_camera_html(b: &mut Bencher) {
|
||||
testutil::init();
|
||||
let server = &*SERVER;
|
||||
let url = hyper::Url::parse(&format!("{}/cameras/{}/", server.base_url,
|
||||
*testutil::TEST_CAMERA_UUID)).unwrap();
|
||||
let mut buf = Vec::new();
|
||||
b.iter(|| {
|
||||
let client = hyper::Client::new();
|
||||
let mut resp = client.get(url.clone()).send().unwrap();
|
||||
assert_eq!(resp.status, hyper::status::StatusCode::Ok);
|
||||
buf.clear();
|
||||
use std::io::Read;
|
||||
resp.read_to_end(&mut buf).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user