From 6a7d3acfcb5e36ec379321bdd86095070a36e5dd 2020-10-23 13:57:30 From: Christopher Esterhuyse Date: 2020-10-23 13:57:30 Subject: [PATCH] logging feature exposed for ease of use --- diff --git a/Cargo.toml b/Cargo.toml index e555a0d97ebe3d1cb46ebae6cdf79c9fd3a41ca2..fae009c6b8d2ba15b6ffbda34087afe5b52b0522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,4 +47,5 @@ default = ["ffi"] ffi = [] # see src/ffi/mod.rs ffi_pseudo_socket_api = ["ffi", "libc", "os_socketaddr"]# see src/ffi/pseudo_socket_api.rs. endpoint_logging = [] # see src/macros.rs -session_optimization = [] # see src/runtime/setup.rs \ No newline at end of file +session_optimization = [] # see src/runtime/setup.rs +no_logging = [] # see src/macros.rs \ No newline at end of file diff --git a/README.md b/README.md index 04902469c056ade24337c53067486e269093d7db..20a741c2a9f751e370931ea810980f6fb5d8440b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This library provides connectors as a generalization of sockets for use in commu - The resulting dylib can be found in `./target/release/`, to be used with the header file: `./reowolf.h`. - *Note*: A list of immediate ancestor dependencies is visible in `./Cargo.toml`. - *Note*: Run `cargo test --release` to run unit tests with release-level optimizations. +1. By default, will compile with logging turned ON and session optimization turned OFF. Control this by passing the desired set of feature flags in {"no_logging", "session_optimization"} to the compiler. For example, `cargo build --release --features no_logging`. ## Using the library - The library may be used as a Rust dependency by adding it as a git dependency, i.e., by adding line `reowolf_rs = { git = "https://scm.cwi.nl/FM/reowolf" }` to downstream crate's manifest file, `Cargo.toml`. diff --git a/src/macros.rs b/src/macros.rs index 7909f33ebe912e7631a79cd8f6c5acb28a2b8780..461f7bb31a05087ab72bebb6b92c5406f16ad044 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -9,8 +9,9 @@ macro_rules! log { // } }}; ($logger:expr, $($arg:tt)*) => {{ - // if let Some(w) = $logger.line_writer() { - // let _ = writeln!(w, $($arg)*); - // } + #[cfg(not(feature = "no_logging"))] + if let Some(w) = $logger.line_writer() { + let _ = writeln!(w, $($arg)*); + } }}; } diff --git a/src/runtime/communication.rs b/src/runtime/communication.rs index 8ee6ec0e57d2720082e7561ddf088d414b6e9953..4fff50f92e68fea351be4bd869a61eabf78d4b55 100644 --- a/src/runtime/communication.rs +++ b/src/runtime/communication.rs @@ -72,6 +72,11 @@ impl CuUndecided for ConnectorUnphased { fn logger_and_protocol_description(&mut self) -> (&mut dyn Logger, &ProtocolDescription) { (&mut *self.logger, &self.proto_description) } + fn logger_and_protocol_components( + &mut self, + ) -> (&mut dyn Logger, &mut HashMap) { + (&mut *self.logger, &mut self.proto_components) + } fn logger(&mut self) -> &mut dyn Logger { &mut *self.logger } @@ -274,7 +279,7 @@ impl Connector { }; let blocker = component.nonsync_run(&mut ctx, proto_description); log!( - cu.logger(), + logger, "proto component {:?} ran to nonsync blocker {:?}", proto_component_id, &blocker @@ -452,22 +457,23 @@ impl Connector { Decision::Success(predicate) => { // commit changes to component states cu.proto_components.clear(); - cu.proto_components.extend( + let (logger, proto_components) = cu.logger_and_protocol_components(); + proto_components.extend( // "flatten" branching components, committing the speculation // consistent with the predicate decided upon. branching_proto_components .into_iter() - .map(|(cid, bpc)| (cid, bpc.collapse_with(&predicate))), + .map(|(cid, bpc)| (cid, bpc.collapse_with(logger, &predicate))), ); // commit changes to ports and id_manager - cu.ips = rctx.ips; log!( - cu.logger, + logger, "End round with (updated) component states {:?}", - cu.proto_components.keys() + proto_components.keys() ); + cu.ips = rctx.ips; // consume native - let round_ok = branching_native.collapse_with(&mut *cu.logger(), &predicate); + let round_ok = branching_native.collapse_with(cu.logger(), &predicate); Ok(Some(round_ok)) } }; @@ -972,6 +978,7 @@ impl BranchingNative { return RoundEndedNative { batch_index: index, gotten }; } } + log!(logger, "Native had no branches matching pred {:?}", solution_predicate); panic!("Native had no branches matching pred {:?}", solution_predicate); } } @@ -1214,7 +1221,11 @@ impl BranchingProtoComponent { // Given the predicate for the round's solution, collapse this // branching native to an ended branch whose predicate is consistent with it. - fn collapse_with(self, solution_predicate: &Predicate) -> ComponentState { + fn collapse_with( + self, + logger: &mut dyn Logger, + solution_predicate: &Predicate, + ) -> ComponentState { let BranchingProtoComponent { branches } = self; for (branch_predicate, branch) in branches { if branch.ended && branch_predicate.assigns_subset(solution_predicate) { @@ -1222,6 +1233,7 @@ impl BranchingProtoComponent { return state; } } + log!(logger, "ProtoComponent had no branches matching pred {:?}", solution_predicate); panic!("ProtoComponent had no branches matching pred {:?}", solution_predicate); } } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 1d8a9841ca0c7ec58c62c60d59f4dd9d7e189dcb..9ec89b0f5297a3c6ce716fa2f581c642d475f56e 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -425,6 +425,9 @@ trait CuUndecided { fn proto_description(&self) -> &ProtocolDescription; fn native_component_id(&self) -> ComponentId; fn logger_and_protocol_description(&mut self) -> (&mut dyn Logger, &ProtocolDescription); + fn logger_and_protocol_components( + &mut self, + ) -> (&mut dyn Logger, &mut HashMap); } // Represents a set of synchronous port operations that the native component diff --git a/src/runtime/tests.rs b/src/runtime/tests.rs index 027bb6b2c735d55c45cf50e2e857f5203e8ae0c3..ceb3b85c0c02de9473d7e7c3de0b24850cc9ffb0 100644 --- a/src/runtime/tests.rs +++ b/src/runtime/tests.rs @@ -1312,6 +1312,58 @@ fn for_msg_byte() { c.sync(None).unwrap(); } +#[test] +fn eq_causality() { + let test_log_path = Path::new("./logs/eq_no_causality"); + let pdl = b" + primitive eq(in a, in b, out c) { + msg ma = null; + msg mb = null; + while(true) synchronous { + if(fires(a)) { + // b and c also fire! + // left first! + ma = get(a); + put(c, ma); + mb = get(b); + assert(ma == mb); + } + } + } + "; + let pd = reowolf::ProtocolDescription::parse(pdl).unwrap(); + let mut c = file_logged_configured_connector(0, test_log_path, Arc::new(pd)); + + /* + [native]p0-->g0[eq]p1--. + g1 | + ^---------` + */ + let [p0, g0] = c.new_port_pair(); + let [p1, g1] = c.new_port_pair(); + c.add_component(b"eq", &[g0, g1, p1]).unwrap(); + + /* + V--------. + g2 | + [native]p2-->g3[eq]p3--` + */ + let [p2, g2] = c.new_port_pair(); + let [p3, g3] = c.new_port_pair(); + c.add_component(b"eq", &[g3, g2, p3]).unwrap(); + c.connect(None).unwrap(); + + for _ in 0..4 { + // everything is fine with LEFT FIRST + c.put(p0, TEST_MSG.clone()).unwrap(); + c.sync(MS100).unwrap(); + + // no solution when left is NOT FIRST + c.put(p2, TEST_MSG.clone()).unwrap(); + c.sync(MS100).unwrap_err(); + } +} + #[test] fn eq_no_causality() { let test_log_path = Path::new("./logs/eq_no_causality"); @@ -1324,22 +1376,25 @@ fn eq_no_causality() { msg ma = null; msg mb = null; while(true) synchronous { - if(fires(leftfirsti)) { - // left first! DO USE DUMMY - ma = get(a); - put(c, ma); - mb = get(b); - - // using dummy! - put(leftfirsto, ma); - get(leftfirsti); - } else { - // right first! DON'T USE DUMMY - mb = get(b); - put(c, mb); - ma = get(a); + if(fires(a)) { + // b and c also fire! + if(fires(leftfirsti)) { + // left first! DO USE DUMMY + ma = get(a); + put(c, ma); + mb = get(b); + + // using dummy! + put(leftfirsto, ma); + get(leftfirsti); + } else { + // right first! DON'T USE DUMMY + mb = get(b); + put(c, mb); + ma = get(a); + } + assert(ma == mb); } - assert(ma == mb); } } "; @@ -1366,8 +1421,11 @@ fn eq_no_causality() { c.connect(None).unwrap(); for _ in 0..32 { + // ok when they send c.put(p0, TEST_MSG.clone()).unwrap(); c.put(p2, TEST_MSG.clone()).unwrap(); c.sync(SEC1).unwrap(); + // ok when they don't + c.sync(SEC1).unwrap(); } }