From 8b1f38b015a6dea501a007fdc7daed4a9f757f34 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 12 Mar 2023 19:01:54 +0000 Subject: [PATCH 01/23] worker_impl: Remove misleading update() from ExamineDatasetMgr [nfc] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `update(mod)` would be on the DatasetDB, not the manager. Rather, modifications currently just fail due to e.g. `set(…)` not being defined. --- artiq/master/worker_impl.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 719ff40a8..ed7ec748e 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -186,10 +186,6 @@ class ExamineDatasetMgr: def get(key, archive=False): return ParentDatasetDB.get(key) - @staticmethod - def update(self, mod): - pass - def examine(device_mgr, dataset_mgr, file): previous_keys = set(sys.modules.keys()) From e9a153b985d1c703338ad49bb0ac986ade29d21a Mon Sep 17 00:00:00 2001 From: Spaqin Date: Wed, 22 Mar 2023 11:16:25 +0800 Subject: [PATCH 02/23] runtime: implement distributed DMA --- artiq/coredevice/dma.py | 17 +- artiq/firmware/ksupport/lib.rs | 26 +- .../firmware/libproto_artiq/drtioaux_proto.rs | 29 +- artiq/firmware/libproto_artiq/kernel_proto.rs | 20 +- artiq/firmware/runtime/main.rs | 7 +- artiq/firmware/runtime/rtio_dma.rs | 284 ++++++++++++++++-- artiq/firmware/runtime/rtio_mgt.rs | 108 ++++++- artiq/firmware/runtime/sched.rs | 4 + artiq/firmware/runtime/session.rs | 61 +++- artiq/firmware/satman/dma.rs | 17 +- artiq/firmware/satman/main.rs | 15 +- 11 files changed, 508 insertions(+), 80 deletions(-) diff --git a/artiq/coredevice/dma.py b/artiq/coredevice/dma.py index 261a6bcfe..72e0f4a08 100644 --- a/artiq/coredevice/dma.py +++ b/artiq/coredevice/dma.py @@ -6,7 +6,7 @@ alone could achieve. """ from artiq.language.core import syscall, kernel -from artiq.language.types import TInt32, TInt64, TStr, TNone, TTuple +from artiq.language.types import TInt32, TInt64, TStr, TNone, TTuple, TBool from artiq.coredevice.exceptions import DMAError from numpy import int64 @@ -17,7 +17,7 @@ def dma_record_start(name: TStr) -> TNone: raise NotImplementedError("syscall not simulated") @syscall -def dma_record_stop(duration: TInt64) -> TNone: +def dma_record_stop(duration: TInt64, enable_ddma: TBool) -> TNone: raise NotImplementedError("syscall not simulated") @syscall @@ -47,6 +47,7 @@ class DMARecordContextManager: def __init__(self): self.name = "" self.saved_now_mu = int64(0) + self.enable_ddma = False @kernel def __enter__(self): @@ -56,7 +57,7 @@ class DMARecordContextManager: @kernel def __exit__(self, type, value, traceback): - dma_record_stop(now_mu()) # see above + dma_record_stop(now_mu(), self.enable_ddma) # see above at_mu(self.saved_now_mu) @@ -74,12 +75,18 @@ class CoreDMA: self.epoch = 0 @kernel - def record(self, name): + def record(self, name, enable_ddma=False): """Returns a context manager that will record a DMA trace called ``name``. Any previously recorded trace with the same name is overwritten. - The trace will persist across kernel switches.""" + The trace will persist across kernel switches. + In DRTIO context, you can toggle distributed DMA with ``enable_ddma``. + Enabling it allows running DMA on satellites, rather than sending all + events from the master. + Disabling it may improve performance in some scenarios, + e.g. when there are many small satellite buffers.""" self.epoch += 1 self.recorder.name = name + self.recorder.enable_ddma = enable_ddma return self.recorder @kernel diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index acb461f88..1af9f7b46 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -269,7 +269,7 @@ extern fn dma_record_start(name: &CSlice) { } #[unwind(allowed)] -extern fn dma_record_stop(duration: i64) { +extern fn dma_record_stop(duration: i64, enable_ddma: bool) { unsafe { dma_record_flush(); @@ -285,7 +285,8 @@ extern fn dma_record_stop(duration: i64) { DMA_RECORDER.active = false; send(&DmaRecordStop { - duration: duration as u64 + duration: duration as u64, + enable_ddma: enable_ddma }); } } @@ -370,7 +371,7 @@ extern fn dma_erase(name: &CSlice) { #[repr(C)] struct DmaTrace { duration: i64, - address: i32, + address: i32 } #[unwind(allowed)] @@ -404,6 +405,7 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { csr::cri_con::selected_write(1); csr::rtio_dma::enable_write(1); + send(&DmaStartRemoteRequest { id: ptr as i32, timestamp: timestamp }); while csr::rtio_dma::enable_read() != 0 {} csr::cri_con::selected_write(0); @@ -424,6 +426,24 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { } } } + + send(&DmaAwaitRemoteRequest { id: ptr as i32 }); + recv!(&DmaAwaitRemoteReply { timeout, error, channel, timestamp } => { + if timeout { + raise!("DMAError", + "Error running DMA on satellite device, timed out waiting for results"); + } + if error & 1 != 0 { + raise!("RTIOUnderflow", + "RTIO underflow at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp as i64, 0); + } + if error & 2 != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp as i64, 0); + } + }); } #[cfg(not(has_rtio_dma))] diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index f5b232db9..efbf56bae 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -14,8 +14,8 @@ impl From> for Error { } } -/* 512 (max size) - 4 (CRC) - 1 (packet ID) - 4 (trace ID) - 1 (last) - 2 (length) */ -const DMA_TRACE_MAX_SIZE: usize = 500; +/* 512 (max size) - 4 (CRC) - 1 (packet ID) - 1 (destination) - 4 (trace ID) - 1 (last) - 2 (length) */ +pub const DMA_TRACE_MAX_SIZE: usize = 499; #[derive(PartialEq, Debug)] pub enum Packet { @@ -58,13 +58,13 @@ pub enum Packet { SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, - DmaAddTraceRequest { id: u32, last: bool, length: u16, trace: [u8; DMA_TRACE_MAX_SIZE] }, + DmaAddTraceRequest { destination: u8, id: u32, last: bool, length: u16, trace: [u8; DMA_TRACE_MAX_SIZE] }, DmaAddTraceReply { succeeded: bool }, - DmaRemoveTraceRequest { id: u32 }, + DmaRemoveTraceRequest { destination: u8, id: u32 }, DmaRemoveTraceReply { succeeded: bool }, - DmaPlaybackRequest { id: u32, timestamp: u64 }, + DmaPlaybackRequest { destination: u8, id: u32, timestamp: u64 }, DmaPlaybackReply { succeeded: bool }, - DmaPlaybackStatus { id: u32, error: u8, channel: u32, timestamp: u64 } + DmaPlaybackStatus { destination: u8, id: u32, error: u8, channel: u32, timestamp: u64 } } @@ -198,12 +198,14 @@ impl Packet { }, 0xb0 => { + let destination = reader.read_u8()?; let id = reader.read_u32()?; let last = reader.read_bool()?; let length = reader.read_u16()?; let mut trace: [u8; DMA_TRACE_MAX_SIZE] = [0; DMA_TRACE_MAX_SIZE]; reader.read_exact(&mut trace[0..length as usize])?; Packet::DmaAddTraceRequest { + destination: destination, id: id, last: last, length: length as u16, @@ -214,12 +216,14 @@ impl Packet { succeeded: reader.read_bool()? }, 0xb2 => Packet::DmaRemoveTraceRequest { + destination: reader.read_u8()?, id: reader.read_u32()? }, 0xb3 => Packet::DmaRemoveTraceReply { succeeded: reader.read_bool()? }, 0xb4 => Packet::DmaPlaybackRequest { + destination: reader.read_u8()?, id: reader.read_u32()?, timestamp: reader.read_u64()? }, @@ -227,6 +231,7 @@ impl Packet { succeeded: reader.read_bool()? }, 0xb6 => Packet::DmaPlaybackStatus { + destination: reader.read_u8()?, id: reader.read_u32()?, error: reader.read_u8()?, channel: reader.read_u32()?, @@ -392,8 +397,9 @@ impl Packet { writer.write_bool(succeeded)?; }, - Packet::DmaAddTraceRequest { id, last, trace, length } => { + Packet::DmaAddTraceRequest { destination, id, last, trace, length } => { writer.write_u8(0xb0)?; + writer.write_u8(destination)?; writer.write_u32(id)?; writer.write_bool(last)?; // trace may be broken down to fit within drtio aux memory limit @@ -405,16 +411,18 @@ impl Packet { writer.write_u8(0xb1)?; writer.write_bool(succeeded)?; }, - Packet::DmaRemoveTraceRequest { id } => { + Packet::DmaRemoveTraceRequest { destination, id } => { writer.write_u8(0xb2)?; + writer.write_u8(destination)?; writer.write_u32(id)?; }, Packet::DmaRemoveTraceReply { succeeded } => { writer.write_u8(0xb3)?; writer.write_bool(succeeded)?; }, - Packet::DmaPlaybackRequest { id, timestamp } => { + Packet::DmaPlaybackRequest { destination, id, timestamp } => { writer.write_u8(0xb4)?; + writer.write_u8(destination)?; writer.write_u32(id)?; writer.write_u64(timestamp)?; }, @@ -422,8 +430,9 @@ impl Packet { writer.write_u8(0xb5)?; writer.write_bool(succeeded)?; }, - Packet::DmaPlaybackStatus { id, error, channel, timestamp } => { + Packet::DmaPlaybackStatus { destination, id, error, channel, timestamp } => { writer.write_u8(0xb6)?; + writer.write_u8(destination)?; writer.write_u32(id)?; writer.write_u8(error)?; writer.write_u32(channel)?; diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 8b07ea46b..e723ea2f5 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -20,7 +20,8 @@ pub enum Message<'a> { DmaRecordStart(&'a str), DmaRecordAppend(&'a [u8]), DmaRecordStop { - duration: u64 + duration: u64, + enable_ddma: bool }, DmaEraseRequest { @@ -32,9 +33,24 @@ pub enum Message<'a> { }, DmaRetrieveReply { trace: Option<&'a [u8]>, - duration: u64 + duration: u64, }, + DmaStartRemoteRequest { + id: i32, + timestamp: i64, + }, + DmaAwaitRemoteRequest { + id: i32 + }, + DmaAwaitRemoteReply { + timeout: bool, + error: u8, + channel: u32, + timestamp: u64 + }, + + RunFinished, RunException { exceptions: &'a [Option>], diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 3ae50dcad..5c54aeffa 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -182,6 +182,8 @@ fn startup() { drtio_routing::interconnect_disable_all(); let aux_mutex = sched::Mutex::new(); + let ddma_mutex = sched::Mutex::new(); + let mut scheduler = sched::Scheduler::new(interface); let io = scheduler.io(); @@ -189,14 +191,15 @@ fn startup() { io.spawn(4096, dhcp::dhcp_thread); } - rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations); + rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex); io.spawn(4096, mgmt::thread); { let aux_mutex = aux_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); let up_destinations = up_destinations.clone(); - io.spawn(16384, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations) }); + let ddma_mutex = ddma_mutex.clone(); + io.spawn(16384, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { diff --git a/artiq/firmware/runtime/rtio_dma.rs b/artiq/firmware/runtime/rtio_dma.rs index 292874047..1ec15384e 100644 --- a/artiq/firmware/runtime/rtio_dma.rs +++ b/artiq/firmware/runtime/rtio_dma.rs @@ -1,10 +1,182 @@ use core::mem; use alloc::{vec::Vec, string::String, collections::btree_map::BTreeMap}; +use sched::{Io, Mutex}; const ALIGNMENT: usize = 64; +#[cfg(has_drtio)] +pub mod remote_dma { + use super::*; + use board_artiq::drtio_routing::RoutingTable; + use rtio_mgt::drtio; + use board_misoc::clock; + + #[derive(Debug, PartialEq, Clone)] + pub enum RemoteState { + NotLoaded, + Loaded, + PlaybackEnded { error: u8, channel: u32, timestamp: u64 } + } + #[derive(Debug, Clone)] + struct RemoteTrace { + trace: Vec, + pub state: RemoteState + } + + impl From> for RemoteTrace { + fn from(trace: Vec) -> Self { + RemoteTrace { + trace: trace, + state: RemoteState::NotLoaded + } + } + } + + impl RemoteTrace { + pub fn get_trace(&self) -> &Vec { + &self.trace + } + } + + // remote traces map. ID -> destination, trace pair + static mut TRACES: BTreeMap> = BTreeMap::new(); + + pub fn add_traces(io: &Io, ddma_mutex: &Mutex, id: u32, traces: BTreeMap>) { + let _lock = ddma_mutex.lock(io); + let mut trace_map: BTreeMap = BTreeMap::new(); + for (destination, trace) in traces { + trace_map.insert(destination, trace.into()); + } + unsafe { TRACES.insert(id, trace_map); } + } + + pub fn await_done(io: &Io, ddma_mutex: &Mutex, id: u32, timeout: u64) -> Result { + let max_time = clock::get_ms() + timeout as u64; + io.until(|| { + if clock::get_ms() > max_time { + return true; + } + if ddma_mutex.test_lock() { + // cannot lock again within io.until - scheduler guarantees + // that it will not be interrupted - so only test the lock + return false; + } + let traces = unsafe { TRACES.get(&id).unwrap() }; + for (_dest, trace) in traces { + match trace.state { + RemoteState::PlaybackEnded {error: _, channel: _, timestamp: _} => (), + _ => return false + } + } + true + }).unwrap(); + if clock::get_ms() > max_time { + error!("Remote DMA await done timed out"); + return Err("Timed out waiting for results."); + } + // clear the internal state, and if there have been any errors, return one of them + let mut playback_state: RemoteState = RemoteState::PlaybackEnded { error: 0, channel: 0, timestamp: 0 }; + { + let _lock = ddma_mutex.lock(io).unwrap(); + let traces = unsafe { TRACES.get_mut(&id).unwrap() }; + for (_dest, trace) in traces { + match trace.state { + RemoteState::PlaybackEnded {error: e, channel: _c, timestamp: _ts} => if e != 0 { playback_state = trace.state.clone(); }, + _ => (), + } + trace.state = RemoteState::Loaded; + } + } + Ok(playback_state) + } + + pub fn erase(io: &Io, aux_mutex: &Mutex, routing_table: &RoutingTable, + ddma_mutex: &Mutex, id: u32) { + let _lock = ddma_mutex.lock(io).unwrap(); + let destinations = unsafe { TRACES.get(&id).unwrap() }; + for destination in destinations.keys() { + match drtio::ddma_send_erase(io, aux_mutex, routing_table, id, *destination) { + Ok(_) => (), + Err(e) => error!("Error erasing trace on DMA: {}", e) + } + } + unsafe { TRACES.remove(&id); } + } + + pub fn upload_traces(io: &Io, aux_mutex: &Mutex, routing_table: &RoutingTable, + ddma_mutex: &Mutex, id: u32) { + let _lock = ddma_mutex.lock(io); + let traces = unsafe { TRACES.get_mut(&id).unwrap() }; + for (destination, mut trace) in traces { + match drtio::ddma_upload_trace(io, aux_mutex, routing_table, id, *destination, trace.get_trace()) + { + Ok(_) => trace.state = RemoteState::Loaded, + Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e) + } + } + } + + pub fn playback(io: &Io, aux_mutex: &Mutex, routing_table: &RoutingTable, + ddma_mutex: &Mutex, id: u32, timestamp: u64) { + // triggers playback on satellites + let destinations = unsafe { + let _lock = ddma_mutex.lock(io).unwrap(); + TRACES.get(&id).unwrap() }; + for (destination, trace) in destinations { + { + // need to drop the lock before sending the playback request to avoid a deadlock + // if a PlaybackStatus is returned from another satellite in the meanwhile. + let _lock = ddma_mutex.lock(io).unwrap(); + if trace.state != RemoteState::Loaded { + error!("Destination {} not ready for DMA, state: {:?}", *destination, trace.state); + continue; + } + } + match drtio::ddma_send_playback(io, aux_mutex, routing_table, ddma_mutex, id, *destination, timestamp) { + Ok(_) => (), + Err(e) => error!("Error during remote DMA playback: {}", e) + } + } + } + + pub fn playback_done(io: &Io, ddma_mutex: &Mutex, + id: u32, destination: u8, error: u8, channel: u32, timestamp: u64) { + // called upon receiving PlaybackDone aux packet + let _lock = ddma_mutex.lock(io).unwrap(); + let mut trace = unsafe { TRACES.get_mut(&id).unwrap().get_mut(&destination).unwrap() }; + trace.state = RemoteState::PlaybackEnded { + error: error, + channel: channel, + timestamp: timestamp + }; + } + + pub fn destination_changed(io: &Io, aux_mutex: &Mutex, routing_table: &RoutingTable, + ddma_mutex: &Mutex, destination: u8, up: bool) { + // update state of the destination, resend traces if it's up + let _lock = ddma_mutex.lock(io).unwrap(); + let traces_iter = unsafe { TRACES.iter_mut() }; + for (id, dest_traces) in traces_iter { + if let Some(trace) = dest_traces.get_mut(&destination) { + if up { + match drtio::ddma_upload_trace(io, aux_mutex, routing_table, *id, destination, trace.get_trace()) + { + Ok(_) => trace.state = RemoteState::Loaded, + Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e) + } + } else { + trace.state = RemoteState::NotLoaded; + } + } + } + + } + +} + + #[derive(Debug)] -struct Entry { +struct LocalEntry { trace: Vec, padding_len: usize, duration: u64 @@ -12,7 +184,8 @@ struct Entry { #[derive(Debug)] pub struct Manager { - entries: BTreeMap, + entries: BTreeMap, + name_map: BTreeMap, recording_name: String, recording_trace: Vec } @@ -21,59 +194,116 @@ impl Manager { pub fn new() -> Manager { Manager { entries: BTreeMap::new(), - recording_name: String::new(), + name_map: BTreeMap::new(), recording_trace: Vec::new(), + recording_name: String::new() } } - pub fn record_start(&mut self, name: &str) { + pub fn record_start(&mut self, name: &str) -> Option { self.recording_name = String::from(name); self.recording_trace = Vec::new(); - - // or we could needlessly OOM replacing a large trace - self.entries.remove(name); + if let Some(id) = self.name_map.get(&self.recording_name) { + // replacing a trace + let old_id = id.clone(); + self.entries.remove(&id); + self.name_map.remove(&self.recording_name); + // return old ID + return Some(old_id); + } + return None; } pub fn record_append(&mut self, data: &[u8]) { self.recording_trace.extend_from_slice(data) } - pub fn record_stop(&mut self, duration: u64) { - let mut trace = Vec::new(); - mem::swap(&mut self.recording_trace, &mut trace); - trace.push(0); - let data_len = trace.len(); + pub fn record_stop(&mut self, duration: u64, enable_ddma: bool, + _io: &Io, _ddma_mutex: &Mutex) -> u32 { + let mut local_trace = Vec::new(); + let mut remote_traces: BTreeMap> = BTreeMap::new(); - // Realign. - trace.reserve(ALIGNMENT - 1); - let padding = ALIGNMENT - trace.as_ptr() as usize % ALIGNMENT; + if enable_ddma { + let mut trace = Vec::new(); + mem::swap(&mut self.recording_trace, &mut trace); + trace.push(0); + // analyze each entry and put in proper buckets, as the kernel core + // sends whole chunks, to limit comms/kernel CPU communication, + // and as only comms core has access to varios DMA buffers. + let mut ptr = 0; + while trace[ptr] != 0 { + // ptr + 3 = tgt >> 24 (destination) + let len = trace[ptr] as usize; + let destination = trace[ptr+3]; + if destination == 0 { + local_trace.extend(&trace[ptr..ptr+len]); + } + else { + if let Some(remote_trace) = remote_traces.get_mut(&destination) { + remote_trace.extend(&trace[ptr..ptr+len]); + } else { + remote_traces.insert(destination, trace[ptr..ptr+len].to_vec()); + } + } + // and jump to the next event + ptr += len; + } + } else { + // with disabled DDMA, move the whole trace to local + mem::swap(&mut self.recording_trace, &mut local_trace); + } + + local_trace.push(0); + let data_len = local_trace.len(); + // Realign the local entry. + local_trace.reserve(ALIGNMENT - 1); + let padding = ALIGNMENT - local_trace.as_ptr() as usize % ALIGNMENT; let padding = if padding == ALIGNMENT { 0 } else { padding }; for _ in 0..padding { // Vec guarantees that this will not reallocate - trace.push(0) + local_trace.push(0) } for i in 1..data_len + 1 { - trace[data_len + padding - i] = trace[data_len - i] + local_trace[data_len + padding - i] = local_trace[data_len - i] } - + // trace ID is its pointer + let id = local_trace[padding..].as_ptr() as u32; + self.entries.insert(id, LocalEntry { + trace: local_trace, + padding_len: padding, + duration: duration, + }); let mut name = String::new(); mem::swap(&mut self.recording_name, &mut name); - self.entries.insert(name, Entry { - trace: trace, - padding_len: padding, - duration: duration - }); + self.name_map.insert(name, id); + + #[cfg(has_drtio)] + remote_dma::add_traces(_io, _ddma_mutex, id, remote_traces); + + id } pub fn erase(&mut self, name: &str) { - self.entries.remove(name); + if let Some(id) = self.name_map.get(name) { + self.entries.remove(&id); + } + self.name_map.remove(name); + } + + #[cfg(has_drtio)] + pub fn get_id(&mut self, name: &str) -> Option<&u32> { + self.name_map.get(name) } pub fn with_trace(&self, name: &str, f: F) -> R where F: FnOnce(Option<&[u8]>, u64) -> R { - match self.entries.get(name) { - Some(entry) => f(Some(&entry.trace[entry.padding_len..]), entry.duration), - None => f(None, 0) + if let Some(ptr) = self.name_map.get(name) { + match self.entries.get(ptr) { + Some(entry) => f(Some(&entry.trace[entry.padding_len..]), entry.duration), + None => f(None, 0) + } + } else { + f(None, 0) } } } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 92aaaf66a..15a67be75 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -18,17 +18,22 @@ static mut RTIO_DEVICE_MAP: BTreeMap = BTreeMap::new(); #[cfg(has_drtio)] pub mod drtio { use super::*; + use alloc::vec::Vec; use drtioaux; + use proto_artiq::drtioaux_proto::DMA_TRACE_MAX_SIZE; + use rtio_dma::remote_dma; pub fn startup(io: &Io, aux_mutex: &Mutex, routing_table: &Urc>, - up_destinations: &Urc>) { + up_destinations: &Urc>, + ddma_mutex: &Mutex) { let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); - io.spawn(4096, move |io| { + let ddma_mutex = ddma_mutex.clone(); + io.spawn(8192, move |io| { let routing_table = routing_table.borrow(); - link_thread(io, &aux_mutex, &routing_table, &up_destinations); + link_thread(io, &aux_mutex, &routing_table, &up_destinations, &ddma_mutex); }); } @@ -147,9 +152,12 @@ pub mod drtio { } } - fn process_unsolicited_aux(io: &Io, aux_mutex: &Mutex, linkno: u8) { + fn process_unsolicited_aux(io: &Io, aux_mutex: &Mutex, linkno: u8, ddma_mutex: &Mutex) { let _lock = aux_mutex.lock(io).unwrap(); match drtioaux::recv(linkno) { + Ok(Some(drtioaux::Packet::DmaPlaybackStatus { id, destination, error, channel, timestamp })) => { + remote_dma::playback_done(io, ddma_mutex, id, destination, error, channel, timestamp); + } Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(None) => (), Err(_) => warn!("[LINK#{}] aux packet error", linkno) @@ -198,7 +206,8 @@ pub mod drtio { fn destination_survey(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_links: &[bool], - up_destinations: &Urc>) { + up_destinations: &Urc>, + ddma_mutex: &Mutex) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; let destination = destination as u8; @@ -216,8 +225,10 @@ pub mod drtio { destination: destination }); match reply { - Ok(drtioaux::Packet::DestinationDownReply) => - destination_set_up(routing_table, up_destinations, destination, false), + Ok(drtioaux::Packet::DestinationDownReply) => { + destination_set_up(routing_table, up_destinations, destination, false); + remote_dma::destination_changed(io, aux_mutex, routing_table, ddma_mutex, destination, false); + } Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => { error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); @@ -236,6 +247,7 @@ pub mod drtio { } } else { destination_set_up(routing_table, up_destinations, destination, false); + remote_dma::destination_changed(io, aux_mutex, routing_table, ddma_mutex, destination, false); } } else { if up_links[linkno as usize] { @@ -247,6 +259,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationOkReply) => { destination_set_up(routing_table, up_destinations, destination, true); init_buffer_space(destination as u8, linkno); + remote_dma::destination_changed(io, aux_mutex, routing_table, ddma_mutex, destination, true); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) @@ -259,7 +272,8 @@ pub mod drtio { pub fn link_thread(io: Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, - up_destinations: &Urc>) { + up_destinations: &Urc>, + ddma_mutex: &Mutex) { let mut up_links = [false; csr::DRTIO.len()]; loop { for linkno in 0..csr::DRTIO.len() { @@ -267,7 +281,7 @@ pub mod drtio { if up_links[linkno as usize] { /* link was previously up */ if link_rx_up(linkno) { - process_unsolicited_aux(&io, aux_mutex, linkno); + process_unsolicited_aux(&io, aux_mutex, linkno, ddma_mutex); process_local_errors(linkno); } else { info!("[LINK#{}] link is down", linkno); @@ -297,7 +311,7 @@ pub mod drtio { } } } - destination_survey(&io, aux_mutex, routing_table, &up_links, up_destinations); + destination_survey(&io, aux_mutex, routing_table, &up_links, up_destinations, ddma_mutex); io.sleep(200).unwrap(); } } @@ -328,6 +342,72 @@ pub mod drtio { } } } + + pub fn ddma_upload_trace(io: &Io, aux_mutex: &Mutex, + routing_table: &drtio_routing::RoutingTable, + id: u32, destination: u8, trace: &Vec) -> Result<(), &'static str> { + let linkno = routing_table.0[destination as usize][0] - 1; + let mut i = 0; + while i < trace.len() { + let mut trace_slice: [u8; DMA_TRACE_MAX_SIZE] = [0; DMA_TRACE_MAX_SIZE]; + let len: usize = if i + DMA_TRACE_MAX_SIZE < trace.len() { DMA_TRACE_MAX_SIZE } else { trace.len() - i } as usize; + let last = i + len == trace.len(); + trace_slice[..len].clone_from_slice(&trace[i..i+len]); + i += len; + let reply = aux_transact(io, aux_mutex, linkno, + &drtioaux::Packet::DmaAddTraceRequest { + id: id, destination: destination, last: last, length: len as u16, trace: trace_slice}); + match reply { + Ok(drtioaux::Packet::DmaAddTraceReply { succeeded: true }) => (), + Ok(drtioaux::Packet::DmaAddTraceReply { succeeded: false }) => { + return Err("error adding trace on satellite"); }, + Ok(_) => { return Err("adding DMA trace failed, unexpected aux packet"); }, + Err(_) => { return Err("adding DMA trace failed, aux error"); } + } + } + Ok(()) + } + + + pub fn ddma_send_erase(io: &Io, aux_mutex: &Mutex, + routing_table: &drtio_routing::RoutingTable, + id: u32, destination: u8) -> Result<(), &'static str> { + let linkno = routing_table.0[destination as usize][0] - 1; + let reply = aux_transact(io, aux_mutex, linkno, + &drtioaux::Packet::DmaRemoveTraceRequest { id: id, destination: destination }); + match reply { + Ok(drtioaux::Packet::DmaRemoveTraceReply { succeeded: true }) => Ok(()), + Ok(drtioaux::Packet::DmaRemoveTraceReply { succeeded: false }) => Err("satellite DMA erase error"), + Ok(_) => Err("adding trace failed, unexpected aux packet"), + Err(_) => Err("erasing trace failed, aux error") + } + } + + pub fn ddma_send_playback(io: &Io, aux_mutex: &Mutex, + routing_table: &drtio_routing::RoutingTable, + ddma_mutex: &Mutex, id: u32, destination: u8, timestamp: u64) -> Result<(), &'static str> { + let linkno = routing_table.0[destination as usize][0] - 1; + let _lock = aux_mutex.lock(io).unwrap(); + drtioaux::send(linkno, &drtioaux::Packet::DmaPlaybackRequest{ + id: id, destination: destination, timestamp: timestamp }).unwrap(); + loop { + let reply = recv_aux_timeout(io, linkno, 200); + match reply { + Ok(drtioaux::Packet::DmaPlaybackReply { succeeded: true }) => { return Ok(()) }, + Ok(drtioaux::Packet::DmaPlaybackReply { succeeded: false }) => { + return Err("error on DMA playback request") }, + // in case we received status from another destination + // but we want to get DmaPlaybackReply anyway, thus the loop + Ok(drtioaux::Packet::DmaPlaybackStatus { id, destination, error, channel, timestamp }) => { + remote_dma::playback_done(io, ddma_mutex, id, destination, error, channel, timestamp); + }, + Ok(_) => { return Err("received unexpected aux packet while DMA playback") }, + Err(_) => { return Err("aux error on DMA playback") } + } + } + } + + } #[cfg(not(has_drtio))] @@ -336,7 +416,8 @@ pub mod drtio { pub fn startup(_io: &Io, _aux_mutex: &Mutex, _routing_table: &Urc>, - _up_destinations: &Urc>) {} + _up_destinations: &Urc>, + _ddma_mutex: &Mutex) {} pub fn reset(_io: &Io, _aux_mutex: &Mutex) {} } @@ -410,9 +491,10 @@ pub fn resolve_channel_name(channel: u32) -> String { pub fn startup(io: &Io, aux_mutex: &Mutex, routing_table: &Urc>, - up_destinations: &Urc>) { + up_destinations: &Urc>, + ddma_mutex: &Mutex) { unsafe { RTIO_DEVICE_MAP = read_device_map(); } - drtio::startup(io, aux_mutex, routing_table, up_destinations); + drtio::startup(io, aux_mutex, routing_table, up_destinations, ddma_mutex); unsafe { csr::rtio_core::reset_phy_write(1); } diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 0adeaddd1..0d751da8e 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -301,6 +301,10 @@ impl Mutex { self.0.set(true); Ok(MutexGuard(&*self.0)) } + + pub fn test_lock<'a>(&'a self) -> bool { + self.0.get() + } } pub struct MutexGuard<'a>(&'a Cell); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index df3865f6b..04ef42864 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -10,6 +10,8 @@ use urc::Urc; use sched::{ThreadHandle, Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use rtio_clocking; use rtio_dma::Manager as DmaManager; +#[cfg(has_drtio)] +use rtio_dma::remote_dma; use rtio_mgt::{get_async_errors, resolve_channel_name}; use cache::Cache; use kern_hwreq; @@ -329,7 +331,7 @@ fn process_host_message(io: &Io, fn process_kern_message(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, - mut stream: Option<&mut TcpStream>, + ddma_mutex: &Mutex, mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { @@ -368,19 +370,31 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, } &kern::DmaRecordStart(name) => { - session.congress.dma_manager.record_start(name); + if let Some(_id) = session.congress.dma_manager.record_start(name) { + // replace the record + #[cfg(has_drtio)] + remote_dma::erase(io, aux_mutex, routing_table, ddma_mutex, _id); + } kern_acknowledge() } &kern::DmaRecordAppend(data) => { session.congress.dma_manager.record_append(data); kern_acknowledge() } - &kern::DmaRecordStop { duration } => { - session.congress.dma_manager.record_stop(duration); + &kern::DmaRecordStop { duration, enable_ddma } => { + let _id = session.congress.dma_manager.record_stop(duration, enable_ddma, io, ddma_mutex); + #[cfg(has_drtio)] + { + remote_dma::upload_traces(io, aux_mutex, routing_table, ddma_mutex, _id); + } cache::flush_l2_cache(); kern_acknowledge() } &kern::DmaEraseRequest { name } => { + #[cfg(has_drtio)] + if let Some(id) = session.congress.dma_manager.get_id(name) { + remote_dma::erase(io, aux_mutex, routing_table, ddma_mutex, *id); + } session.congress.dma_manager.erase(name); kern_acknowledge() } @@ -392,6 +406,27 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, }) }) } + &kern::DmaStartRemoteRequest { id: _id, timestamp: _timestamp } => { + #[cfg(has_drtio)] + remote_dma::playback(io, aux_mutex, routing_table, ddma_mutex, _id as u32, _timestamp as u64); + kern_acknowledge() + } + &kern::DmaAwaitRemoteRequest { id: _id } => { + #[cfg(has_drtio)] + let reply = match remote_dma::await_done(io, ddma_mutex, _id as u32, 10_000) { + Ok(remote_dma::RemoteState::PlaybackEnded { error, channel, timestamp }) => + kern::DmaAwaitRemoteReply { + timeout: false, + error: error, + channel: channel, + timestamp: timestamp + }, + _ => kern::DmaAwaitRemoteReply { timeout: true, error: 0, channel: 0, timestamp: 0}, + }; + #[cfg(not(has_drtio))] + let reply = kern::DmaAwaitRemoteReply { timeout: false, error: 0, channel: 0, timestamp: 0}; + kern_send(io, &reply) + } &kern::RpcSend { async, service, tag, data } => { match stream { @@ -511,7 +546,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, - stream: &mut TcpStream, + ddma_mutex: &Mutex, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -529,6 +564,7 @@ fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, if mailbox::receive() != 0 { process_kern_message(io, aux_mutex, routing_table, up_destinations, + ddma_mutex, Some(stream), &mut session)?; } @@ -546,7 +582,7 @@ fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, - congress: &mut Congress, + ddma_mutex: &Mutex, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -568,7 +604,7 @@ fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, } if mailbox::receive() != 0 { - if process_kern_message(io, aux_mutex, routing_table, up_destinations, None, &mut session)? { + if process_kern_message(io, aux_mutex, routing_table, up_destinations, ddma_mutex, None, &mut session)? { return Ok(()) } } @@ -598,7 +634,8 @@ fn respawn(io: &Io, handle: &mut Option, f: F) pub fn thread(io: Io, aux_mutex: &Mutex, routing_table: &Urc>, - up_destinations: &Urc>) { + up_destinations: &Urc>, + ddma_mutex: &Mutex) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -609,7 +646,7 @@ pub fn thread(io: Io, aux_mutex: &Mutex, { let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &aux_mutex, &routing_table.borrow(), &up_destinations, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &aux_mutex, &routing_table.borrow(), &up_destinations, ddma_mutex, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -649,12 +686,13 @@ pub fn thread(io: Io, aux_mutex: &Mutex, let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); + let ddma_mutex = ddma_mutex.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &ddma_mutex, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -677,10 +715,11 @@ pub fn thread(io: Io, aux_mutex: &Mutex, let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); + let ddma_mutex = ddma_mutex.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &ddma_mutex, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/artiq/firmware/satman/dma.rs b/artiq/firmware/satman/dma.rs index c0a0affcf..133bfd3c0 100644 --- a/artiq/firmware/satman/dma.rs +++ b/artiq/firmware/satman/dma.rs @@ -1,4 +1,4 @@ -use board_misoc::csr; +use board_misoc::{csr, cache::flush_l2_cache}; use alloc::{vec::Vec, collections::btree_map::BTreeMap}; const ALIGNMENT: usize = 64; @@ -52,7 +52,19 @@ impl Manager { pub fn add(&mut self, id: u32, last: bool, trace: &[u8], trace_len: usize) -> Result<(), Error> { let entry = match self.entries.get_mut(&id) { - Some(entry) => entry, + Some(entry) => { + if entry.complete { + // replace entry + self.entries.remove(&id); + self.entries.insert(id, Entry { + trace: Vec::new(), + padding_len: 0, + complete: false }); + self.entries.get_mut(&id).unwrap() + } else { + entry + } + }, None => { self.entries.insert(id, Entry { trace: Vec::new(), @@ -80,6 +92,7 @@ impl Manager { } entry.complete = true; entry.padding_len = padding; + flush_l2_cache(); } Ok(()) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 6f7ed4e6a..fb97b2bdb 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -301,19 +301,22 @@ fn process_aux_packet(_manager: &mut DmaManager, _repeaters: &mut [repeater::Rep } } #[cfg(has_rtio_dma)] - drtioaux::Packet::DmaAddTraceRequest { id, last, length, trace } => { + drtioaux::Packet::DmaAddTraceRequest { destination: _destination, id, last, length, trace } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = _manager.add(id, last, &trace, length as usize).is_ok(); drtioaux::send(0, &drtioaux::Packet::DmaAddTraceReply { succeeded: succeeded }) } #[cfg(has_rtio_dma)] - drtioaux::Packet::DmaRemoveTraceRequest { id } => { + drtioaux::Packet::DmaRemoveTraceRequest { destination: _destination, id } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = _manager.erase(id).is_ok(); drtioaux::send(0, &drtioaux::Packet::DmaRemoveTraceReply { succeeded: succeeded }) } #[cfg(has_rtio_dma)] - drtioaux::Packet::DmaPlaybackRequest { id, timestamp } => { + drtioaux::Packet::DmaPlaybackRequest { destination: _destination, id, timestamp } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = _manager.playback(id, timestamp).is_ok(); drtioaux::send(0, &drtioaux::Packet::DmaPlaybackReply { succeeded: succeeded }) @@ -463,7 +466,8 @@ pub extern fn main() -> i32 { unsafe { ALLOC.add_range(&mut _fheap, &mut _eheap); - pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); + // stack guard disabled, see https://github.com/m-labs/artiq/issues/2067 + // pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); } clock::init(); @@ -571,8 +575,9 @@ pub extern fn main() -> i32 { } } if let Some(status) = dma_manager.check_state() { + info!("playback done, error: {}, channel: {}, timestamp: {}", status.error, status.channel, status.timestamp); if let Err(e) = drtioaux::send(0, &drtioaux::Packet::DmaPlaybackStatus { - id: status.id, error: status.error, channel: status.channel, timestamp: status.timestamp }) { + destination: rank, id: status.id, error: status.error, channel: status.channel, timestamp: status.timestamp }) { error!("error sending DMA playback status: {}", e); } } From 9150230ea79d223b9e82d3f7aa74cb2fdc65d9a1 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 27 Mar 2023 17:06:20 +0800 Subject: [PATCH 03/23] dma: gate ddma features behind cfg(has_drtio) --- artiq/firmware/ksupport/lib.rs | 41 +++++++++++++++++------------- artiq/firmware/runtime/rtio_dma.rs | 13 +++++----- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 1af9f7b46..6693b7196 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -405,6 +405,7 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { csr::cri_con::selected_write(1); csr::rtio_dma::enable_write(1); + #[cfg(has_drtio)] send(&DmaStartRemoteRequest { id: ptr as i32, timestamp: timestamp }); while csr::rtio_dma::enable_read() != 0 {} csr::cri_con::selected_write(0); @@ -427,23 +428,29 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { } } - send(&DmaAwaitRemoteRequest { id: ptr as i32 }); - recv!(&DmaAwaitRemoteReply { timeout, error, channel, timestamp } => { - if timeout { - raise!("DMAError", - "Error running DMA on satellite device, timed out waiting for results"); - } - if error & 1 != 0 { - raise!("RTIOUnderflow", - "RTIO underflow at channel {rtio_channel_info:0}, {1} mu", - channel as i64, timestamp as i64, 0); - } - if error & 2 != 0 { - raise!("RTIODestinationUnreachable", - "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu", - channel as i64, timestamp as i64, 0); - } - }); + #[cfg(has_drtio)] + { + send(&DmaAwaitRemoteRequest { id: ptr as i32 }); + recv!(&DmaAwaitRemoteReply { timeout, error, channel, timestamp } => { + if timeout { + println!("timeout\n"); + raise!("DMAError", + "Error running DMA on satellite device, timed out waiting for results"); + } + if error & 1 != 0 { + println!("rtio underflow from ddma\n"); + raise!("RTIOUnderflow", + "RTIO underflow at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp as i64, 0); + } + if error & 2 != 0 { + println!("rtio destun from ddma\n"); + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp as i64, 0); + } + }); + } } #[cfg(not(has_rtio_dma))] diff --git a/artiq/firmware/runtime/rtio_dma.rs b/artiq/firmware/runtime/rtio_dma.rs index 1ec15384e..d388d9bfc 100644 --- a/artiq/firmware/runtime/rtio_dma.rs +++ b/artiq/firmware/runtime/rtio_dma.rs @@ -218,12 +218,13 @@ impl Manager { self.recording_trace.extend_from_slice(data) } - pub fn record_stop(&mut self, duration: u64, enable_ddma: bool, + pub fn record_stop(&mut self, duration: u64, _enable_ddma: bool, _io: &Io, _ddma_mutex: &Mutex) -> u32 { let mut local_trace = Vec::new(); - let mut remote_traces: BTreeMap> = BTreeMap::new(); + let mut _remote_traces: BTreeMap> = BTreeMap::new(); - if enable_ddma { + #[cfg(has_drtio)] + if _enable_ddma { let mut trace = Vec::new(); mem::swap(&mut self.recording_trace, &mut trace); trace.push(0); @@ -239,10 +240,10 @@ impl Manager { local_trace.extend(&trace[ptr..ptr+len]); } else { - if let Some(remote_trace) = remote_traces.get_mut(&destination) { + if let Some(remote_trace) = _remote_traces.get_mut(&destination) { remote_trace.extend(&trace[ptr..ptr+len]); } else { - remote_traces.insert(destination, trace[ptr..ptr+len].to_vec()); + _remote_traces.insert(destination, trace[ptr..ptr+len].to_vec()); } } // and jump to the next event @@ -278,7 +279,7 @@ impl Manager { self.name_map.insert(name, id); #[cfg(has_drtio)] - remote_dma::add_traces(_io, _ddma_mutex, id, remote_traces); + remote_dma::add_traces(_io, _ddma_mutex, id, _remote_traces); id } From 696bda5c035912e0aa5c7ec7b1efe04ccc237e68 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 28 Mar 2023 11:22:02 +0800 Subject: [PATCH 04/23] handle playback status in aux_transact --- artiq/firmware/runtime/kern_hwreq.rs | 63 ++++++++++---------- artiq/firmware/runtime/main.rs | 3 +- artiq/firmware/runtime/moninj.rs | 31 +++++----- artiq/firmware/runtime/rtio_dma.rs | 11 ++-- artiq/firmware/runtime/rtio_mgt.rs | 89 ++++++++++++++-------------- artiq/firmware/runtime/session.rs | 4 +- 6 files changed, 101 insertions(+), 100 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 952a18439..b178d8e29 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -14,8 +14,8 @@ mod remote_i2c { use rtio_mgt::drtio; use sched::{Io, Mutex}; - pub fn start(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), &'static str> { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStartRequest { + pub fn start(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), &'static str> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::I2cStartRequest { destination: destination, busno: busno }); @@ -34,8 +34,8 @@ mod remote_i2c { } } - pub fn restart(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), &'static str> { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cRestartRequest { + pub fn restart(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), &'static str> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::I2cRestartRequest { destination: destination, busno: busno }); @@ -54,8 +54,8 @@ mod remote_i2c { } } - pub fn stop(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), &'static str> { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStopRequest { + pub fn stop(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), &'static str> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::I2cStopRequest { destination: destination, busno: busno }); @@ -74,8 +74,8 @@ mod remote_i2c { } } - pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u8) -> Result { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cWriteRequest { + pub fn write(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u8) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::I2cWriteRequest { destination: destination, busno: busno, data: data @@ -95,8 +95,8 @@ mod remote_i2c { } } - pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cReadRequest { + pub fn read(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::I2cReadRequest { destination: destination, busno: busno, ack: ack @@ -116,8 +116,8 @@ mod remote_i2c { } } - pub fn switch_select(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, address: u8, mask: u8) -> Result<(), &'static str> { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cSwitchSelectRequest { + pub fn switch_select(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, address: u8, mask: u8) -> Result<(), &'static str> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::I2cSwitchSelectRequest { destination: destination, busno: busno, address: address, @@ -145,8 +145,8 @@ mod remote_spi { use rtio_mgt::drtio; use sched::{Io, Mutex}; - pub fn set_config(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiSetConfigRequest { + pub fn set_config(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::SpiSetConfigRequest { destination: destination, busno: busno, flags: flags, @@ -169,8 +169,8 @@ mod remote_spi { } } - pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiWriteRequest { + pub fn write(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::SpiWriteRequest { destination: destination, busno: busno, data: data @@ -190,8 +190,8 @@ mod remote_spi { } } - pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiReadRequest { + pub fn read(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::SpiReadRequest { destination: destination, busno: busno }); @@ -214,7 +214,7 @@ mod remote_spi { #[cfg(has_drtio)] macro_rules! dispatch { - ($io:ident, $aux_mutex:ident, $mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $ddma_mutex:ident, $mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ let destination = ($busno >> 16) as u8; let busno = $busno as u8; let hop = $routing_table.0[destination as usize][0]; @@ -222,27 +222,28 @@ macro_rules! dispatch { $mod_local::$func(busno, $($param, )*) } else { let linkno = hop - 1; - $mod_remote::$func($io, $aux_mutex, linkno, destination, busno, $($param, )*) + $mod_remote::$func($io, $aux_mutex, $ddma_mutex, linkno, destination, busno, $($param, )*) } }} } #[cfg(not(has_drtio))] macro_rules! dispatch { - ($io:ident, $aux_mutex:ident,$mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $ddma_mutex:ident, $mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ let busno = $busno as u8; $mod_local::$func(busno, $($param, )*) }} } pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex, + ddma_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, _up_destinations: &Urc>, request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { info!("resetting RTIO"); - rtio_mgt::reset(io, aux_mutex); + rtio_mgt::reset(io, aux_mutex, ddma_mutex); kern_acknowledge() } @@ -258,47 +259,47 @@ pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex, } &kern::I2cStartRequest { busno } => { - let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); + let succeeded = dispatch!(io, aux_mutex, ddma_mutex, local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cRestartRequest { busno } => { - let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); + let succeeded = dispatch!(io, aux_mutex, ddma_mutex, local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cStopRequest { busno } => { - let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); + let succeeded = dispatch!(io, aux_mutex, ddma_mutex, local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cWriteRequest { busno, data } => { - match dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, write, data) { + match dispatch!(io, aux_mutex, ddma_mutex, local_i2c, remote_i2c, _routing_table, busno, write, data) { Ok(ack) => kern_send(io, &kern::I2cWriteReply { succeeded: true, ack: ack }), Err(_) => kern_send(io, &kern::I2cWriteReply { succeeded: false, ack: false }) } } &kern::I2cReadRequest { busno, ack } => { - match dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, read, ack) { + match dispatch!(io, aux_mutex, ddma_mutex, local_i2c, remote_i2c, _routing_table, busno, read, ack) { Ok(data) => kern_send(io, &kern::I2cReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff }) } } &kern::I2cSwitchSelectRequest { busno, address, mask } => { - let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, ddma_mutex, local_i2c, remote_i2c, _routing_table, busno, switch_select, address, mask).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { - let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, ddma_mutex, local_spi, remote_spi, _routing_table, busno, set_config, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, &kern::SpiWriteRequest { busno, data } => { - let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, ddma_mutex, local_spi, remote_spi, _routing_table, busno, write, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) } &kern::SpiReadRequest { busno } => { - match dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, read) { + match dispatch!(io, aux_mutex, ddma_mutex, local_spi, remote_spi, _routing_table, busno, read) { Ok(data) => kern_send(io, &kern::SpiReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::SpiReadReply { succeeded: false, data: 0 }) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 5c54aeffa..994c9dfc0 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -204,8 +204,9 @@ fn startup() { #[cfg(any(has_rtio_moninj, has_drtio))] { let aux_mutex = aux_mutex.clone(); + let ddma_mutex = ddma_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); - io.spawn(4096, move |io| { moninj::thread(io, &aux_mutex, &drtio_routing_table) }); + io.spawn(4096, move |io| { moninj::thread(io, &aux_mutex, &ddma_mutex, &drtio_routing_table) }); } #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 36d4bbb47..88f6c6aaf 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -53,8 +53,8 @@ mod remote_moninj { use rtio_mgt::drtio; use sched::{Io, Mutex}; - pub fn read_probe(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, probe: u8) -> u64 { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::MonitorRequest { + pub fn read_probe(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, probe: u8) -> u64 { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::MonitorRequest { destination: destination, channel: channel, probe: probe @@ -67,7 +67,7 @@ mod remote_moninj { 0 } - pub fn inject(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { + pub fn inject(io: &Io, aux_mutex: &Mutex, _ddma_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { let _lock = aux_mutex.lock(io).unwrap(); drtioaux::send(linkno, &drtioaux::Packet::InjectionRequest { destination: destination, @@ -77,8 +77,8 @@ mod remote_moninj { }).unwrap(); } - pub fn read_injection_status(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { - let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::InjectionStatusRequest { + pub fn read_injection_status(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::InjectionStatusRequest { destination: destination, channel: channel, overrd: overrd @@ -94,7 +94,7 @@ mod remote_moninj { #[cfg(has_drtio)] macro_rules! dispatch { - ($io:ident, $aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $ddma_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ let destination = ($channel >> 16) as u8; let channel = $channel as u16; let hop = $routing_table.0[destination as usize][0]; @@ -102,20 +102,20 @@ macro_rules! dispatch { local_moninj::$func(channel, $($param, )*) } else { let linkno = hop - 1; - remote_moninj::$func($io, $aux_mutex, linkno, destination, channel, $($param, )*) + remote_moninj::$func($io, $aux_mutex, $ddma_mutex, linkno, destination, channel, $($param, )*) } }} } #[cfg(not(has_drtio))] macro_rules! dispatch { - ($io:ident, $aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $ddma_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ let channel = $channel as u16; local_moninj::$func(channel, $($param, )*) }} } -fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, +fn connection_worker(io: &Io, _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, mut stream: &mut TcpStream) -> Result<(), Error> { let mut probe_watch_list = BTreeMap::new(); let mut inject_watch_list = BTreeMap::new(); @@ -144,9 +144,9 @@ fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing let _ = inject_watch_list.remove(&(channel, overrd)); } }, - HostMessage::Inject { channel, overrd, value } => dispatch!(io, _aux_mutex, _routing_table, channel, inject, overrd, value), + HostMessage::Inject { channel, overrd, value } => dispatch!(io, _aux_mutex, _ddma_mutex, _routing_table, channel, inject, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = dispatch!(io, _aux_mutex, _routing_table, channel, read_injection_status, overrd); + let value = dispatch!(io, _aux_mutex, _ddma_mutex, _routing_table, channel, read_injection_status, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -163,7 +163,7 @@ fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing if clock::get_ms() > next_check { for (&(channel, probe), previous) in probe_watch_list.iter_mut() { - let current = dispatch!(io, _aux_mutex, _routing_table, channel, read_probe, probe); + let current = dispatch!(io, _aux_mutex, _ddma_mutex, _routing_table, channel, read_probe, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, @@ -178,7 +178,7 @@ fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing } } for (&(channel, overrd), previous) in inject_watch_list.iter_mut() { - let current = dispatch!(io, _aux_mutex, _routing_table, channel, read_injection_status, overrd); + let current = dispatch!(io, _aux_mutex, _ddma_mutex, _routing_table, channel, read_injection_status, overrd); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::InjectionStatus { channel: channel, @@ -199,18 +199,19 @@ fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing } } -pub fn thread(io: Io, aux_mutex: &Mutex, routing_table: &Urc>) { +pub fn thread(io: Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, routing_table: &Urc>) { let listener = TcpListener::new(&io, 2047); listener.listen(1383).expect("moninj: cannot listen"); loop { let aux_mutex = aux_mutex.clone(); + let ddma_mutex = ddma_mutex.clone(); let routing_table = routing_table.clone(); let stream = listener.accept().expect("moninj: cannot accept").into_handle(); io.spawn(16384, move |io| { let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match connection_worker(&io, &aux_mutex, &routing_table, &mut stream) { + match connection_worker(&io, &aux_mutex, &ddma_mutex, &routing_table, &mut stream) { Ok(()) => {}, Err(err) => error!("moninj aborted: {}", err) } diff --git a/artiq/firmware/runtime/rtio_dma.rs b/artiq/firmware/runtime/rtio_dma.rs index d388d9bfc..517d1d10b 100644 --- a/artiq/firmware/runtime/rtio_dma.rs +++ b/artiq/firmware/runtime/rtio_dma.rs @@ -95,7 +95,7 @@ pub mod remote_dma { let _lock = ddma_mutex.lock(io).unwrap(); let destinations = unsafe { TRACES.get(&id).unwrap() }; for destination in destinations.keys() { - match drtio::ddma_send_erase(io, aux_mutex, routing_table, id, *destination) { + match drtio::ddma_send_erase(io, aux_mutex, ddma_mutex, routing_table, id, *destination) { Ok(_) => (), Err(e) => error!("Error erasing trace on DMA: {}", e) } @@ -108,7 +108,7 @@ pub mod remote_dma { let _lock = ddma_mutex.lock(io); let traces = unsafe { TRACES.get_mut(&id).unwrap() }; for (destination, mut trace) in traces { - match drtio::ddma_upload_trace(io, aux_mutex, routing_table, id, *destination, trace.get_trace()) + match drtio::ddma_upload_trace(io, aux_mutex, ddma_mutex, routing_table, id, *destination, trace.get_trace()) { Ok(_) => trace.state = RemoteState::Loaded, Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e) @@ -132,7 +132,7 @@ pub mod remote_dma { continue; } } - match drtio::ddma_send_playback(io, aux_mutex, routing_table, ddma_mutex, id, *destination, timestamp) { + match drtio::ddma_send_playback(io, aux_mutex, ddma_mutex, routing_table, id, *destination, timestamp) { Ok(_) => (), Err(e) => error!("Error during remote DMA playback: {}", e) } @@ -159,7 +159,7 @@ pub mod remote_dma { for (id, dest_traces) in traces_iter { if let Some(trace) = dest_traces.get_mut(&destination) { if up { - match drtio::ddma_upload_trace(io, aux_mutex, routing_table, *id, destination, trace.get_trace()) + match drtio::ddma_upload_trace(io, aux_mutex, ddma_mutex, routing_table, *id, destination, trace.get_trace()) { Ok(_) => trace.state = RemoteState::Loaded, Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e) @@ -223,8 +223,7 @@ impl Manager { let mut local_trace = Vec::new(); let mut _remote_traces: BTreeMap> = BTreeMap::new(); - #[cfg(has_drtio)] - if _enable_ddma { + if _enable_ddma & cfg!(has_drtio) { let mut trace = Vec::new(); mem::swap(&mut self.recording_trace, &mut trace); trace.push(0); diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 15a67be75..964c5dc02 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -62,14 +62,23 @@ pub mod drtio { } } - pub fn aux_transact(io: &Io, aux_mutex: &Mutex, - linkno: u8, request: &drtioaux::Packet) -> Result { + pub fn aux_transact(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, + linkno: u8, request: &drtioaux::Packet ) -> Result { let _lock = aux_mutex.lock(io).unwrap(); drtioaux::send(linkno, request).unwrap(); - recv_aux_timeout(io, linkno, 200) + loop { + let reply = recv_aux_timeout(io, linkno, 200); + match reply { + Ok(drtioaux::Packet::DmaPlaybackStatus { id, destination, error, channel, timestamp }) => { + remote_dma::playback_done(io, ddma_mutex, id, destination, error, channel, timestamp); + }, + Ok(packet) => return Ok(packet), + Err(e) => return Err(e) + } + } } - fn ping_remote(io: &Io, aux_mutex: &Mutex, linkno: u8) -> u32 { + fn ping_remote(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8) -> u32 { let mut count = 0; loop { if !link_rx_up(linkno) { @@ -79,7 +88,7 @@ pub mod drtio { if count > 100 { return 0; } - let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::EchoRequest); + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::EchoRequest); match reply { Ok(drtioaux::Packet::EchoReply) => { // make sure receive buffer is drained @@ -115,10 +124,10 @@ pub mod drtio { } } - fn load_routing_table(io: &Io, aux_mutex: &Mutex, linkno: u8, routing_table: &drtio_routing::RoutingTable) - -> Result<(), &'static str> { + fn load_routing_table(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, + linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { - let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::RoutingSetPath { + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, hops: routing_table.0[i] })?; @@ -129,8 +138,8 @@ pub mod drtio { Ok(()) } - fn set_rank(io: &Io, aux_mutex: &Mutex, linkno: u8, rank: u8) -> Result<(), &'static str> { - let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::RoutingSetRank { + fn set_rank(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, linkno: u8, rank: u8) -> Result<(), &'static str> { + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::RoutingSetRank { rank: rank })?; if reply != drtioaux::Packet::RoutingAck { @@ -221,7 +230,7 @@ pub mod drtio { let linkno = hop - 1; if destination_up(up_destinations, destination) { if up_links[linkno as usize] { - let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination }); match reply { @@ -251,7 +260,7 @@ pub mod drtio { } } else { if up_links[linkno as usize] { - let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination }); match reply { @@ -291,17 +300,17 @@ pub mod drtio { /* link was previously down */ if link_rx_up(linkno) { info!("[LINK#{}] link RX became up, pinging", linkno); - let ping_count = ping_remote(&io, aux_mutex, linkno); + let ping_count = ping_remote(&io, aux_mutex, ddma_mutex, linkno); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); up_links[linkno as usize] = true; if let Err(e) = sync_tsc(&io, aux_mutex, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } - if let Err(e) = load_routing_table(&io, aux_mutex, linkno, routing_table) { + if let Err(e) = load_routing_table(&io, aux_mutex, ddma_mutex, linkno, routing_table) { error!("[LINK#{}] failed to load routing table ({})", linkno, e); } - if let Err(e) = set_rank(&io, aux_mutex, linkno, 1) { + if let Err(e) = set_rank(&io, aux_mutex, ddma_mutex, linkno, 1) { error!("[LINK#{}] failed to set rank ({})", linkno, e); } info!("[LINK#{}] link initialization completed", linkno); @@ -316,7 +325,7 @@ pub mod drtio { } } - pub fn reset(io: &Io, aux_mutex: &Mutex) { + pub fn reset(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex) { for linkno in 0..csr::DRTIO.len() { unsafe { (csr::DRTIO[linkno].reset_write)(1); @@ -332,7 +341,7 @@ pub mod drtio { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; if link_rx_up(linkno) { - let reply = aux_transact(io, aux_mutex, linkno, + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::ResetRequest); match reply { Ok(drtioaux::Packet::ResetAck) => (), @@ -343,7 +352,7 @@ pub mod drtio { } } - pub fn ddma_upload_trace(io: &Io, aux_mutex: &Mutex, + pub fn ddma_upload_trace(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, id: u32, destination: u8, trace: &Vec) -> Result<(), &'static str> { let linkno = routing_table.0[destination as usize][0] - 1; @@ -354,7 +363,7 @@ pub mod drtio { let last = i + len == trace.len(); trace_slice[..len].clone_from_slice(&trace[i..i+len]); i += len; - let reply = aux_transact(io, aux_mutex, linkno, + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::DmaAddTraceRequest { id: id, destination: destination, last: last, length: len as u16, trace: trace_slice}); match reply { @@ -369,45 +378,35 @@ pub mod drtio { } - pub fn ddma_send_erase(io: &Io, aux_mutex: &Mutex, + pub fn ddma_send_erase(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, id: u32, destination: u8) -> Result<(), &'static str> { let linkno = routing_table.0[destination as usize][0] - 1; - let reply = aux_transact(io, aux_mutex, linkno, + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::DmaRemoveTraceRequest { id: id, destination: destination }); match reply { Ok(drtioaux::Packet::DmaRemoveTraceReply { succeeded: true }) => Ok(()), Ok(drtioaux::Packet::DmaRemoveTraceReply { succeeded: false }) => Err("satellite DMA erase error"), - Ok(_) => Err("adding trace failed, unexpected aux packet"), + Ok(_) => Err("erasing trace failed, unexpected aux packet"), Err(_) => Err("erasing trace failed, aux error") } } - pub fn ddma_send_playback(io: &Io, aux_mutex: &Mutex, + pub fn ddma_send_playback(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, - ddma_mutex: &Mutex, id: u32, destination: u8, timestamp: u64) -> Result<(), &'static str> { + id: u32, destination: u8, timestamp: u64) -> Result<(), &'static str> { let linkno = routing_table.0[destination as usize][0] - 1; - let _lock = aux_mutex.lock(io).unwrap(); - drtioaux::send(linkno, &drtioaux::Packet::DmaPlaybackRequest{ - id: id, destination: destination, timestamp: timestamp }).unwrap(); - loop { - let reply = recv_aux_timeout(io, linkno, 200); - match reply { - Ok(drtioaux::Packet::DmaPlaybackReply { succeeded: true }) => { return Ok(()) }, - Ok(drtioaux::Packet::DmaPlaybackReply { succeeded: false }) => { - return Err("error on DMA playback request") }, - // in case we received status from another destination - // but we want to get DmaPlaybackReply anyway, thus the loop - Ok(drtioaux::Packet::DmaPlaybackStatus { id, destination, error, channel, timestamp }) => { - remote_dma::playback_done(io, ddma_mutex, id, destination, error, channel, timestamp); - }, - Ok(_) => { return Err("received unexpected aux packet while DMA playback") }, - Err(_) => { return Err("aux error on DMA playback") } - } + let reply = aux_transact(io, aux_mutex, ddma_mutex, linkno, &drtioaux::Packet::DmaPlaybackRequest{ + id: id, destination: destination, timestamp: timestamp }); + match reply { + Ok(drtioaux::Packet::DmaPlaybackReply { succeeded: true }) => return Ok(()), + Ok(drtioaux::Packet::DmaPlaybackReply { succeeded: false }) => + return Err("error on DMA playback request"), + Ok(_) => return Err("received unexpected aux packet during DMA playback"), + Err(_) => return Err("aux error on DMA playback") } } - } #[cfg(not(has_drtio))] @@ -418,7 +417,7 @@ pub mod drtio { _routing_table: &Urc>, _up_destinations: &Urc>, _ddma_mutex: &Mutex) {} - pub fn reset(_io: &Io, _aux_mutex: &Mutex) {} + pub fn reset(_io: &Io, _aux_mutex: &Mutex, _ddma_mutex: &Mutex) {} } static mut SEEN_ASYNC_ERRORS: u8 = 0; @@ -501,9 +500,9 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, io.spawn(4096, async_error_thread); } -pub fn reset(io: &Io, aux_mutex: &Mutex) { +pub fn reset(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex) { unsafe { csr::rtio_core::reset_write(1); } - drtio::reset(io, aux_mutex) + drtio::reset(io, aux_mutex, ddma_mutex) } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 04ef42864..2096dcc94 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -349,7 +349,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, aux_mutex, routing_table, up_destinations, request)? { + if kern_hwreq::process_kern_hwreq(io, aux_mutex, ddma_mutex, routing_table, up_destinations, request)? { return Ok(false) } @@ -384,7 +384,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, &kern::DmaRecordStop { duration, enable_ddma } => { let _id = session.congress.dma_manager.record_stop(duration, enable_ddma, io, ddma_mutex); #[cfg(has_drtio)] - { + if enable_ddma { remote_dma::upload_traces(io, aux_mutex, routing_table, ddma_mutex, _id); } cache::flush_l2_cache(); From b225717ddbd038f40af5d3b875a5cebcda622098 Mon Sep 17 00:00:00 2001 From: Spaqin Date: Wed, 29 Mar 2023 13:46:33 +0800 Subject: [PATCH 05/23] DDMA: documentation --- RELEASE_NOTES.rst | 2 ++ artiq/coredevice/dma.py | 6 ++++-- doc/manual/getting_started_core.rst | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 8ccbc3347..590ade183 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -23,6 +23,8 @@ Highlights: support legacy installations, but may be removed in a future release. * Added channel names to RTIO errors. * Full Python 3.10 support. +* Distributed DMA is now supported, allowing DMA to be run directly on satellites for corresponding + RTIO events, increasing bandwidth in scenarios with heavy satellite usage. ARTIQ-7 ------- diff --git a/artiq/coredevice/dma.py b/artiq/coredevice/dma.py index 72e0f4a08..ff4aa01cb 100644 --- a/artiq/coredevice/dma.py +++ b/artiq/coredevice/dma.py @@ -79,10 +79,12 @@ class CoreDMA: """Returns a context manager that will record a DMA trace called ``name``. Any previously recorded trace with the same name is overwritten. The trace will persist across kernel switches. - In DRTIO context, you can toggle distributed DMA with ``enable_ddma``. + + In DRTIO context, distributed DMA can be toggled with ``enable_ddma``. Enabling it allows running DMA on satellites, rather than sending all events from the master. - Disabling it may improve performance in some scenarios, + + Keeping it disabled it may improve performance in some scenarios, e.g. when there are many small satellite buffers.""" self.epoch += 1 self.recorder.name = name diff --git a/doc/manual/getting_started_core.rst b/doc/manual/getting_started_core.rst index a17e0633e..5b7cab0e5 100644 --- a/doc/manual/getting_started_core.rst +++ b/doc/manual/getting_started_core.rst @@ -243,3 +243,27 @@ Try this: :: # execute RTIO operations in the DMA buffer # each playback advances the timeline by 50*(100+100) ns self.core_dma.playback_handle(pulses_handle) + +Distributed Direct Memory Access (DDMA) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default on DRTIO systems, all events recorded by the DMA core are kept and played back on the master. + +With distributed DMA, RTIO events that should be played back on remote destinations, are distributed to the corresponding satellites. In some cases (typically, large buffers on several satellites with high event throughput), it allows for better performance and higher bandwidth, as the RTIO events do not have to be sent over the DRTIO link(s) during playback. + +To enable distributed DMA, simply provide an ``enable_ddma=True`` argument for the :meth:`~artiq.coredevice.dma.CoreDMA.record` method - taking a snippet from the previous example: :: + + @kernel + def record(self): + with self.core_dma.record("pulses", enable_ddma=True): + # all RTIO operations now go to the "pulses" + # DMA buffer, instead of being executed immediately. + for i in range(50): + self.ttl0.pulse(100*ns) + delay(100*ns) + +This argument is ignored on standalone systems, as it does not apply there. + +Enabling DDMA on a purely local sequence on a DRTIO system introduces an overhead during trace recording which comes from additional processing done on the record, so careful use is advised. + +Due to the extra time that communicating with relevant satellites takes, an additional delay before playback may be necessary to prevent a :exc:`~artiq.coredevice.exceptions.RTIOUnderflow` when playing back a DDMA-enabled sequence. \ No newline at end of file From 7ba06bfe61cad4ad41f478188917cac6571a6875 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Sat, 1 Apr 2023 18:30:36 +0900 Subject: [PATCH 06/23] fix typo in comm_analyzer.py error_occured -> error_occurred occured -> occurred --- artiq/coredevice/comm_analyzer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 8024e59bd..09ad3618f 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -102,15 +102,15 @@ def decode_dump(data): # messages are big endian parts = struct.unpack(endian + "IQbbb", data[:15]) (sent_bytes, total_byte_count, - error_occured, log_channel, dds_onehot_sel) = parts + error_occurred, log_channel, dds_onehot_sel) = parts expected_len = sent_bytes + 15 if expected_len != len(data): raise ValueError("analyzer dump has incorrect length " "(got {}, expected {})".format( len(data), expected_len)) - if error_occured: - logger.warning("error occured within the analyzer, " + if error_occurred: + logger.warning("error occurred within the analyzer, " "data may be corrupted") if total_byte_count > sent_bytes: logger.info("analyzer ring buffer has wrapped %d times", From 97161a3df24a749ef95f42c32eca57845c064bc5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 4 Apr 2023 11:27:08 +0800 Subject: [PATCH 07/23] firmware: improve RTIO map error reporting --- artiq/firmware/runtime/rtio_mgt.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 964c5dc02..f0aad09b8 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -456,11 +456,11 @@ fn read_device_map() -> BTreeMap { config::read("device_map", |value: Result<&[u8], config::Error>| { let mut bytes = match value { Ok(val) => if val.len() > 0 { Cursor::new(val) } else { - error!("read_device_map: `device_map` was not found in the config"); + warn!("device map not found in config, device names will not be available in RTIO error messages"); return; }, Err(err) => { - error!("read_device_map: error reading `device_map` from config: {}", err); + warn!("error reading device map ({}), device names will not be available in RTIO error messages", err); return; } }; @@ -469,7 +469,7 @@ fn read_device_map() -> BTreeMap { let channel = bytes.read_u32().unwrap(); let device_name= bytes.read_string().unwrap(); if let Some(old_entry) = device_map.insert(channel, device_name.clone()) { - error!("conflicting entries for channel {}: `{}` and `{}`", + warn!("conflicting device map entries for RTIO channel {}: '{}' and '{}'", channel, old_entry, device_name); } } From dc3db8bb660ad831043f958cd851c07b26e5746e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 7 Apr 2023 16:03:33 +0800 Subject: [PATCH 08/23] afws_client: WebSocket, system certificates --- artiq/frontend/afws_client.py | 40 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/artiq/frontend/afws_client.py b/artiq/frontend/afws_client.py index bf12f4759..21dd92c06 100755 --- a/artiq/frontend/afws_client.py +++ b/artiq/frontend/afws_client.py @@ -13,17 +13,6 @@ from getpass import getpass from tqdm import tqdm -def get_artiq_cert(): - try: - import artiq - except ImportError: - return None - filename = os.path.join(os.path.dirname(artiq.__file__), "afws.pem") - if not os.path.isfile(filename): - return None - return filename - - def get_artiq_rev(): try: import artiq @@ -54,6 +43,7 @@ class Client: def __init__(self, server, port, cafile): self.ssl_context = ssl.create_default_context(cafile=cafile) self.raw_socket = socket.create_connection((server, port)) + self.init_websocket(server) try: self.socket = self.ssl_context.wrap_socket(self.raw_socket, server_hostname=server) except: @@ -61,6 +51,19 @@ class Client: raise self.fsocket = self.socket.makefile("rwb") + def init_websocket(self, server): + self.raw_socket.sendall("GET / HTTP/1.1\r\nHost: {}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n" + .format(server).encode()) + crlf_count = 0 + while crlf_count < 4: + char = self.raw_socket.recv(1) + if not char: + return ValueError("Connection closed during WebSocket initialization") + if char == b"\r" or char == b"\n": + crlf_count += 1 + else: + crlf_count = 0 + def close(self): self.socket.close() self.raw_socket.close() @@ -160,9 +163,9 @@ class Client: def main(): parser = argparse.ArgumentParser() - parser.add_argument("--server", default="nixbld.m-labs.hk", help="server to connect to (default: %(default)s)") - parser.add_argument("--port", default=7402, type=int, help="port to connect to (default: %(default)d)") - parser.add_argument("--cert", default=None, help="SSL certificate file used to authenticate server (default: afws.pem in ARTIQ)") + parser.add_argument("--server", default="afws.m-labs.hk", help="server to connect to (default: %(default)s)") + parser.add_argument("--port", default=80, type=int, help="port to connect to (default: %(default)d)") + parser.add_argument("--cert", default=None, help="SSL certificate file used to authenticate server (default: use system certificates)") parser.add_argument("username", help="user name for logging into AFWS") action = parser.add_subparsers(dest="action") action.required = True @@ -181,19 +184,12 @@ def main(): act_get_json.add_argument("-f", "--force", action="store_true", help="overwrite file if it already exists") args = parser.parse_args() - cert = args.cert - if cert is None: - cert = get_artiq_cert() - if cert is None: - print("SSL certificate not found in ARTIQ. Specify manually using --cert.") - sys.exit(1) - if args.action == "passwd": password = getpass("Current password: ") else: password = getpass() - client = Client(args.server, args.port, cert) + client = Client(args.server, args.port, args.cert) try: if not client.login(args.username, password): print("Login failed") From c1474c134a6e61640a69ff294dcd49ae8aaaae53 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 7 Apr 2023 16:09:47 +0800 Subject: [PATCH 09/23] remove obsolete AFWS certificate --- artiq/afws.pem | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 artiq/afws.pem diff --git a/artiq/afws.pem b/artiq/afws.pem deleted file mode 100644 index cebce3e97..000000000 --- a/artiq/afws.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID0zCCArugAwIBAgIUPkNfEUx/uau3z8SD4mgMbCK/DEgwDQYJKoZIhvcNAQEL -BQAweTELMAkGA1UEBhMCSEsxEzARBgNVBAgMClNvbWUtU3RhdGUxFzAVBgNVBAoM -Dk0tTGFicyBMaW1pdGVkMRkwFwYDVQQDDBBuaXhibGQubS1sYWJzLmhrMSEwHwYJ -KoZIhvcNAQkBFhJoZWxwZGVza0BtLWxhYnMuaGswHhcNMjIwMjA2MTA1ODQ0WhcN -MjUwMjA1MTA1ODQ0WjB5MQswCQYDVQQGEwJISzETMBEGA1UECAwKU29tZS1TdGF0 -ZTEXMBUGA1UECgwOTS1MYWJzIExpbWl0ZWQxGTAXBgNVBAMMEG5peGJsZC5tLWxh -YnMuaGsxITAfBgkqhkiG9w0BCQEWEmhlbHBkZXNrQG0tbGFicy5oazCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAPWetZhoggPR2ae7waGzv1AQ8NQO3noW -8DofVjusNpX5i/YB0waAr1bm1tALLJoHV2r/gTxujlXCe/L/WG1DLseCf6NO9sHg -t0FLhDpF9kPMWBgauVVLepd2Y2yU1G8eFuEVGnsiQSu0IzsZP5FQBJSyxvxJ+V/L -EW9ox91VGOP9VZR9jqdlYjGhcwClHA/nHe0q1fZq42+9rG466I5yIlNSoa7ilhTU -2C2doxy6Sr6VJYnLEMQqoIF65t3MkKi9iaqN7az0OCrj6XR0P5iKBzUhIgMUd2qs -7Id0XUdbQvaoaRI67vhGkNr+f4rdAUNCDGcbbokuBnmE7/gva6BAABUCAwEAAaNT -MFEwHQYDVR0OBBYEFM2e2FmcytXhKyfC1KEjVJ2mPSy3MB8GA1UdIwQYMBaAFM2e -2FmcytXhKyfC1KEjVJ2mPSy3MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAKH0z5vlbfTghjYWwd2yEEFBbZx5XxaLHboFQpFpxu9sZoidVs047tco -MOr1py9juiNGGM8G35sw9306f+thDFwqlQfSExUwp5pRQNq+mxglMSF05HWDqBwb -wnItKi/WXpkMQXgpQJFVeflz4B4ZFNlH1UQl5bwacXOM9NM9zO7duCjVXmGE0yxi -VQyApfPQYu9whCSowDYYaA0toJeikMzGfWxhlAH79/2Qmit8KcSCbX1fK/QoRZLa -5NeUi/OlJbBpkgTrfzfMLphmsPWPAVMeUKzqd/vXfG6ZBOZZm6e6sl8RBycBezII -15WekikTE5+T54/E0xiu+zIW/Xhhk14= ------END CERTIFICATE----- From 757c00b0fe7600f04b08bf72d899306556d1b238 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 8 Apr 2023 16:50:15 +0800 Subject: [PATCH 10/23] afws_client: improve UX of common build errors --- artiq/frontend/afws_client.py | 46 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/artiq/frontend/afws_client.py b/artiq/frontend/afws_client.py index 21dd92c06..49ce122c8 100755 --- a/artiq/frontend/afws_client.py +++ b/artiq/frontend/afws_client.py @@ -184,29 +184,10 @@ def main(): act_get_json.add_argument("-f", "--force", action="store_true", help="overwrite file if it already exists") args = parser.parse_args() - if args.action == "passwd": - password = getpass("Current password: ") - else: - password = getpass() - client = Client(args.server, args.port, args.cert) try: - if not client.login(args.username, password): - print("Login failed") - sys.exit(1) - print("Logged in successfully.") - if args.action == "passwd": - print("Password must made of alphanumeric characters (a-z, A-Z, 0-9) and be at least 8 characters long.") - password = getpass("New password: ") - password_confirm = getpass("New password (again): ") - while password != password_confirm: - print("Passwords do not match") - password = getpass("New password: ") - password_confirm = getpass("New password (again): ") - if not client.passwd(password): - print("Failed to change password") - sys.exit(1) - elif args.action == "build": + if args.action == "build": + # do this before user enters password so errors are reported without unnecessary user action try: os.mkdir(args.directory) except FileExistsError: @@ -229,6 +210,29 @@ def main(): if rev is None: print("Unable to determine currently installed ARTIQ revision. Specify manually using --rev.") sys.exit(1) + + if args.action == "passwd": + password = getpass("Current password: ") + else: + password = getpass() + if not client.login(args.username, password): + print("Login failed") + sys.exit(1) + + print("Logged in successfully.") + if args.action == "passwd": + print("Password must made of alphanumeric characters (a-z, A-Z, 0-9) and be at least 8 characters long.") + password = getpass("New password: ") + password_confirm = getpass("New password (again): ") + while password != password_confirm: + print("Passwords do not match") + password = getpass("New password: ") + password_confirm = getpass("New password (again): ") + if not client.passwd(password): + print("Failed to change password") + sys.exit(1) + elif args.action == "build": + # build dir and version variables set up above result, contents = client.build(major_ver, rev, args.variant, args.log, args.experimental) if result != "OK": if result == "UNAUTHORIZED": From d0b881868832b1f04b75fd2d50a6dbcae3018888 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Thu, 13 Apr 2023 11:06:53 +0800 Subject: [PATCH 11/23] Add 125 MHz from 80 MHz reference option to rtio clocking Signed-off-by: Egor Savkin --- artiq/firmware/runtime/rtio_clocking.rs | 20 ++++++++++++++++++++ doc/manual/core_device.rst | 1 + doc/manual/installing.rst | 5 +++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index f094e5383..cce5d3b7b 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -10,6 +10,7 @@ pub enum RtioClock { Int_100, Ext0_Bypass, Ext0_Synth0_10to125, + Ext0_Synth0_80to125, Ext0_Synth0_100to125, Ext0_Synth0_125to125, } @@ -24,6 +25,7 @@ fn get_rtio_clock_cfg() -> RtioClock { Ok("ext0_bypass_125") => RtioClock::Ext0_Bypass, Ok("ext0_bypass_100") => RtioClock::Ext0_Bypass, Ok("ext0_synth0_10to125") => RtioClock::Ext0_Synth0_10to125, + Ok("ext0_synth0_80to125") => RtioClock::Ext0_Synth0_80to125, Ok("ext0_synth0_100to125") => RtioClock::Ext0_Synth0_100to125, Ok("ext0_synth0_125to125") => RtioClock::Ext0_Synth0_125to125, Ok("i") => { @@ -44,6 +46,8 @@ fn get_rtio_clock_cfg() -> RtioClock { warn!("si5324_ext_ref and ext_ref_frequency compile-time options are deprecated. Please use the rtio_clock coreconfig settings instead."); #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "10.0"))] return RtioClock::Ext0_Synth0_10to125; + #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "80.0"))] + return RtioClock::Ext0_Synth0_80to125; #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "100.0"))] return RtioClock::Ext0_Synth0_100to125; #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "125.0"))] @@ -110,6 +114,22 @@ fn setup_si5324_pll(cfg: RtioClock) { SI5324_EXT_INPUT ) }, + RtioClock::Ext0_Synth0_80to125 => { // 125 MHz output from 80 MHz CLKINx reference, 611 Hz BW + info!("using 80MHz reference to make 125MHz RTIO clock with PLL"); + ( + si5324::FrequencySettings { + n1_hs : 4, + nc1_ls : 10, + n2_hs : 10, + n2_ls : 250, + n31 : 40, + n32 : 40, + bwsel : 4, + crystal_as_ckin2: false + }, + SI5324_EXT_INPUT + ) + }, RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth info!("using 100MHz reference to make 125MHz RTIO clock with PLL"); ( diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 6ba064e52..24e9768c0 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -175,6 +175,7 @@ KC705 in DRTIO variants and Kasli generates the RTIO clock using a PLL locked ei * ``int_100`` - internal crystal oscillator using PLL, 100 MHz output, * ``int_150`` - internal crystal oscillator using PLL, 150 MHz output, * ``ext0_synth0_10to125`` - external 10 MHz reference using PLL, 125 MHz output, + * ``ext0_synth0_80to125`` - external 80 MHz reference using PLL, 125 MHz output, * ``ext0_synth0_100to125`` - external 100 MHz reference using PLL, 125 MHz output, * ``ext0_synth0_125to125`` - external 125 MHz reference using PLL, 125 MHz output, * ``ext0_bypass``, ``ext0_bypass_125``, ``ext0_bypass_100`` - external clock - with explicit aliases available. diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 002cb4004..dcf079949 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -343,8 +343,9 @@ The KC705 may use either an external clock signal, or its internal clock with ex Other options include: - ``ext0_synth0_10to125`` - external 10MHz reference clock used by Si5324 to synthesize a 125MHz RTIO clock, - - ``ext0_synth0_100to125`` - exteral 100MHz reference clock used by Si5324 to synthesize a 125MHz RTIO clock, - - ``ext0_synth0_125to125`` - exteral 125MHz reference clock used by Si5324 to synthesize a 125MHz RTIO clock, + - ``ext0_synth0_80to125`` - external 80MHz reference clock used by Si5324 to synthesize a 125MHz RTIO clock, + - ``ext0_synth0_100to125`` - external 100MHz reference clock used by Si5324 to synthesize a 125MHz RTIO clock, + - ``ext0_synth0_125to125`` - external 125MHz reference clock used by Si5324 to synthesize a 125MHz RTIO clock, - ``int_100`` - internal crystal reference is used by Si5324 to synthesize a 100MHz RTIO clock, - ``int_150`` - internal crystal reference is used by Si5324 to synthesize a 150MHz RTIO clock. - ``ext0_bypass_125`` and ``ext0_bypass_100`` - explicit aliases for ``ext0_bypass``. From 8984f5104a7c443661010a6f2c5acad2485e19de Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Thu, 30 Mar 2023 16:35:00 +0800 Subject: [PATCH 12/23] Move RTIO errors formatting to the session_proto This would be closer to the artiq-zynq implementation Signed-off-by: Egor Savkin --- .../firmware/libproto_artiq/session_proto.rs | 34 +++++++++++++++++-- artiq/firmware/runtime/rtio_mgt.rs | 22 +++--------- artiq/firmware/runtime/session.rs | 29 ++-------------- 3 files changed, 38 insertions(+), 47 deletions(-) diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 523331416..d4277c26c 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -1,10 +1,14 @@ -use core::str::Utf8Error; -use alloc::vec::Vec; +use core::{str, str::Utf8Error, slice}; +use alloc::{vec::Vec, format, collections::BTreeMap, string::String}; use eh::eh_artiq::{Exception, StackPointerBacktrace}; use cslice::CSlice; use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError, ReadStringError}; +pub type DeviceMap = BTreeMap; + +static mut RTIO_DEVICE_MAP: Option = None; + #[derive(Fail, Debug)] pub enum Error { #[fail(display = "incorrect magic")] @@ -190,7 +194,14 @@ impl<'a> Reply<'a> { for exception in exceptions.iter() { let exception = exception.as_ref().unwrap(); writer.write_u32(exception.id as u32)?; - write_exception_string(writer, &exception.message)?; + if exception.message.len() == usize::MAX { + // exception with host string + write_exception_string(writer, &exception.message)?; + } else { + let msg = str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) }).unwrap() + .replace("{rtio_channel_info:0}", &format!("0x{:04x}:{}", exception.param[0], resolve_channel_name(exception.param[0] as u32))); + write_exception_string(writer, unsafe { &CSlice::new(msg.as_ptr(), msg.len()) })?; + } writer.write_u64(exception.param[0] as u64)?; writer.write_u64(exception.param[1] as u64)?; writer.write_u64(exception.param[2] as u64)?; @@ -226,3 +237,20 @@ impl<'a> Reply<'a> { Ok(()) } } + +pub fn set_device_map(device_map: DeviceMap) { + unsafe { RTIO_DEVICE_MAP = Some(device_map); } +} + +fn _resolve_channel_name(channel: u32, device_map: &Option) -> String { + if let Some(dev_map) = device_map { + match dev_map.get(&channel) { + Some(val) => val.clone(), + None => String::from("unknown") + } + } else { String::from("unknown") } +} + +pub fn resolve_channel_name(channel: u32) -> String { + _resolve_channel_name(channel, unsafe{&RTIO_DEVICE_MAP}) +} diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f0aad09b8..6b864c128 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,5 +1,3 @@ -use alloc::collections::BTreeMap; -use alloc::string::String; use core::cell::RefCell; use urc::Urc; use board_misoc::{csr, config}; @@ -9,12 +7,11 @@ use board_artiq::drtio_routing; use sched::Io; use sched::Mutex; use io::{Cursor, ProtoRead}; +use session_proto::{DeviceMap, resolve_channel_name, set_device_map}; const ASYNC_ERROR_COLLISION: u8 = 1 << 0; const ASYNC_ERROR_BUSY: u8 = 1 << 1; const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2; -static mut RTIO_DEVICE_MAP: BTreeMap = BTreeMap::new(); - #[cfg(has_drtio)] pub mod drtio { use super::*; @@ -451,8 +448,8 @@ fn async_error_thread(io: Io) { } } -fn read_device_map() -> BTreeMap { - let mut device_map: BTreeMap = BTreeMap::new(); +fn read_device_map() -> DeviceMap { + let mut device_map: DeviceMap = DeviceMap::new(); config::read("device_map", |value: Result<&[u8], config::Error>| { let mut bytes = match value { Ok(val) => if val.len() > 0 { Cursor::new(val) } else { @@ -477,22 +474,11 @@ fn read_device_map() -> BTreeMap { device_map } -fn _resolve_channel_name(channel: u32, device_map: &BTreeMap) -> String { - match device_map.get(&channel) { - Some(val) => val.clone(), - None => String::from("unknown") - } -} - -pub fn resolve_channel_name(channel: u32) -> String { - _resolve_channel_name(channel, unsafe{&RTIO_DEVICE_MAP}) -} - pub fn startup(io: &Io, aux_mutex: &Mutex, routing_table: &Urc>, up_destinations: &Urc>, ddma_mutex: &Mutex) { - unsafe { RTIO_DEVICE_MAP = read_device_map(); } + set_device_map(read_device_map()); drtio::startup(io, aux_mutex, routing_table, up_destinations, ddma_mutex); unsafe { csr::rtio_core::reset_phy_write(1); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 2096dcc94..f99f08ae6 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -1,4 +1,4 @@ -use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite, slice}; +use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; use alloc::{vec::Vec, string::String}; use byteorder::{ByteOrder, NativeEndian}; use cslice::CSlice; @@ -12,7 +12,7 @@ use rtio_clocking; use rtio_dma::Manager as DmaManager; #[cfg(has_drtio)] use rtio_dma::remote_dma; -use rtio_mgt::{get_async_errors, resolve_channel_name}; +use rtio_mgt::get_async_errors; use cache::Cache; use kern_hwreq; use board_artiq::drtio_routing; @@ -484,29 +484,6 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, session.kernel_state = KernelState::Absent; unsafe { session.congress.cache.unborrow() } - let exceptions_with_channel: Vec> = exceptions.iter() - .map(|exception| { - if let Some(exn) = exception { - if exn.message.len() == usize::MAX { // host string - Some(exn.clone()) - } else { - let msg = str::from_utf8(unsafe { slice::from_raw_parts(exn.message.as_ptr(), exn.message.len()) }) - .unwrap() - .replace("{rtio_channel_info:0}", &format!("0x{:04x}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32))); - Some(eh::eh_artiq::Exception { - id: exn.id, - file: exn.file, - line: exn.line, - column: exn.column, - function: exn.function, - message: unsafe { CSlice::new(msg.as_ptr(), msg.len()) }, - param: exn.param, - }) - } - } else { None } - }) - .collect(); - match stream { None => { error!("exception in flash kernel"); @@ -517,7 +494,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, }, Some(ref mut stream) => { host_write(stream, host::Reply::KernelException { - exceptions: &exceptions_with_channel, + exceptions: exceptions, stack_pointers: stack_pointers, backtrace: backtrace, async_errors: unsafe { get_async_errors() } From b5d9062ba90bba13c2341d495be1a675c80a3107 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Fri, 31 Mar 2023 11:18:23 +0800 Subject: [PATCH 13/23] Fix AD9914 channel map Signed-off-by: Egor Savkin --- artiq/coredevice/ad9914.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 9466b90d8..2fde49f2c 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -81,8 +81,11 @@ class AD9914: self.exit_x_duration_mu = 3 * self.write_duration_mu @staticmethod - def get_rtio_channels(bus_channel, **kwargs): - return [(bus_channel, None)] + def get_rtio_channels(bus_channel, channel, **kwargs): + # return only first entry, as there are several devices with the same RTIO channel + if channel == 0: + return [(bus_channel, None)] + return [] @kernel def write(self, addr, data): From 918d30b90072d4c1afbdf17215f24d15edc09e62 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 14 Apr 2023 14:41:34 +0800 Subject: [PATCH 14/23] dma: pass "uses_ddma" for non-remote recordings --- artiq/coredevice/dma.py | 16 +++++++------- artiq/firmware/ksupport/lib.rs | 21 ++++++++++--------- artiq/firmware/libproto_artiq/kernel_proto.rs | 1 + artiq/firmware/runtime/rtio_dma.rs | 6 ++++++ artiq/firmware/runtime/session.rs | 14 ++++++++++--- 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/artiq/coredevice/dma.py b/artiq/coredevice/dma.py index ff4aa01cb..9868b7fdd 100644 --- a/artiq/coredevice/dma.py +++ b/artiq/coredevice/dma.py @@ -25,11 +25,11 @@ def dma_erase(name: TStr) -> TNone: raise NotImplementedError("syscall not simulated") @syscall -def dma_retrieve(name: TStr) -> TTuple([TInt64, TInt32]): +def dma_retrieve(name: TStr) -> TTuple([TInt64, TInt32, TBool]): raise NotImplementedError("syscall not simulated") @syscall -def dma_playback(timestamp: TInt64, ptr: TInt32) -> TNone: +def dma_playback(timestamp: TInt64, ptr: TInt32, enable_ddma: TBool) -> TNone: raise NotImplementedError("syscall not simulated") @@ -101,24 +101,24 @@ class CoreDMA: def playback(self, name): """Replays a previously recorded DMA trace. This function blocks until the entire trace is submitted to the RTIO FIFOs.""" - (advance_mu, ptr) = dma_retrieve(name) - dma_playback(now_mu(), ptr) + (advance_mu, ptr, uses_ddma) = dma_retrieve(name) + dma_playback(now_mu(), ptr, uses_ddma) delay_mu(advance_mu) @kernel def get_handle(self, name): """Returns a handle to a previously recorded DMA trace. The returned handle is only valid until the next call to :meth:`record` or :meth:`erase`.""" - (advance_mu, ptr) = dma_retrieve(name) - return (self.epoch, advance_mu, ptr) + (advance_mu, ptr, uses_ddma) = dma_retrieve(name) + return (self.epoch, advance_mu, ptr, uses_ddma) @kernel def playback_handle(self, handle): """Replays a handle obtained with :meth:`get_handle`. Using this function is much faster than :meth:`playback` for replaying a set of traces repeatedly, but incurs the overhead of managing the handles onto the programmer.""" - (epoch, advance_mu, ptr) = handle + (epoch, advance_mu, ptr, uses_ddma) = handle if self.epoch != epoch: raise DMAError("Invalid handle") - dma_playback(now_mu(), ptr) + dma_playback(now_mu(), ptr, uses_ddma) delay_mu(advance_mu) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 6693b7196..0c949f2b2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -371,7 +371,8 @@ extern fn dma_erase(name: &CSlice) { #[repr(C)] struct DmaTrace { duration: i64, - address: i32 + address: i32, + uses_ddma: bool, } #[unwind(allowed)] @@ -379,11 +380,12 @@ extern fn dma_retrieve(name: &CSlice) -> DmaTrace { let name = str::from_utf8(name.as_ref()).unwrap(); send(&DmaRetrieveRequest { name: name }); - recv!(&DmaRetrieveReply { trace, duration } => { + recv!(&DmaRetrieveReply { trace, duration, uses_ddma } => { match trace { Some(bytes) => Ok(DmaTrace { address: bytes.as_ptr() as i32, - duration: duration as i64 + duration: duration as i64, + uses_ddma: uses_ddma, }), None => Err(()) } @@ -396,7 +398,7 @@ extern fn dma_retrieve(name: &CSlice) -> DmaTrace { #[cfg(has_rtio_dma)] #[unwind(allowed)] -extern fn dma_playback(timestamp: i64, ptr: i32) { +extern fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) { assert!(ptr % 64 == 0); unsafe { @@ -406,7 +408,9 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { csr::cri_con::selected_write(1); csr::rtio_dma::enable_write(1); #[cfg(has_drtio)] - send(&DmaStartRemoteRequest { id: ptr as i32, timestamp: timestamp }); + if _uses_ddma { + send(&DmaStartRemoteRequest { id: ptr as i32, timestamp: timestamp }); + } while csr::rtio_dma::enable_read() != 0 {} csr::cri_con::selected_write(0); @@ -429,22 +433,19 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { } #[cfg(has_drtio)] - { + if _uses_ddma { send(&DmaAwaitRemoteRequest { id: ptr as i32 }); recv!(&DmaAwaitRemoteReply { timeout, error, channel, timestamp } => { if timeout { - println!("timeout\n"); raise!("DMAError", "Error running DMA on satellite device, timed out waiting for results"); } if error & 1 != 0 { - println!("rtio underflow from ddma\n"); raise!("RTIOUnderflow", "RTIO underflow at channel {rtio_channel_info:0}, {1} mu", channel as i64, timestamp as i64, 0); } if error & 2 != 0 { - println!("rtio destun from ddma\n"); raise!("RTIODestinationUnreachable", "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu", channel as i64, timestamp as i64, 0); @@ -455,7 +456,7 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { #[cfg(not(has_rtio_dma))] #[unwind(allowed)] -extern fn dma_playback(_timestamp: i64, _ptr: i32) { +extern fn dma_playback(_timestamp: i64, _ptr: i32, _uses_ddma: bool) { unimplemented!("not(has_rtio_dma)") } diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index e723ea2f5..cc17147cd 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -34,6 +34,7 @@ pub enum Message<'a> { DmaRetrieveReply { trace: Option<&'a [u8]>, duration: u64, + uses_ddma: bool, }, DmaStartRemoteRequest { diff --git a/artiq/firmware/runtime/rtio_dma.rs b/artiq/firmware/runtime/rtio_dma.rs index 517d1d10b..c057edaeb 100644 --- a/artiq/firmware/runtime/rtio_dma.rs +++ b/artiq/firmware/runtime/rtio_dma.rs @@ -17,6 +17,7 @@ pub mod remote_dma { Loaded, PlaybackEnded { error: u8, channel: u32, timestamp: u64 } } + #[derive(Debug, Clone)] struct RemoteTrace { trace: Vec, @@ -169,7 +170,12 @@ pub mod remote_dma { } } } + } + pub fn has_remote_traces(io: &Io, ddma_mutex: &Mutex, id: u32) -> bool { + let _lock = ddma_mutex.lock(io).unwrap(); + let trace_list = unsafe { TRACES.get(&id).unwrap() }; + !trace_list.is_empty() } } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index f99f08ae6..95b3ca28f 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -146,9 +146,9 @@ fn host_write(writer: &mut W, reply: host::Reply) -> Result<(), IoError Result<(), Error> { match request { &kern::LoadRequest(_) => debug!("comm->kern LoadRequest(...)"), - &kern::DmaRetrieveReply { trace, duration } => { + &kern::DmaRetrieveReply { trace, duration, uses_ddma } => { if trace.map(|data| data.len() > 100).unwrap_or(false) { - debug!("comm->kern DmaRetrieveReply {{ trace: ..., duration: {:?} }}", duration) + debug!("comm->kern DmaRetrieveReply {{ trace: ..., duration: {:?}, uses_ddma: {} }}", duration, uses_ddma) } else { debug!("comm->kern {:?}", request) } @@ -400,9 +400,17 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, } &kern::DmaRetrieveRequest { name } => { session.congress.dma_manager.with_trace(name, |trace, duration| { + #[cfg(has_drtio)] + let uses_ddma = match trace { + Some(trace) => remote_dma::has_remote_traces(io, aux_mutex, trace.as_ptr() as u32), + None => false + }; + #[cfg(not(has_drtio))] + let uses_ddma = false; kern_send(io, &kern::DmaRetrieveReply { trace: trace, - duration: duration + duration: duration, + uses_ddma: uses_ddma, }) }) } From aed47d79ff9fc63f49d0a3371c16a1c7e6ddcafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Tue, 18 Apr 2023 15:03:06 +0800 Subject: [PATCH 15/23] master: add terminate API --- artiq/frontend/artiq_client.py | 10 +++++++++- artiq/frontend/artiq_master.py | 13 +++++++++++-- flake.lock | 6 +++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index 8601fed77..03eca3887 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -125,6 +125,9 @@ def get_argparser(): "ls", help="list a directory on the master") parser_ls.add_argument("directory", default="", nargs="?") + subparsers.add_parser( + "terminate", help="terminate the ARTIQ master") + common_args.verbosity_args(parser) return parser @@ -195,6 +198,10 @@ def _action_ls(remote, args): print(name) +def _action_terminate(remote, _args): + remote.terminate() + + def _show_schedule(schedule): clear_screen() if schedule: @@ -319,7 +326,8 @@ def main(): "del_dataset": "master_dataset_db", "scan_devices": "master_device_db", "scan_repository": "master_experiment_db", - "ls": "master_experiment_db" + "ls": "master_experiment_db", + "terminate": "master_terminate", }[action] remote = Client(args.server, port, target_name) try: diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index ced3c828c..05959beb5 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -4,6 +4,7 @@ import asyncio import argparse import atexit import logging +from types import SimpleNamespace from sipyco.pc_rpc import Server as RPCServer from sipyco.sync_struct import Publisher @@ -133,12 +134,16 @@ def main(): }) experiment_db.scan_repository_async(loop=loop) + signal_handler_task = loop.create_task(signal_handler.wait_terminate()) + master_terminate = SimpleNamespace(terminate=lambda: signal_handler_task.cancel()) + server_control = RPCServer({ "master_config": config, "master_device_db": device_db, "master_dataset_db": dataset_db, "master_schedule": scheduler, - "master_experiment_db": experiment_db + "master_experiment_db": experiment_db, + "master_terminate": master_terminate }, allow_parallel=True) loop.run_until_complete(server_control.start( bind, args.port_control)) @@ -161,7 +166,11 @@ def main(): atexit_register_coroutine(server_logging.stop, loop=loop) print("ARTIQ master is now ready.") - loop.run_until_complete(signal_handler.wait_terminate()) + try: + loop.run_until_complete(signal_handler_task) + except asyncio.CancelledError: + pass + if __name__ == "__main__": main() diff --git a/flake.lock b/flake.lock index c846559f1..907524a64 100644 --- a/flake.lock +++ b/flake.lock @@ -89,11 +89,11 @@ ] }, "locked": { - "lastModified": 1673433867, - "narHash": "sha256-a7Oq35YoDzPtISbqAsaT+2/v15HZ7G1q0ukXmKWdb7Q=", + "lastModified": 1681290481, + "narHash": "sha256-VEZcGhbtJGonRrrWi31evNDVSerlLjEPL0MZGm9VlB8=", "owner": "m-labs", "repo": "sipyco", - "rev": "38f8f4185d7db6b68bd7f71546da9077b1e2561c", + "rev": "727631ada6e59dc6ef0ad50bfcc376d2ffe805aa", "type": "github" }, "original": { From 2f35869eb14fdf6cf3f44f449131dc11aca97505 Mon Sep 17 00:00:00 2001 From: Spaqin Date: Thu, 20 Apr 2023 15:45:15 +0800 Subject: [PATCH 16/23] satman: fix PMP and L2 flush --- artiq/firmware/satman/main.rs | 3 +-- artiq/firmware/satman/satman.ld | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index fb97b2bdb..3b770a2c0 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -466,8 +466,7 @@ pub extern fn main() -> i32 { unsafe { ALLOC.add_range(&mut _fheap, &mut _eheap); - // stack guard disabled, see https://github.com/m-labs/artiq/issues/2067 - // pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); + pmp::init_stack_guard(&_sstack_guard as *const u8 as usize); } clock::init(); diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index 4834c36a1..f58ef38d8 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -12,6 +12,7 @@ SECTIONS .text : { *(.text .text.*) + . = ALIGN(0x40000); } > main_ram .eh_frame : From 9331911139ea84c1217ed9c91482d19dfb8e9da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Mon, 24 Apr 2023 11:43:24 +0800 Subject: [PATCH 17/23] add tests for client submit functionality --- artiq/test/test_client.py | 91 +++++++++++++++++++++++++++++++++++++++ flake.nix | 4 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 artiq/test/test_client.py diff --git a/artiq/test/test_client.py b/artiq/test/test_client.py new file mode 100644 index 000000000..f3110d150 --- /dev/null +++ b/artiq/test/test_client.py @@ -0,0 +1,91 @@ +"""Tests for artiq_client functionality""" + +import subprocess +import sys +import os +import unittest +from tempfile import TemporaryDirectory +from pygit2 import init_repository, Signature + +EXPERIMENT_CONTENT = """ +from artiq.experiment import * +class EmptyExperiment(EnvExperiment): + def build(self): + pass + def run(self): + print("test content") +""" + +DDB_CONTENT = """ +device_db = {} +""" + + +def get_env(): + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + return env + + +class TestClient(unittest.TestCase): + def setUp(self): + self.tmp_dir = TemporaryDirectory(prefix="test") + self.tmp_empty_dir = TemporaryDirectory(prefix="empty_repo") + self.exp_name = "experiment.py" + self.exp_path = os.path.join(self.tmp_dir.name, self.exp_name) + self.device_db_path = os.path.join(self.tmp_dir.name, "device_db.py") + with open(self.exp_path, "w") as f: + f.write(EXPERIMENT_CONTENT) + with open(self.device_db_path, "w") as f: + f.write(DDB_CONTENT) + + def start_master(self, *args): + self.master = subprocess.Popen([sys.executable, "-m", "artiq.frontend.artiq_master", "--device-db", + self.device_db_path, *args], encoding="utf8", env=get_env(), + text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + while self.master.stdout.readline().strip() != "ARTIQ master is now ready.": + pass + + def check_and_terminate_master(self): + while not ("test content" in self.master.stdout.readline()): + pass + self.run_client("terminate") + self.assertEqual(self.master.wait(), 0) + self.master.stdout.close() + + @staticmethod + def run_client(*args): + subprocess.run([sys.executable, "-m", "artiq.frontend.artiq_client", *args], check=True, + capture_output=True, env=get_env(), text=True, encoding="utf8").check_returncode() + + def test_submit_outside_repo(self): + self.start_master("-r", self.tmp_empty_dir.name) + self.run_client("submit", self.exp_path) + self.check_and_terminate_master() + + def test_submit_by_content(self): + self.start_master("-r", self.tmp_empty_dir.name) + self.run_client("submit", self.exp_path, "--content") + self.check_and_terminate_master() + + def test_submit_by_file_repo(self): + self.start_master("-r", self.tmp_dir.name) + self.run_client("submit", self.exp_name, "-R") + self.check_and_terminate_master() + + def test_submit_by_git_repo(self): + repo = init_repository(self.tmp_dir.name) + repo.index.add_all() + repo.index.write() + tree = repo.index.write_tree() + signature = Signature("Test", "test@example.com") + commit_msg = "Commit message" + repo.create_commit("HEAD", signature, signature, commit_msg, tree, []) + + self.start_master("-r", self.tmp_dir.name, "-g") + self.run_client("submit", self.exp_name, "-R") + self.check_and_terminate_master() + + def tearDown(self): + self.tmp_dir.cleanup() + self.tmp_empty_dir.cleanup() diff --git a/flake.nix b/flake.nix index 2b2ae17fe..2d28f6079 100644 --- a/flake.nix +++ b/flake.nix @@ -144,7 +144,9 @@ ]; # FIXME: automatically propagate lld_11 llvm_11 dependencies - checkInputs = [ pkgs.lld_11 pkgs.llvm_11 libartiq-support pkgs.lit outputcheck ]; + # cacert is required in the check stage only, as certificates are to be + # obtained from system elsewhere + checkInputs = [ pkgs.lld_11 pkgs.llvm_11 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; checkPhase = '' python -m unittest discover -v artiq.test From 40561688753cc74db06e61f578fc9481c0b3426b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 24 Apr 2023 17:34:30 +0800 Subject: [PATCH 18/23] master: store datasets in LMDB (#1743) --- RELEASE_NOTES.rst | 1 + artiq/compiler/testbench/perf_embedding.py | 7 +++- artiq/frontend/artiq_compile.py | 42 ++++++++++--------- artiq/frontend/artiq_master.py | 3 +- artiq/frontend/artiq_run.py | 47 ++++++++++++---------- artiq/master/databases.py | 38 ++++++++++++----- artiq/test/hardware_testbench.py | 3 +- flake.nix | 2 +- 8 files changed, 88 insertions(+), 55 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 590ade183..cd41ac526 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -25,6 +25,7 @@ Highlights: * Full Python 3.10 support. * Distributed DMA is now supported, allowing DMA to be run directly on satellites for corresponding RTIO events, increasing bandwidth in scenarios with heavy satellite usage. +* Persistent datasets are now stored in a LMDB database for improved performance. ARTIQ-7 ------- diff --git a/artiq/compiler/testbench/perf_embedding.py b/artiq/compiler/testbench/perf_embedding.py index 75267cb5b..5d148cb34 100644 --- a/artiq/compiler/testbench/perf_embedding.py +++ b/artiq/compiler/testbench/perf_embedding.py @@ -30,8 +30,9 @@ def main(): device_db_path = os.path.join(os.path.dirname(sys.argv[1]), "device_db.py") device_mgr = DeviceManager(DeviceDB(device_db_path)) - dataset_db_path = os.path.join(os.path.dirname(sys.argv[1]), "dataset_db.pyon") - dataset_mgr = DatasetManager(DatasetDB(dataset_db_path)) + dataset_db_path = os.path.join(os.path.dirname(sys.argv[1]), "dataset_db.mdb") + dataset_db = DatasetDB(dataset_db_path) + dataset_mgr = DatasetManager() argument_mgr = ProcessArgumentManager({}) @@ -68,5 +69,7 @@ def main(): benchmark(lambda: target.strip(elf_shlib), "Stripping debug information") + dataset_db.close_db() + if __name__ == "__main__": main() diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 918a58c65..fcba5297d 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -24,7 +24,7 @@ def get_argparser(): common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") - parser.add_argument("--dataset-db", default="dataset_db.pyon", + parser.add_argument("--dataset-db", default="dataset_db.mdb", help="dataset file (default: '%(default)s')") parser.add_argument("-c", "--class-name", default=None, @@ -45,29 +45,33 @@ def main(): common_args.init_logger_from_args(args) device_mgr = DeviceManager(DeviceDB(args.device_db)) - dataset_mgr = DatasetManager(DatasetDB(args.dataset_db)) - + dataset_db = DatasetDB(args.dataset_db) try: - module = file_import(args.file, prefix="artiq_run_") - exp = get_experiment(module, args.class_name) - arguments = parse_arguments(args.arguments) - argument_mgr = ProcessArgumentManager(arguments) - exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) - argument_mgr.check_unprocessed_arguments() + dataset_mgr = DatasetManager(dataset_db) + + try: + module = file_import(args.file, prefix="artiq_run_") + exp = get_experiment(module, args.class_name) + arguments = parse_arguments(args.arguments) + argument_mgr = ProcessArgumentManager(arguments) + exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) + argument_mgr.check_unprocessed_arguments() - if not hasattr(exp.run, "artiq_embedded"): - raise ValueError("Experiment entry point must be a kernel") - core_name = exp.run.artiq_embedded.core_name - core = getattr(exp_inst, core_name) + if not hasattr(exp.run, "artiq_embedded"): + raise ValueError("Experiment entry point must be a kernel") + core_name = exp.run.artiq_embedded.core_name + core = getattr(exp_inst, core_name) - object_map, kernel_library, _, _ = \ - core.compile(exp.run, [exp_inst], {}, - attribute_writeback=False, print_as_rpc=False) - except CompileError as error: - return + object_map, kernel_library, _, _ = \ + core.compile(exp.run, [exp_inst], {}, + attribute_writeback=False, print_as_rpc=False) + except CompileError as error: + return + finally: + device_mgr.close_devices() finally: - device_mgr.close_devices() + dataset_db.close_db() if object_map.has_rpc(): raise ValueError("Experiment must not use RPC") diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index 05959beb5..b5f725b47 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -40,7 +40,7 @@ def get_argparser(): group = parser.add_argument_group("databases") group.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") - group.add_argument("--dataset-db", default="dataset_db.pyon", + group.add_argument("--dataset-db", default="dataset_db.mdb", help="dataset file (default: '%(default)s')") group = parser.add_argument_group("repository") @@ -101,6 +101,7 @@ def main(): device_db = DeviceDB(args.device_db) dataset_db = DatasetDB(args.dataset_db) + atexit.register(dataset_db.close_db) dataset_db.start(loop=loop) atexit_register_coroutine(dataset_db.stop, loop=loop) worker_handlers = dict() diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index c3d548c26..948c34475 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -134,7 +134,7 @@ def get_argparser(with_file=True): common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") - parser.add_argument("--dataset-db", default="dataset_db.pyon", + parser.add_argument("--dataset-db", default="dataset_db.mdb", help="dataset file (default: '%(default)s')") parser.add_argument("-c", "--class-name", default=None, @@ -197,29 +197,32 @@ def run(with_file=False): virtual_devices={"scheduler": DummyScheduler(), "ccb": DummyCCB()}) dataset_db = DatasetDB(args.dataset_db) - dataset_mgr = DatasetManager(dataset_db) - try: - exp_inst = _build_experiment(device_mgr, dataset_mgr, args) - exp_inst.prepare() - exp_inst.run() - exp_inst.analyze() - except CompileError as error: - return - except Exception as exn: - if hasattr(exn, "artiq_core_exception"): - print(exn.artiq_core_exception, file=sys.stderr) - raise exn - finally: - device_mgr.close_devices() + dataset_mgr = DatasetManager(dataset_db) - if args.hdf5 is not None: - with h5py.File(args.hdf5, "w") as f: - dataset_mgr.write_hdf5(f) - else: - for k, v in sorted(dataset_mgr.local.items(), key=itemgetter(0)): - print("{}: {}".format(k, v)) - dataset_db.save() + try: + exp_inst = _build_experiment(device_mgr, dataset_mgr, args) + exp_inst.prepare() + exp_inst.run() + exp_inst.analyze() + except CompileError as error: + return + except Exception as exn: + if hasattr(exn, "artiq_core_exception"): + print(exn.artiq_core_exception, file=sys.stderr) + raise exn + finally: + device_mgr.close_devices() + + if args.hdf5 is not None: + with h5py.File(args.hdf5, "w") as f: + dataset_mgr.write_hdf5(f) + else: + for k, v in sorted(dataset_mgr.local.items(), key=itemgetter(0)): + print("{}: {}".format(k, v)) + dataset_db.save() + finally: + dataset_db.close_db() def main(): diff --git a/artiq/master/databases.py b/artiq/master/databases.py index 14cfae4cd..68b494f76 100644 --- a/artiq/master/databases.py +++ b/artiq/master/databases.py @@ -1,11 +1,13 @@ import asyncio -from artiq.tools import file_import +import lmdb -from sipyco.sync_struct import Notifier, process_mod, update_from_dict +from sipyco.sync_struct import Notifier, process_mod, ModAction, update_from_dict from sipyco import pyon from sipyco.asyncio_tools import TaskObject +from artiq.tools import file_import + def device_db_from_file(filename): mod = file_import(filename) @@ -40,15 +42,25 @@ class DatasetDB(TaskObject): self.persist_file = persist_file self.autosave_period = autosave_period - try: - file_data = pyon.load_file(self.persist_file) - except FileNotFoundError: - file_data = dict() - self.data = Notifier({k: (True, v) for k, v in file_data.items()}) + self.lmdb = lmdb.open(persist_file, subdir=False, map_size=2**30) + data = dict() + with self.lmdb.begin() as txn: + for key, value in txn.cursor(): + data[key.decode()] = (True, pyon.decode(value.decode())) + self.data = Notifier(data) + self.pending_keys = set() + + def close_db(self): + self.lmdb.close() def save(self): - data = {k: v[1] for k, v in self.data.raw_view.items() if v[0]} - pyon.store_file(self.persist_file, data) + with self.lmdb.begin(write=True) as txn: + for key in self.pending_keys: + if key not in self.data.raw_view or not self.data.raw_view[key][0]: + txn.delete(key.encode()) + else: + txn.put(key.encode(), pyon.encode(self.data.raw_view[key][1]).encode()) + self.pending_keys.clear() async def _do(self): try: @@ -62,6 +74,12 @@ class DatasetDB(TaskObject): return self.data.raw_view[key][1] def update(self, mod): + if mod["path"]: + key = mod["path"][0] + else: + assert(mod["action"] == ModAction.setitem.value or mod["action"] == ModAction.delitem.value) + key = mod["key"] + self.pending_keys.add(key) process_mod(self.data, mod) # convenience functions (update() can be used instead) @@ -72,7 +90,9 @@ class DatasetDB(TaskObject): else: persist = False self.data[key] = (persist, value) + self.pending_keys.add(key) def delete(self, key): del self.data[key] + self.pending_keys.add(key) # diff --git a/artiq/test/hardware_testbench.py b/artiq/test/hardware_testbench.py index 987a1cf6b..c5cebfeff 100644 --- a/artiq/test/hardware_testbench.py +++ b/artiq/test/hardware_testbench.py @@ -21,13 +21,14 @@ class ExperimentCase(unittest.TestCase): def setUp(self): self.device_db = DeviceDB(os.path.join(artiq_root, "device_db.py")) self.dataset_db = DatasetDB( - os.path.join(artiq_root, "dataset_db.pyon")) + os.path.join(artiq_root, "dataset_db.mdb")) self.device_mgr = DeviceManager( self.device_db, virtual_devices={"scheduler": DummyScheduler()}) self.dataset_mgr = DatasetManager(self.dataset_db) def tearDown(self): self.device_mgr.close_devices() + self.dataset_db.close_db() def create(self, cls, *args, **kwargs): try: diff --git a/flake.nix b/flake.nix index 2d28f6079..1336351bb 100644 --- a/flake.nix +++ b/flake.nix @@ -127,7 +127,7 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools ] - ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm ]); + ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb ]); dontWrapQtApps = true; postFixup = '' From 4417acd13b7bcdae142ae169971ce32696393b3c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 24 Apr 2023 17:36:13 +0800 Subject: [PATCH 19/23] flake: update dependencies --- flake.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/flake.lock b/flake.lock index 907524a64..81eff9ce0 100644 --- a/flake.lock +++ b/flake.lock @@ -42,11 +42,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1672878308, - "narHash": "sha256-0+fl6PHokhtSV+w58z2QD2rTf8QhcOGsT9o4LwHHZHE=", + "lastModified": 1677493379, + "narHash": "sha256-A1gO8zlWLv3+tZ3cGVB1WYvvoN9pbFyv0xIJHcTsckw=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "d38863db88e100866b3e494a651ee4962b762fcc", + "rev": "78e723925daf5c9e8d0a1837ec27059e61649cb6", "type": "github" }, "original": { @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1673345971, - "narHash": "sha256-4DfFcKLRfVUTyuGrGNNmw37IeIZSoku9tgTVmu/iD98=", + "lastModified": 1682173319, + "narHash": "sha256-tPhOpJJ+wrWIusvGgIB2+x6ILfDkEgQMX0BTtM5vd/4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "54644f409ab471e87014bb305eac8c50190bcf48", + "rev": "ee7ec1c71adc47d2e3c2d5eb0d6b8fbbd42a8d1c", "type": "github" }, "original": { @@ -105,11 +105,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1673433200, - "narHash": "sha256-ribBG06gsucz5oBS+O6aL8s2oJjx+qfl+vXmspts8gg=", + "lastModified": 1674045327, + "narHash": "sha256-oYdeY0MbTReKbAwmSznnqw0wNawdInJoFJVWW3tesFA=", "owner": "m-labs", "repo": "migen", - "rev": "f3e9145c9825514a1b4225378936569da4df8e12", + "rev": "ccaee68e14d3636e1d8fb2e0864dd89b1b1f7384", "type": "github" }, "original": { @@ -121,11 +121,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1671158014, - "narHash": "sha256-50w0K2E2ympYrG1Tte/HVbsp4FS2U+yohqZByXTOo4I=", + "lastModified": 1679903508, + "narHash": "sha256-TI0agjSSMJtH4mgAMpSO128zxcwSo/AjY1B6AW7zBQQ=", "ref": "refs/heads/master", - "rev": "26f039f9f6931a20a04ccd0f0a5402f67f553916", - "revCount": 2436, + "rev": "0cf0ebb7d4f56cc6d44a3dea3e386efab9d82419", + "revCount": 2437, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 0bf57f4ebd177922d53f8d3dfc7f5c1357e1a197 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 18 Apr 2023 13:19:01 +0100 Subject: [PATCH 20/23] Fix ADF3536 having RTIO channel names The channel in this device refers to a channel on the mirny, not an RTIO channel. --- artiq/coredevice/adf5356.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index f2b594dbf..0bffb91be 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -74,8 +74,8 @@ class ADF5356: self._init_registers() @staticmethod - def get_rtio_channels(channel, **kwargs): - return [(channel, None)] + def get_rtio_channels(**kwargs): + return [] @kernel def init(self, blind=False): From a533f2a0cd6c116c0a2311f489365b82dc22baf3 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Apr 2023 14:49:55 +0800 Subject: [PATCH 21/23] rtio: SED, InputCollector use rio clock domain --- artiq/gateware/rtio/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 1d9cfc006..52012379d 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -60,17 +60,17 @@ class Core(Module, AutoCSR): # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] - outputs = SED(channels, tsc.glbl_fine_ts_width, + outputs = ClockDomainsRenamer("rio")(SED(channels, tsc.glbl_fine_ts_width, quash_channels=quash_channels, lane_count=lane_count, fifo_depth=fifo_depth, - interface=self.cri) + interface=self.cri)) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts) self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 12) - inputs = InputCollector(tsc, channels, + inputs = ClockDomainsRenamer("rio")(InputCollector(tsc, channels, quash_channels=quash_channels, - interface=self.cri) + interface=self.cri)) self.submodules += inputs # Asychronous output errors From 5199bea353064c2b7ee8f14db98c9ca264629bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Sun, 30 Apr 2023 15:22:21 +0800 Subject: [PATCH 22/23] master: emit warning if datasets will not be stored --- artiq/master/worker_db.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index fccdc1c11..015a125fa 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -119,6 +119,9 @@ class DatasetManager: if persist: broadcast = True + if not (broadcast or archive): + logger.warning(f"Dataset '{key}' will not be stored. Both 'broadcast' and 'archive' are set to False.") + if broadcast: self._broadcaster[key] = persist, value elif key in self._broadcaster.raw_view: From 2c1438c4b9a99cde81d7de1ac128e10cb54898fd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 30 Apr 2023 16:07:56 +0800 Subject: [PATCH 23/23] coredevice: add missing pattern to sampler_hw_rev --- artiq/coredevice/coredevice_generic.schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index 951184881..d2c9a6abd 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -383,7 +383,8 @@ "maxItems": 2 }, "sampler_hw_rev": { - "type": "string" + "type": "string", + "pattern": "^v[0-9]+\\.[0-9]+" }, "urukul0_ports": { "type": "array",