diff --git a/measurements/A.py b/measurements/A.py new file mode 100644 index 0000000..b7d0fb6 --- /dev/null +++ b/measurements/A.py @@ -0,0 +1,76 @@ +# A.py (Client and Primary Measurement Node) +import concore +import time +import os +import psutil +import sys + +# --- ZMQ Initialization --- +# This REQ socket connects to Node B +concore.init_zmq_port( + port_name=PORT_NAME_F1_F2, + port_type="connect", + address="tcp://localhost:" + PORT_F1_F2, + socket_type_str="REQ" +) + +print("Node A client started.") + +# --- Measurement Initialization --- +min_latency = float('inf') +max_latency = 0.0 +total_latency = 0.0 +message_count = 0 +total_bytes = 0 +process = psutil.Process(os.getpid()) +overall_start_time = time.monotonic() +loop_start_time = 0 + +current_value = 0 +max_value = 100 + +while current_value < max_value: + loop_start_time = time.monotonic() # Start timer for round-trip latency + print(f"Node A: Sending value {current_value:.2f} to Node B.") + + # 1. Send the current value as a request to the pipeline + concore.write(PORT_NAME_F1_F2, "value", [current_value]) + total_bytes += sys.getsizeof([current_value]) + + # 2. Wait for the final, processed value in reply + received_data = concore.read(PORT_NAME_F1_F2, "value", [0.0]) + + loop_end_time = time.monotonic() + latency_ms = (loop_end_time - loop_start_time) * 1000 + + # Update metrics + message_count += 1 + min_latency = min(min_latency, latency_ms) + max_latency = max(max_latency, latency_ms) + total_latency += latency_ms + + current_value = received_data[0] + print(f"Node A: Received final value {current_value:.2f} from the pipeline. | Latency: {latency_ms:.2f} ms") + print("-" * 20) + +# --- Finalize and Report Measurements --- +overall_end_time = time.monotonic() +total_duration = overall_end_time - overall_start_time +cpu_usage = process.cpu_percent() / total_duration if total_duration > 0 else 0 +avg_latency = total_latency / message_count if message_count > 0 else 0 + +print("\n" + "="*35) +print("--- NODE A: END-TO-END RESULTS ---") +print(f"Total pipeline iterations: {message_count}") +print(f"Total data sent: {total_bytes / 1024:.4f} KB") +print(f"Total End-to-End Time: {total_duration:.4f} seconds") +print("-" * 35) +print(f"Min round-trip latency: {min_latency:.2f} ms") +print(f"Avg round-trip latency: {avg_latency:.2f} ms") +print(f"Max round-trip latency: {max_latency:.2f} ms") +print("-" * 35) +print(f"Approximate CPU usage: {cpu_usage:.2f}%") +print("="*35) + +print(f"\nNode A: Final value {current_value:.2f} reached the target. Terminating.") +concore.terminate_zmq() diff --git a/measurements/B.py b/measurements/B.py new file mode 100644 index 0000000..8ab05d0 --- /dev/null +++ b/measurements/B.py @@ -0,0 +1,60 @@ +# B.py (Broker with Measurements) +import concore +import time + +# --- ZMQ Initialization --- +# This REP socket binds and waits for requests from Node A +concore.init_zmq_port( + port_name=PORT_NAME_F1_F2, + port_type="bind", + address="tcp://*:" + PORT_F1_F2, + socket_type_str="REP" +) +# This REQ socket connects to Node C +concore.init_zmq_port( + port_name=PORT_NAME_F2_F3, + port_type="connect", + address="tcp://localhost:" + PORT_F2_F3, + socket_type_str="REQ" +) + +print("Node B broker started. Waiting for requests...") + +# --- Measurement Initialization --- +start_time = time.monotonic() +messages_routed = 0 + +while True: + # 1. Wait for a request from Node A + value_from_a = concore.read(PORT_NAME_F1_F2, "value", [0.0]) + received_value = value_from_a[0] + print(f"Node B: Received {received_value:.2f} from Node A. Forwarding to C...") + + # 2. Send the received value as a new request to Node C + concore.write(PORT_NAME_F2_F3, "value", [received_value]) + + # 3. Wait for the reply from Node C + value_from_c = concore.read(PORT_NAME_F2_F3, "value", [0.0]) + processed_value = value_from_c[0] + print(f"Node B: Received {processed_value:.2f} from Node C. Replying to A...") + + # 4. Send the processed value back as a reply to Node A + concore.write(PORT_NAME_F1_F2, "value", [processed_value]) + messages_routed += 1 + + # 5. Check termination condition + if processed_value >= 100: + break + +# --- Finalize and Report Measurements --- +end_time = time.monotonic() +duration = end_time - start_time + +print("\n" + "="*30) +print("--- NODE B: RESULTS ---") +print(f"Total messages routed: {messages_routed}") +print(f"Total execution time: {duration:.4f} seconds") +print("="*30) + +print("\nNode B: Terminating.") +concore.terminate_zmq() diff --git a/measurements/C.py b/measurements/C.py new file mode 100644 index 0000000..1448069 --- /dev/null +++ b/measurements/C.py @@ -0,0 +1,62 @@ +# C.py (Processing Server and Measurement Endpoint) +import concore +import time +import psutil +import os +import sys + +# --- ZMQ Initialization --- +# This REP socket binds and waits for requests from Node B +concore.init_zmq_port( + port_name=PORT_NAME_F2_F3, + port_type="bind", + address="tcp://*:" + PORT_F2_F3, + socket_type_str="REP" +) + +print("Node C server started. Waiting for requests...") + +# --- Measurement Initialization --- +process = psutil.Process(os.getpid()) +start_time = time.monotonic() +message_count = 0 +total_bytes = 0 + +while True: + # 1. Wait to receive a request from Node B + received_data = concore.read(PORT_NAME_F2_F3, "value", [0.0]) + received_value = received_data[0] + + # Track received data for metrics + message_count += 1 + total_bytes += sys.getsizeof(received_data) + + print(f"Node C: Received {received_value:.2f} from Node B.") + + # 2. Process the value (increment by 10) + new_value = received_value + 10 + print(f"Node C: Sending back processed value {new_value:.2f}.") + + # 3. Send the reply back to Node B + concore.write(PORT_NAME_F2_F3, "value", [new_value]) + + # 4. Check the value to know when to shut down gracefully. + if new_value >= 100: + break + +# --- Finalize and Report Measurements --- +end_time = time.monotonic() +duration = end_time - start_time +# This captures the CPU usage over the process's lifetime relative to the test duration +cpu_usage = process.cpu_percent() / duration if duration > 0 else 0 + +print("\n" + "="*30) +print("--- NODE C: RESULTS ---") +print(f"Total messages processed: {message_count}") +print(f"Total data processed: {total_bytes / 1024:.4f} KB") +print(f"Total execution time: {duration:.4f} seconds") +print(f"Approximate CPU usage: {cpu_usage:.2f}%") +print("="*30) + +print("\nNode C: Terminating.") +concore.terminate_zmq() diff --git a/measurements/ZeroMQOnly.graphml b/measurements/ZeroMQOnly.graphml new file mode 100644 index 0000000..e2d88c6 --- /dev/null +++ b/measurements/ZeroMQOnly.graphml @@ -0,0 +1,280 @@ + + + + + + + + + + + + F1:A.py + + + + + + + + + + + F2:B.py + + + + + + + + + + + F3:C.py + + + + + + + + + + 0x1234_U + + + + + + + + + + + + 0x1235_Y + + + + + + + + 1750189426493 + + DEL_NODE + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiXQ== + + + ADD_NODE + WyJGMTpmaXJzdE5vZGUucHkiLHsid2lkdGgiOjEyOCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJvcmRpbiIseyJ4IjoxMTYsInkiOjExMH0se30sIjNhMGU3YTg1LTFlYjAtNDE3My1hYjRmLTE0ZmQwZDdjN2E2ZiJd + + 326ab944dc81b1821c8da10835df1b91 + + + 1750189429966 + + SET_POS + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLHsieCI6MTAwLCJ5IjoxMDB9LHsieCI6MTY5LCJ5IjoyNTh9XQ== + + + SET_POS + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLHsieCI6MTY5LCJ5IjoyNTh9LHsieCI6MTAwLCJ5IjoxMDB9XQ== + + 680f94c71c2a0a6c26cb302206337ac4 + + + 1750189440456 + + DEL_NODE + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiXQ== + + + ADD_NODE + WyJGMjpzZWNvbmROb2RlLnB5Iix7IndpZHRoIjoxNTQsImhlaWdodCI6NTAsInNoYXBlIjoicmVjdGFuZ2xlIiwib3BhY2l0eSI6MSwiYmFja2dyb3VuZENvbG9yIjoiI2ZmY2MwMCIsImJvcmRlckNvbG9yIjoiIzAwMCIsImJvcmRlcldpZHRoIjoxfSwib3JkaW4iLHsieCI6NDA1LCJ5IjozMTh9LHt9LCI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiXQ== + + 3d9bcbaa70f3846f8254748756b5cb84 + + + 1750189448750 + + SET_POS + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLHsieCI6MTAwLCJ5IjoxMDB9LHsieCI6NDE3LCJ5IjoyNTh9XQ== + + + SET_POS + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLHsieCI6NDE3LCJ5IjoyNTh9LHsieCI6MTAwLCJ5IjoxMDB9XQ== + + a191948b47544272a56a2f705214ab55 + + + 1750189460209 + + DEL_NODE + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiXQ== + + + ADD_NODE + WyJGMzp0aGlyZE5vZGUucHkiLHsid2lkdGgiOjEzNCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJvcmRpbiIseyJ4Ijo2OTcsInkiOjExMH0se30sImYzMWNmY2ViLTk3MjctNDg4Zi04Y2E0LWY0MWQ0ZTM2MGUzOSJd + + 69b8535e1d43f1d7f6ce343dff130655 + + + 1750189464533 + + SET_POS + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsieCI6MTAwLCJ5IjoxMDB9LHsieCI6Njg4LCJ5IjoyNTd9XQ== + + + SET_POS + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsieCI6Njg4LCJ5IjoyNTd9LHsieCI6MTAwLCJ5IjoxMDB9XQ== + + eaf400a73bea2db0fcb4d24fdc1e511c + + + 1750189470864 + + SET_POS + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsieCI6Njg4LCJ5IjoyNTd9LHsieCI6NjgwLCJ5IjoyNTl9XQ== + + + SET_POS + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsieCI6NjgwLCJ5IjoyNTl9LHsieCI6Njg4LCJ5IjoyNTd9XQ== + + b077669aa6784b6d6783a10c1dc4cdd9 + + + 1750189472901 + + DEL_EDGE + WyJkMGVjZGNlNy02MTI1LTRjNzAtOTBmNC02NDVkMTg0OTRhYmYiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLCJ0YXJnZXRJRCI6IjcxMjYxMGRkLWZkMzQtNDQxZS05OTk5LTgyYjI0MDVhM2Q1ZSIsImxhYmVsIjoiMHg0NTY3X1UxIiwic3R5bGUiOnsidGhpY2tuZXNzIjoxLCJiYWNrZ3JvdW5kQ29sb3IiOm51bGwsInNoYXBlIjoic29saWQifSwiaWQiOiJkMGVjZGNlNy02MTI1LTRjNzAtOTBmNC02NDVkMTg0OTRhYmYifV0= + + d24a689c7eaa05ea16bae0fe52dd67d1 + + + 1750189489267 + + SET_POS + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLHsieCI6MTY5LCJ5IjoyNTh9LHsieCI6MTE2LCJ5IjoxMTB9XQ== + + + SET_POS + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLHsieCI6MTE2LCJ5IjoxMTB9LHsieCI6MTY5LCJ5IjoyNTh9XQ== + + 5a81d32b9be7e01c9a3ee322528734ee + + + 1750189491699 + + SET_POS + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLHsieCI6NDE3LCJ5IjoyNTh9LHsieCI6NDA1LCJ5IjozMTh9XQ== + + + SET_POS + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLHsieCI6NDA1LCJ5IjozMTh9LHsieCI6NDE3LCJ5IjoyNTh9XQ== + + 3d5e1d4dd3c116825682ca44a7ff6df9 + + + 1750189499398 + + SET_POS + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsieCI6NjgwLCJ5IjoyNTl9LHsieCI6Njk3LCJ5IjoxMTB9XQ== + + + SET_POS + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsieCI6Njk3LCJ5IjoxMTB9LHsieCI6NjgwLCJ5IjoyNTl9XQ== + + 8cd64e7bd8e811a830c632b7b27eb005 + + + 1750189502566 + + DEL_EDGE + WyI2MWI0OTQ0Yi1iOWU5LTRmMmUtOWE4Mi0zMDA0ZmZlMzFlYTYiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLCJ0YXJnZXRJRCI6ImYzMWNmY2ViLTk3MjctNDg4Zi04Y2E0LWY0MWQ0ZTM2MGUzOSIsImxhYmVsIjoiMHg1Njc4X1kiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6bnVsbCwic2hhcGUiOiJzb2xpZCJ9LCJpZCI6IjYxYjQ5NDRiLWI5ZTktNGYyZS05YTgyLTMwMDRmZmUzMWVhNiJ9XQ== + + 771e97ad0acb41eb9d328619db10ceda + + + 1750189516115 + + UPDATE_EDGE + WyJkMGVjZGNlNy02MTI1LTRjNzAtOTBmNC02NDVkMTg0OTRhYmYiLHsidGhpY2tuZXNzIjoxLCJiYWNrZ3JvdW5kQ29sb3IiOm51bGwsInNoYXBlIjoic29saWQifSwiMHg0NTY3X1UxIix0cnVlXQ== + + + UPDATE_EDGE + WyJkMGVjZGNlNy02MTI1LTRjNzAtOTBmNC02NDVkMTg0OTRhYmYiLHsidGhpY2tuZXNzIjoxLCJiYWNrZ3JvdW5kQ29sb3IiOm51bGwsInNoYXBlIjoic29saWQifSwiMHg0NTY3X1UiLHRydWVd + + 5b03334dacd3a042b436831f9d5ef10f + + + 1750189753337 + + UPDATE_NODE + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLHsid2lkdGgiOjEyOCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpmaXJzdE5vZGUucHkiLHRydWVd + + + UPDATE_NODE + WyIzYTBlN2E4NS0xZWIwLTQxNzMtYWI0Zi0xNGZkMGQ3YzdhNmYiLHsid2lkdGgiOjEyOCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpBLnB5Iix0cnVlXQ== + + 2ab3b1eeaa702bb111bf269e23855761 + + + 1750189765951 + + UPDATE_NODE + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLHsid2lkdGgiOjE1NCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMjpzZWNvbmROb2RlLnB5Iix0cnVlXQ== + + + UPDATE_NODE + WyI3MTI2MTBkZC1mZDM0LTQ0MWUtOTk5OS04MmIyNDA1YTNkNWUiLHsid2lkdGgiOjE1NCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMjpCLnB5Iix0cnVlXQ== + + e2494c096e25828dd77c851848832639 + + + 1750189773017 + + UPDATE_NODE + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsid2lkdGgiOjEzNCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMzp0aGlyZE5vZGUucHkiLHRydWVd + + + UPDATE_NODE + WyJmMzFjZmNlYi05NzI3LTQ4OGYtOGNhNC1mNDFkNGUzNjBlMzkiLHsid2lkdGgiOjEzNCwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMzpDLnB5Iix0cnVlXQ== + + 5b9df460bea4d01e2ef0261302e1e7c1 + + + 1750191811368 + + UPDATE_EDGE + WyJlNDhhZjM3NS03Mjc1LTRhOTQtOWExZC00YmQ2NmM3MzQ1NDgiLHsidGhpY2tuZXNzIjoxLCJzaGFwZSI6InNvbGlkIn0sIjB4NDU2N19VIix0cnVlXQ== + + + UPDATE_EDGE + WyJlNDhhZjM3NS03Mjc1LTRhOTQtOWExZC00YmQ2NmM3MzQ1NDgiLHsidGhpY2tuZXNzIjoxLCJzaGFwZSI6InNvbGlkIn0sIjB4MTIzNF9VIix0cnVlXQ== + + 46236a6533af1eb9059e6953fd17dd63 + + + 1750191817718 + + UPDATE_EDGE + WyI5ZDEyNmRjMi05NjVhLTQxZjMtODA2ZS00ZmZlNzU4YTc2ZjMiLHsidGhpY2tuZXNzIjoxLCJzaGFwZSI6InNvbGlkIn0sIjB4NTY3OF9ZIix0cnVlXQ== + + + UPDATE_EDGE + WyI5ZDEyNmRjMi05NjVhLTQxZjMtODA2ZS00ZmZlNzU4YTc2ZjMiLHsidGhpY2tuZXNzIjoxLCJzaGFwZSI6InNvbGlkIn0sIjB4MTIzNV9ZIix0cnVlXQ== + + e4ead03fe18f22635d9cea49ae008114 + + + \ No newline at end of file diff --git a/measurements/comm_node_test.dir/concore2.py b/measurements/comm_node_test.dir/concore2.py new file mode 100644 index 0000000..a018ddf --- /dev/null +++ b/measurements/comm_node_test.dir/concore2.py @@ -0,0 +1,263 @@ +import time +import os +from ast import literal_eval +import sys +import re +import zmq # Added for ZeroMQ + +#if windows, create script to kill this process +# because batch files don't provide easy way to know pid of last command +# ignored for posix!=windows, because "concorepid" is handled by script +# ignored for docker (linux!=windows), because handled by docker stop +if hasattr(sys, 'getwindowsversion'): + with open("concorekill.bat","w") as fpid: + fpid.write("taskkill /F /PID "+str(os.getpid())+"\n") + +# --- ZeroMQ Integration Start --- +class ZeroMQPort: + def __init__(self, port_type, address, zmq_socket_type): + self.context = zmq.Context() + self.socket = self.context.socket(zmq_socket_type) + self.port_type = port_type # "bind" or "connect" + self.address = address + if self.port_type == "bind": + self.socket.bind(address) + print(f"ZMQ Port bound to {address}") + else: + self.socket.connect(address) + print(f"ZMQ Port connected to {address}") + +# Global ZeroMQ ports registry +zmq_ports = {} + +def init_zmq_port(port_name, port_type, address, socket_type_str): + """ + Initializes and registers a ZeroMQ port. + port_name (str): A unique name for this ZMQ port. + port_type (str): "bind" or "connect". + address (str): The ZMQ address (e.g., "tcp://*:5555", "tcp://localhost:5555"). + socket_type_str (str): String representation of ZMQ socket type (e.g., "REQ", "REP", "PUB", "SUB"). + """ + if port_name in zmq_ports: + print(f"ZMQ Port {port_name} already initialized.") + return # Avoid reinitialization + + try: + # Map socket type string to actual ZMQ constant (e.g., zmq.REQ, zmq.REP) + zmq_socket_type = getattr(zmq, socket_type_str.upper()) + zmq_ports[port_name] = ZeroMQPort(port_type, address, zmq_socket_type) + print(f"Initialized ZMQ port: {port_name} ({socket_type_str}) on {address}") + except AttributeError: + print(f"Error: Invalid ZMQ socket type string '{socket_type_str}'.") + except zmq.error.ZMQError as e: + print(f"Error initializing ZMQ port {port_name} on {address}: {e}") + except Exception as e: + print(f"An unexpected error occurred during ZMQ port initialization for {port_name}: {e}") + +def terminate_zmq(): + for port in zmq_ports.values(): + try: + port.socket.close() + port.context.term() + except Exception as e: + print(f"Error while terminating ZMQ port {port.address}: {e}") +# --- ZeroMQ Integration End --- + +def safe_literal_eval(filename, defaultValue): + try: + with open(filename, "r") as file: + return literal_eval(file.read()) + except (FileNotFoundError, SyntaxError, ValueError, Exception) as e: + # Keep print for debugging, but can be made quieter + # print(f"Info: Error reading {filename} or file not found, using default: {e}") + return defaultValue + +iport = safe_literal_eval("concore.iport", {}) +oport = safe_literal_eval("concore.oport", {}) + +s = '' +olds = '' +delay = 1 +retrycount = 0 +inpath = "./in" #must be rel path for local +outpath = "./out" +simtime = 0 + +#9/21/22 +try: + sparams_path = os.path.join(inpath + "1", "concore.params") + if os.path.exists(sparams_path): + with open(sparams_path, "r") as f: + sparams = f.read() + if sparams: # Ensure sparams is not empty + if sparams[0] == '"' and sparams[-1] == '"': #windows keeps "" need to remove + sparams = sparams[1:-1] + if sparams != '{' and not (sparams.startswith('{') and sparams.endswith('}')): # Check if it needs conversion + print("converting sparams: "+sparams) + sparams = "{'"+re.sub(';',",'",re.sub('=',"':",re.sub(' ','',sparams)))+"}" + print("converted sparams: " + sparams) + try: + params = literal_eval(sparams) + except Exception as e: + print(f"bad params content: {sparams}, error: {e}") + params = dict() + else: + params = dict() + else: + params = dict() +except Exception as e: + # print(f"Info: concore.params not found or error reading, using empty dict: {e}") + params = dict() + +#9/30/22 +def tryparam(n, i): + return params.get(n, i) + + +#9/12/21 +def default_maxtime(default): + global maxtime + maxtime_path = os.path.join(inpath + "1", "concore.maxtime") + maxtime = safe_literal_eval(maxtime_path, default) + +default_maxtime(100) + +def unchanged(): + global olds, s + if olds == s: + s = '' + return True + olds = s + return False + +def read(port_identifier, name, initstr_val): + global s, simtime, retrycount + + default_return_val = initstr_val + if isinstance(initstr_val, str): + try: + default_return_val = literal_eval(initstr_val) + except (SyntaxError, ValueError): + pass + + if isinstance(port_identifier, str) and port_identifier in zmq_ports: + zmq_p = zmq_ports[port_identifier] + try: + message = zmq_p.socket.recv_json() + return message + except zmq.error.ZMQError as e: + print(f"ZMQ read error on port {port_identifier} (name: {name}): {e}. Returning default.") + return default_return_val + except Exception as e: + print(f"Unexpected error during ZMQ read on port {port_identifier} (name: {name}): {e}. Returning default.") + return default_return_val + + try: + file_port_num = int(port_identifier) + except ValueError: + print(f"Error: Invalid port identifier '{port_identifier}' for file operation. Must be integer or ZMQ name.") + return default_return_val + + time.sleep(delay) + file_path = os.path.join(inpath+str(file_port_num), name) + ins = "" + + try: + with open(file_path, "r") as infile: + ins = infile.read() + except FileNotFoundError: + ins = str(initstr_val) + except Exception as e: + print(f"Error reading {file_path}: {e}. Using default value.") + return default_return_val + + attempts = 0 + max_retries = 5 + while len(ins) == 0 and attempts < max_retries: + time.sleep(delay) + try: + with open(file_path, "r") as infile: + ins = infile.read() + except Exception as e: + print(f"Retry {attempts + 1}: Error reading {file_path} - {e}") + attempts += 1 + retrycount += 1 + + if len(ins) == 0: + print(f"Max retries reached for {file_path}, using default value.") + return default_return_val + + s += ins + try: + inval = literal_eval(ins) + if isinstance(inval, list) and len(inval) > 0: + current_simtime_from_file = inval[0] + if isinstance(current_simtime_from_file, (int, float)): + simtime = max(simtime, current_simtime_from_file) + return inval[1:] + else: + print(f"Warning: Unexpected data format in {file_path}: {ins}. Returning raw content or default.") + return inval + except Exception as e: + print(f"Error parsing content from {file_path} ('{ins}'): {e}. Returning default.") + return default_return_val + + +def write(port_identifier, name, val, delta=0): + global simtime + + if isinstance(port_identifier, str) and port_identifier in zmq_ports: + zmq_p = zmq_ports[port_identifier] + try: + zmq_p.socket.send_json(val) + except zmq.error.ZMQError as e: + print(f"ZMQ write error on port {port_identifier} (name: {name}): {e}") + except Exception as e: + print(f"Unexpected error during ZMQ write on port {port_identifier} (name: {name}): {e}") + return + try: + if isinstance(port_identifier, str) and port_identifier in zmq_ports: + file_path = os.path.join("../"+port_identifier, name) + else: + file_port_num = int(port_identifier) + file_path = os.path.join(outpath+str(file_port_num), name) + except ValueError: + print(f"Error: Invalid port identifier '{port_identifier}' for file operation. Must be integer or ZMQ name.") + return + + if isinstance(val, str): + time.sleep(2 * delay) + elif not isinstance(val, list): + print(f"File write to {file_path} must have list or str value, got {type(val)}") + return + + try: + with open(file_path, "w") as outfile: + if isinstance(val, list): + data_to_write = [simtime + delta] + val + outfile.write(str(data_to_write)) + simtime += delta + else: + outfile.write(val) + except Exception as e: + print(f"Error writing to {file_path}: {e}") + +def initval(simtime_val_str): + global simtime + try: + val = literal_eval(simtime_val_str) + if isinstance(val, list) and len(val) > 0: + first_element = val[0] + if isinstance(first_element, (int, float)): + simtime = first_element + return val[1:] + else: + print(f"Error: First element in initval string '{simtime_val_str}' is not a number. Using data part as is or empty.") + return val[1:] if len(val) > 1 else [] + else: + print(f"Error: initval string '{simtime_val_str}' is not a list or is empty. Returning empty list.") + return [] + + except Exception as e: + print(f"Error parsing simtime_val_str '{simtime_val_str}': {e}. Returning empty list.") + return [] \ No newline at end of file diff --git a/measurements/comm_node_test.py b/measurements/comm_node_test.py new file mode 100644 index 0000000..dac015e --- /dev/null +++ b/measurements/comm_node_test.py @@ -0,0 +1,68 @@ +import concore +import concore2 +import time +import sys + +# --- Script Configuration --- +concore.delay = 0.07 +concore2.delay = 0.07 +concore2.inpath = concore.inpath +concore2.outpath = concore.outpath +concore2.simtime = 0 +concore.default_maxtime(100) # This will be ignored by the new logic +init_simtime_u = "[0.0, 0.0, 0.0]" +init_simtime_ym = "[0.0, 0.0, 0.0]" + +# --- Measurement Initialization --- +messages_processed = 0 +start_time = time.monotonic() + +# --- Main Script Logic --- +u = concore.initval(init_simtime_u) +ym = concore2.initval(init_simtime_ym) +curr = 0 +max_value = 100 +iteration = 0 +iteration_limit = 15 # Safety break + +print("comm_node_test.py started...") + +while curr < max_value and iteration < iteration_limit: + # 1. Wait for a message from the 'u' channel + while concore.unchanged(): + u = concore.read(concore.iport['U'], "u", init_simtime_u) + + # 2. Forward it to the 'U1' channel + concore.write(concore.oport['U1'], "u", u) + curr = u[0] + + # Break if the loop condition is met after the first read + if curr >= max_value: + # Forward a final message to ensure the next node also terminates + concore2.write(concore.oport['Y'], "ym", [curr]) + break + + # 3. Wait for a message from the 'Y1' channel + old2 = concore2.simtime + while concore2.unchanged() or concore2.simtime <= old2: + ym = concore2.read(concore.iport['Y1'], "ym", init_simtime_ym) + + # 4. Forward it to the 'Y' channel + concore2.write(concore.oport['Y'], "ym", ym) + curr = ym[0] + + print(f"comm_node: u={u[0]:.2f} | ym={ym[0]:.2f}") + + messages_processed += 2 # Counting one read and one write as two "processed" messages + iteration += 1 + +# --- Finalize and Report Measurements --- +end_time = time.monotonic() +duration = end_time - start_time + +print("\n" + "="*30) +print("--- COMM_NODE_TEST: FINAL RESULTS ---") +print(f"Total messages routed: {messages_processed}") +print(f"Total execution time: {duration:.4f} seconds") +print(f"concore retry count: {concore.retrycount}") +print("="*30) diff --git a/measurements/cpymax_test.py b/measurements/cpymax_test.py new file mode 100644 index 0000000..c7b50ed --- /dev/null +++ b/measurements/cpymax_test.py @@ -0,0 +1,78 @@ +import concore +import time +import os +import psutil +import sys + +# --- Measurement & Script Configuration --- +concore.delay = 0.01 +init_simtime_u = "[0.0, 0.0, 0.0]" +init_simtime_ym = "[0.0, 0.0, 0.0]" + +# --- Measurement Initialization --- +min_latency = float('inf') +max_latency = 0.0 +total_latency = 0.0 +message_count = 0 +total_bytes = 0 +process = psutil.Process(os.getpid()) +overall_start_time = time.monotonic() +wallclock1 = time.perf_counter() + +# --- Main Script Logic --- +u = concore.initval(init_simtime_u) +curr = 0.0 +max_value = 100.0 +iteration_limit = 15 # Safety break +iteration = 0 + +print("cpymax_test.py started...") + +# Initiate the loop by writing an initial value +print(f"ym=N/A u={u[0]:.2f} (initial)") +concore.write(1, "u", u) + +while curr < max_value and iteration < iteration_limit: + # Wait for the processed value to come back + while concore.unchanged(): + ym = concore.read(1, "ym", init_simtime_ym) + + wallclock2 = time.perf_counter() + latency_ms = (wallclock2 - wallclock1) * 1000 # Round-trip time in milliseconds + + # Update metrics + message_count += 1 + total_bytes += sys.getsizeof(ym) + min_latency = min(min_latency, latency_ms) + max_latency = max(max_latency, latency_ms) + total_latency += latency_ms + + # Prepare next value + u[0] = ym[0] + curr = u[0] + print(f"ym={ym[0]:.2f} u={u[0]:.2f} | Latency: {latency_ms:.2f} ms") + + # Write the value back into the loop + concore.write(1, "u", u) + wallclock1 = time.perf_counter() # Reset timer for next round-trip + iteration += 1 + +# --- Finalize and Report Measurements --- +overall_end_time = time.monotonic() +total_duration = overall_end_time - overall_start_time +cpu_usage = process.cpu_percent() / total_duration if total_duration > 0 else 0 +avg_latency = total_latency / message_count if message_count > 0 else 0 + +print("\n" + "="*30) +print("--- CPYMAX_TEST: FINAL RESULTS ---") +print(f"Total loop iterations: {message_count}") +print(f"Total data received: {total_bytes / 1024:.4f} KB") +print(f"Total execution time: {total_duration:.4f} seconds") +print("-" * 30) +print(f"Min round-trip latency: {min_latency:.2f} ms") +print(f"Avg round-trip latency: {avg_latency:.2f} ms") +print(f"Max round-trip latency: {max_latency:.2f} ms") +print("-" * 30) +print(f"Approximate CPU usage: {cpu_usage:.2f}%") +print(f"concore retry count: {concore.retrycount}") +print("="*30) diff --git a/measurements/fileOnlyCommunication.graphml b/measurements/fileOnlyCommunication.graphml new file mode 100644 index 0000000..522cad1 --- /dev/null +++ b/measurements/fileOnlyCommunication.graphml @@ -0,0 +1,508 @@ + + + + + + + + + + + + PZ:pmpymax_test.py + + + + + + + + + + + CZ:cpymax_test.py + + + + + + + + + + + F1:comm_node_test.py + + + + + + + + + + U + + + + + + + + + + + + Y + + + + + + + + + + + + U1 + + + + + + + + + + + + Y1 + + + + + + + + 1664644923582 + + DEL_NODE + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciXQ== + + + ADD_NODE + WyJQWjpwbXB5bWF4LnB5Iix7IndpZHRoIjoxMzYsImhlaWdodCI6NTAsInNoYXBlIjoicmVjdGFuZ2xlIiwib3BhY2l0eSI6MSwiYmFja2dyb3VuZENvbG9yIjoiI2ZmY2MwMCIsImJvcmRlckNvbG9yIjoiIzAwMCIsImJvcmRlcldpZHRoIjoxfSwib3JkaW4iLHsieCI6NTg3LjE1NzgxMTg0NjY1NTYsInkiOjEwMC40NDIzMjkyNjUzNzgzNn0se30sImJkOTJmOWQ4LTdkNjMtNDJiMi05NjhiLTM5MDllZjRjNzIzNyJd + + a53a7f7273a40c7970938b6de1829249 + + + 1664644939781 + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6MTAwLCJ5IjoxMDB9LHsieCI6NDA0LjIzNDYxMDc2NDgxNDIsInkiOi04OS4wMTM4NDMyODM2NzE3OH1d + + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NDA0LjIzNDYxMDc2NDgxNDIsInkiOi04OS4wMTM4NDMyODM2NzE3OH0seyJ4IjoxMDAsInkiOjEwMH1d + + 3d4a875a8a6ea281598aa70364b0ea82 + + + 1664644951652 + + DEL_NODE + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiXQ== + + + ADD_NODE + WyJDWjpjcHltYXgucHkiLHsid2lkdGgiOjEyMiwiaGVpZ2h0Ijo1MCwic2hhcGUiOiJyZWN0YW5nbGUiLCJvcGFjaXR5IjoxLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJvcmRpbiIseyJ4IjotMTM3Ljc3NjIwMzU0OTQyMzgzLCJ5Ijo5MS4zMjAxMjcwNjgyNTY0MX0se30sImQ5NWY3ODg3LTQyYmYtNGUxMi1hMDIyLTAyMTg2OTcwMWM2YSJd + + 5ed7e3d12fd25656b2ad03e29c307d65 + + + 1664644958838 + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6MTAwLCJ5IjoxMDB9LHsieCI6OTcuNDEwNzY5MjcwMDg2NjksInkiOi05MS42MDMwNzQwMTM1ODUxfV0= + + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6OTcuNDEwNzY5MjcwMDg2NjksInkiOi05MS42MDMwNzQwMTM1ODUxfSx7IngiOjEwMCwieSI6MTAwfV0= + + 35c613c8203b65e1f44e066b3d783143 + + + 1664644988539 + + DEL_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiXQ== + + + ADD_NODE + WyJGMTpmdW5jYWxsLnB5Iix7IndpZHRoIjoxMTEsImhlaWdodCI6NTAsInNoYXBlIjoicmVjdGFuZ2xlIiwib3BhY2l0eSI6MSwiYmFja2dyb3VuZENvbG9yIjoiI2ZmY2MwMCIsImJvcmRlckNvbG9yIjoiIzAwMCIsImJvcmRlcldpZHRoIjoxfSwib3JkaW4iLHsieCI6MTAwLCJ5Ijo5NC43NzM2MjI4MjYyMzMxMX0se30sImY1NmY4YjI0LTQxYTYtNDViNC04ODJiLTY1OTYwNDBiNmFmMCJd + + 33d0b0cc4d3dbe3c42323e33f06993e9 + + + 1664645002278 + + DEL_NODE + WyJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiXQ== + + + ADD_NODE + WyJGMjpmdW5ib2R5LnB5Iix7IndpZHRoIjoxMjAsImhlaWdodCI6NTAsInNoYXBlIjoicmVjdGFuZ2xlIiwib3BhY2l0eSI6MSwiYmFja2dyb3VuZENvbG9yIjoiI2ZmY2MwMCIsImJvcmRlckNvbG9yIjoiIzAwMCIsImJvcmRlcldpZHRoIjoxfSwib3JkaW4iLHsieCI6MzM2LjAxODYzNzA4NTU4NjY1LCJ5IjoxMDAuOTM3NjkyNDQ1MzAzNDF9LHt9LCJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiXQ== + + 8d0d4a735631afe6241c66143fb29db8 + + + 1664645010353 + + SET_POS + WyJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLHsieCI6MTEwLCJ5IjoxMTB9LHsieCI6Mzk0LjgxNTM4MDI5MDQ2NDMsInkiOjEwMC45Mzc2OTI0NDUzMDM0MX1d + + + SET_POS + WyJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLHsieCI6Mzk0LjgxNTM4MDI5MDQ2NDMsInkiOjEwMC45Mzc2OTI0NDUzMDM0MX0seyJ4IjoxMTAsInkiOjExMH1d + + 8a01a9ca8b3706bc3b1ce4de33669b6d + + + 1664645015576 + + DEL_EDGE + WyIwZjk1MWZiYy0wZDNmLTQzYzAtYmJmMC04NjViYzQ3ZjEyMGUiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLCJ0YXJnZXRJRCI6ImY1NmY4YjI0LTQxYTYtNDViNC04ODJiLTY1OTYwNDBiNmFmMCIsImxhYmVsIjoiVSIsInN0eWxlIjp7InRoaWNrbmVzcyI6MSwiYmFja2dyb3VuZENvbG9yIjoiIzgyNzcxNyIsInNoYXBlIjoic29saWQifSwiaWQiOiIwZjk1MWZiYy0wZDNmLTQzYzAtYmJmMC04NjViYzQ3ZjEyMGUifV0= + + 14416fc2e3c48db65e2b5e1012027ee0 + + + 1664645043815 + + DEL_EDGE + WyIzY2ZiNDBjZC01NTdhLTQ4NTAtOTNhNi1mZGMwOWNkMDA1ZjAiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLCJ0YXJnZXRJRCI6ImRiMzFiZTNmLTNlNTgtNGMzNi05NzlkLTQxZmIyOGFlZmU2OCIsImxhYmVsIjoiVTEiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiM3YzRkZmYiLCJzaGFwZSI6InNvbGlkIn0sImlkIjoiM2NmYjQwY2QtNTU3YS00ODUwLTkzYTYtZmRjMDljZDAwNWYwIn1d + + 326a920ffd7e662bc64ca95c086fb9de + + + 1664645057658 + + DEL_EDGE + WyI3MTRkYjk4OS01NjcyLTQwM2ItYWU3Ni1mZDlhMjA4OTM0NzUiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLCJ0YXJnZXRJRCI6ImJkOTJmOWQ4LTdkNjMtNDJiMi05NjhiLTM5MDllZjRjNzIzNyIsImxhYmVsIjoiVTIiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmZjZkMDAiLCJzaGFwZSI6InNvbGlkIn0sImlkIjoiNzE0ZGI5ODktNTY3Mi00MDNiLWFlNzYtZmQ5YTIwODkzNDc1In1d + + 4593337e9924ae4b23dc5c5576c31394 + + + 1664645068951 + + DEL_EDGE + WyJhOGFlNzg5MC1iMmJiLTQyNzMtODc1My0wMTgxY2ViNDg2YzEiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLCJ0YXJnZXRJRCI6ImRiMzFiZTNmLTNlNTgtNGMzNi05NzlkLTQxZmIyOGFlZmU2OCIsImxhYmVsIjoiWTIiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmNDQzMzYiLCJzaGFwZSI6InNvbGlkIn0sImlkIjoiYThhZTc4OTAtYjJiYi00MjczLTg3NTMtMDE4MWNlYjQ4NmMxIn1d + + 568d8b7a109ffacc4b912095793cb2ca + + + 1664645081283 + + DEL_EDGE + WyI1NWI5OWFiNi1hN2Q2LTRjNjctYWI0ZS1hOGUyOTM5YzFiMGYiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLCJ0YXJnZXRJRCI6ImY1NmY4YjI0LTQxYTYtNDViNC04ODJiLTY1OTYwNDBiNmFmMCIsImxhYmVsIjoiWTEiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmZjZkMDAiLCJzaGFwZSI6InNvbGlkIn0sImlkIjoiNTViOTlhYjYtYTdkNi00YzY3LWFiNGUtYThlMjkzOWMxYjBmIn1d + + 0d0aa0179f22f9d73a11f8ccfbcc145e + + + 1664645089735 + + SET_POS + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsieCI6MTAwLCJ5IjoxMDB9LHsieCI6MTAwLCJ5Ijo5NC43NzM2MjI4MjYyMzMxMX1d + + + SET_POS + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsieCI6MTAwLCJ5Ijo5NC43NzM2MjI4MjYyMzMxMX0seyJ4IjoxMDAsInkiOjEwMH1d + + 1c19591402c0f2daca7d2b4a8af5e956 + + + 1664645092868 + + DEL_EDGE + WyI3OWE1NDdmNS02NzBhLTQ1ZjYtYTc4My02ZGI4ZmYwZTY1NTkiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLCJ0YXJnZXRJRCI6ImQ5NWY3ODg3LTQyYmYtNGUxMi1hMDIyLTAyMTg2OTcwMWM2YSIsImxhYmVsIjoiWSIsInN0eWxlIjp7InRoaWNrbmVzcyI6MSwiYmFja2dyb3VuZENvbG9yIjoiIzgyNzcxNyIsInNoYXBlIjoic29saWQifSwiaWQiOiI3OWE1NDdmNS02NzBhLTQ1ZjYtYTc4My02ZGI4ZmYwZTY1NTkifV0= + + 3c913497d8aa8f1c79bbdc03c3feec16 + + + 1664645142026 + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6OTcuNDEwNzY5MjcwMDg2NjksInkiOi05MS42MDMwNzQwMTM1ODUxfSx7IngiOi0xNzAuNDQxMDYwODg1NDY2OTUsInkiOjkwLjAxMzUzMjc3NDgxNDY5fV0= + + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6LTE3MC40NDEwNjA4ODU0NjY5NSwieSI6OTAuMDEzNTMyNzc0ODE0Njl9LHsieCI6OTcuNDEwNzY5MjcwMDg2NjksInkiOi05MS42MDMwNzQwMTM1ODUxfV0= + + ecbd46b28ecaf800c8da0d2ada69b4de + + + 1664645149601 + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NDA0LjIzNDYxMDc2NDgxNDIsInkiOi04OS4wMTM4NDMyODM2NzE3OH0seyJ4Ijo3NTQuNDAxODgxNDA3MTk2NSwieSI6OTkuMTM1NzM0OTcxOTM2NjR9XQ== + + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NzU0LjQwMTg4MTQwNzE5NjUsInkiOjk5LjEzNTczNDk3MTkzNjY0fSx7IngiOjQwNC4yMzQ2MTA3NjQ4MTQyLCJ5IjotODkuMDEzODQzMjgzNjcxNzh9XQ== + + ea35c112764d7964f8b7e35e9a18efbd + + + 1664645223291 + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NzU0LjQwMTg4MTQwNzE5NjUsInkiOjk5LjEzNTczNDk3MTkzNjY0fSx7IngiOjY3Ni4wMDYyMjM4MDA2OTMsInkiOjEwMC40NDIzMjkyNjUzNzgzNn1d + + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6Njc2LjAwNjIyMzgwMDY5MywieSI6MTAwLjQ0MjMyOTI2NTM3ODM2fSx7IngiOjc1NC40MDE4ODE0MDcxOTY1LCJ5Ijo5OS4xMzU3MzQ5NzE5MzY2NH1d + + d669d3d37a4693ad860a18c69999b31f + + + 1664645228453 + + SET_POS + WyJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLHsieCI6Mzk0LjgxNTM4MDI5MDQ2NDMsInkiOjEwMC45Mzc2OTI0NDUzMDM0MX0seyJ4IjozMzYuMDE4NjM3MDg1NTg2NjUsInkiOjEwMC45Mzc2OTI0NDUzMDM0MX1d + + + SET_POS + WyJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLHsieCI6MzM2LjAxODYzNzA4NTU4NjY1LCJ5IjoxMDAuOTM3NjkyNDQ1MzAzNDF9LHsieCI6Mzk0LjgxNTM4MDI5MDQ2NDMsInkiOjEwMC45Mzc2OTI0NDUzMDM0MX1d + + f7eb6af4003cb4eff19f39421fc00174 + + + 1664645231883 + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6Njc2LjAwNjIyMzgwMDY5MywieSI6MTAwLjQ0MjMyOTI2NTM3ODM2fSx7IngiOjU4Ny4xNTc4MTE4NDY2NTU2LCJ5IjoxMDAuNDQyMzI5MjY1Mzc4MzZ9XQ== + + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NTg3LjE1NzgxMTg0NjY1NTYsInkiOjEwMC40NDIzMjkyNjUzNzgzNn0seyJ4Ijo2NzYuMDA2MjIzODAwNjkzLCJ5IjoxMDAuNDQyMzI5MjY1Mzc4MzZ9XQ== + + 49dd0c2013be6e39c2f11ea967dbcab4 + + + 1664645237206 + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6LTE3MC40NDEwNjA4ODU0NjY5NSwieSI6OTAuMDEzNTMyNzc0ODE0Njl9LHsieCI6LTEzNy43NzYyMDM1NDk0MjM4MywieSI6OTEuMzIwMTI3MDY4MjU2NDF9XQ== + + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6LTEzNy43NzYyMDM1NDk0MjM4MywieSI6OTEuMzIwMTI3MDY4MjU2NDF9LHsieCI6LTE3MC40NDEwNjA4ODU0NjY5NSwieSI6OTAuMDEzNTMyNzc0ODE0Njl9XQ== + + 009fc03903a9ae6003caea49a6575ddb + + + 1664646509534 + + ADD_EDGE + W3sic291cmNlSUQiOiJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLCJ0YXJnZXRJRCI6ImJkOTJmOWQ4LTdkNjMtNDJiMi05NjhiLTM5MDllZjRjNzIzNyIsImxhYmVsIjoiVTIiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmZjZkMDAiLCJzaGFwZSI6InNvbGlkIn0sInR5cGUiOiJvcmRpbiIsInNvdXJjZSI6IjYyOGMyOTI0LWI2YzEtNDBjNi05ZjM5LTZjMDUxNmI3MGI1YSIsInRhcmdldCI6ImJkOTJmOWQ4LTdkNjMtNDJiMi05NjhiLTM5MDllZjRjNzIzNyIsImJlbmREYXRhIjp7ImJlbmREaXN0YW5jZSI6MCwiYmVuZFdlaWdodCI6MC41LCJiZW5kUG9pbnQiOnsieCI6NDkxLjU4ODIyNDQ2NjEyMTEsInkiOjEwMC42MzA4MzY4MzIxNzMyMn19LCJpZCI6IjcxNGRiOTg5LTU2NzItNDAzYi1hZTc2LWZkOWEyMDg5MzQ3NSJ9XQ== + + + DEL_EDGE + WyI3MTRkYjk4OS01NjcyLTQwM2ItYWU3Ni1mZDlhMjA4OTM0NzUiXQ== + + 86704f8d36bc9bfa5f599c3a4b445d78 + + + 1664646579649 + + DEL_EDGE + WyIwM2RlN2FjYS1hZTA0LTQ5ZWEtYThjZC04YTg3YTA0MjA0ZjEiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLCJ0YXJnZXRJRCI6ImJkOTJmOWQ4LTdkNjMtNDJiMi05NjhiLTM5MDllZjRjNzIzNyIsImlkIjoiMDNkZTdhY2EtYWUwNC00OWVhLWE4Y2QtOGE4N2EwNDIwNGYxIn1d + + 44b7833e0adb98fcda7606fe873176a4 + + + 1664646592082 + + ADD_EDGE + W3sic291cmNlSUQiOiJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLCJ0YXJnZXRJRCI6ImY1NmY4YjI0LTQxYTYtNDViNC04ODJiLTY1OTYwNDBiNmFmMCIsImxhYmVsIjoiWTEiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmZjZkMDAiLCJzaGFwZSI6InNvbGlkIn0sInR5cGUiOiJvcmRpbiIsInNvdXJjZSI6ImZlYjllMGU5LTA2NTktNDdmYy1iNGQzLTZiZGRkOGM2YjNkNiIsInRhcmdldCI6ImY1NmY4YjI0LTQxYTYtNDViNC04ODJiLTY1OTYwNDBiNmFmMCIsImJlbmREYXRhIjp7ImJlbmREaXN0YW5jZSI6MjAsImJlbmRXZWlnaHQiOjAuNSwiYmVuZFBvaW50Ijp7IngiOjE4Ny42MDY5NDA0NzI4NDkzLCJ5Ijo3My4wMDY2NjE0ODk4MDV9fSwiaWQiOiI1NWI5OWFiNi1hN2Q2LTRjNjctYWI0ZS1hOGUyOTM5YzFiMGYifV0= + + + DEL_EDGE + WyI1NWI5OWFiNi1hN2Q2LTRjNjctYWI0ZS1hOGUyOTM5YzFiMGYiXQ== + + 980dd3b8b785d6454a88fd4a0b28c931 + + + 1664646592082 + + ADD_EDGE + W3sic291cmNlSUQiOiJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLCJ0YXJnZXRJRCI6ImRiMzFiZTNmLTNlNTgtNGMzNi05NzlkLTQxZmIyOGFlZmU2OCIsImxhYmVsIjoiWTIiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmNDQzMzYiLCJzaGFwZSI6InNvbGlkIn0sInR5cGUiOiJvcmRpbiIsInNvdXJjZSI6Ijg3ODFjMWFiLTI3MzUtNGE1NS1iMzQyLWExMzBhNTlmMzcwNyIsInRhcmdldCI6ImRiMzFiZTNmLTNlNTgtNGMzNi05NzlkLTQxZmIyOGFlZmU2OCIsImJlbmREYXRhIjp7ImJlbmREaXN0YW5jZSI6MjAsImJlbmRXZWlnaHQiOjAuNSwiYmVuZFBvaW50Ijp7IngiOjQyNi42MTkzODI1NjIzMjg2LCJ5Ijo3Ni41MjAxMzYxMTU4NzI2NX19LCJpZCI6ImE4YWU3ODkwLWIyYmItNDI3My04NzUzLTAxODFjZWI0ODZjMSJ9XQ== + + + DEL_EDGE + WyJhOGFlNzg5MC1iMmJiLTQyNzMtODc1My0wMTgxY2ViNDg2YzEiXQ== + + 167c73cd93b1abdcd56b452ed8d8c24e + + + 1664646592082 + + ADD_EDGE + W3sic291cmNlSUQiOiJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLCJ0YXJnZXRJRCI6ImRiMzFiZTNmLTNlNTgtNGMzNi05NzlkLTQxZmIyOGFlZmU2OCIsImxhYmVsIjoiVTEiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiM3YzRkZmYiLCJzaGFwZSI6InNvbGlkIn0sInR5cGUiOiJvcmRpbiIsInNvdXJjZSI6ImFhNjZiNDZiLTRkYTgtNDAxMC1iODk0LWQ0YmFhNWEzYWY4MiIsInRhcmdldCI6ImRiMzFiZTNmLTNlNTgtNGMzNi05NzlkLTQxZmIyOGFlZmU2OCIsImJlbmREYXRhIjp7ImJlbmREaXN0YW5jZSI6MC4wMDAwMjc4NjgxNzM4NjU0NjQwMywiYmVuZFdlaWdodCI6MC41MDAwMDAwMDQwMzA1MDY2LCJiZW5kUG9pbnQiOnsieCI6MjQ1Ljc1OTMxODQ3MDQxOTI2LCJ5Ijo5OC4zNDU3NTk1MDM4MjE4N319LCJpZCI6IjNjZmI0MGNkLTU1N2EtNDg1MC05M2E2LWZkYzA5Y2QwMDVmMCJ9XQ== + + + DEL_EDGE + WyIzY2ZiNDBjZC01NTdhLTQ4NTAtOTNhNi1mZGMwOWNkMDA1ZjAiXQ== + + d2945a87d6e5d69e9ab87ba9fc45210a + + + 1664646592082 + + ADD_NODE + WyJGMjpmdW5ib2R5LnB5Iix7IndpZHRoIjoxMjAsImhlaWdodCI6NTAsInNoYXBlIjoicmVjdGFuZ2xlIiwib3BhY2l0eSI6MSwiYmFja2dyb3VuZENvbG9yIjoiI2ZmY2MwMCIsImJvcmRlckNvbG9yIjoiIzAwMCIsImJvcmRlcldpZHRoIjoxfSwib3JkaW4iLHsieCI6MzM2LjAxODYzNzA4NTU4NjY1LCJ5IjoxMDAuOTM3NjkyNDQ1MzAzNDF9LHsiaWQiOiJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiLCJsYWJlbCI6IkYyOmZ1bmJvZHkucHkiLCJ0eXBlIjoib3JkaW4iLCJzdHlsZSI6eyJ3aWR0aCI6MTIwLCJoZWlnaHQiOjUwLCJzaGFwZSI6InJlY3RhbmdsZSIsIm9wYWNpdHkiOjEsImJhY2tncm91bmRDb2xvciI6IiNmZmNjMDAiLCJib3JkZXJDb2xvciI6IiMwMDAiLCJib3JkZXJXaWR0aCI6MX19LCJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiXQ== + + + DEL_NODE + WyJkYjMxYmUzZi0zZTU4LTRjMzYtOTc5ZC00MWZiMjhhZWZlNjgiXQ== + + 339f60a97384ac1435d5512fd70f37b7 + + + 1664646604837 + + DEL_EDGE + WyIzN2UyMzg0NC1hODgwLTQ1MjktOTA2Mi00YmIyNTIxZTI5YzUiXQ== + + + ADD_EDGE + W3sic291cmNlSUQiOiJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLCJ0YXJnZXRJRCI6ImY1NmY4YjI0LTQxYTYtNDViNC04ODJiLTY1OTYwNDBiNmFmMCIsImxhYmVsIjoiWTEiLCJzdHlsZSI6eyJ0aGlja25lc3MiOjEsImJhY2tncm91bmRDb2xvciI6IiNmZjZkMDAiLCJzaGFwZSI6InNvbGlkIn0sImlkIjoiMzdlMjM4NDQtYTg4MC00NTI5LTkwNjItNGJiMjUyMWUyOWM1In1d + + bfa293ad0bde125ea5db2d194297d66a + + + 1749408065766 + + UPDATE_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsid2lkdGgiOjExMSwiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpmdW5jYWxsLnB5Iix0cnVlXQ== + + + UPDATE_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsid2lkdGgiOjE1MywiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpjb21tX25vZGUucHkiLHRydWVd + + 6806b2037ce2ff878ea6f1ec962044b0 + + + 1749408086201 + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NTg3LjE1NzgxMTg0NjY1NTYsInkiOjEwMC40NDIzMjkyNjUzNzgzNn0seyJ4IjozODEuMTU3ODExODQ2NjU1NiwieSI6OTQuNDQyMzI5MjY1Mzc4MzZ9XQ== + + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6MzgxLjE1NzgxMTg0NjY1NTYsInkiOjk0LjQ0MjMyOTI2NTM3ODM2fSx7IngiOjU4Ny4xNTc4MTE4NDY2NTU2LCJ5IjoxMDAuNDQyMzI5MjY1Mzc4MzZ9XQ== + + c851b427b6f20d6ba88759a36ec55409 + + + 1749408089116 + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6LTEzNy43NzYyMDM1NDk0MjM4MywieSI6OTEuMzIwMTI3MDY4MjU2NDF9LHsieCI6LTE5Ni43NzYyMDM1NDk0MjM4MywieSI6OTQuMzIwMTI3MDY4MjU2NDF9XQ== + + + SET_POS + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsieCI6LTE5Ni43NzYyMDM1NDk0MjM4MywieSI6OTQuMzIwMTI3MDY4MjU2NDF9LHsieCI6LTEzNy43NzYyMDM1NDk0MjM4MywieSI6OTEuMzIwMTI3MDY4MjU2NDF9XQ== + + 5754a9589aae86257d22e65d39587d65 + + + 1749408091800 + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6MzgxLjE1NzgxMTg0NjY1NTYsInkiOjk0LjQ0MjMyOTI2NTM3ODM2fSx7IngiOjQwMS4xNTc4MTE4NDY2NTU2LCJ5Ijo5My40NDIzMjkyNjUzNzgzNn1d + + + SET_POS + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsieCI6NDAxLjE1NzgxMTg0NjY1NTYsInkiOjkzLjQ0MjMyOTI2NTM3ODM2fSx7IngiOjM4MS4xNTc4MTE4NDY2NTU2LCJ5Ijo5NC40NDIzMjkyNjUzNzgzNn1d + + 888e627d6b97ef44aaaef82e629bb77c + + + 1750196730434 + + UPDATE_NODE + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsid2lkdGgiOjEyMiwiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJDWjpjcHltYXgucHkiLHRydWVd + + + UPDATE_NODE + WyJkOTVmNzg4Ny00MmJmLTRlMTItYTAyMi0wMjE4Njk3MDFjNmEiLHsid2lkdGgiOjE1NywiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJDWjpjcHltYXhfdGVzdC5weSIsdHJ1ZV0= + + a8b51b5dca1f266f68d8df4a6fab373d + + + 1750196739873 + + UPDATE_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsid2lkdGgiOjE1MywiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpjb21tX25vZGUucHkiLHRydWVd + + + UPDATE_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsid2lkdGgiOjE4NywiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpjb21tX25vZGVfdGVzdC5weSIsdHJ1ZV0= + + 45e59fe61196c6e17fa107b0b1758248 + + + 1750196745274 + + UPDATE_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsid2lkdGgiOjE4NywiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpjb21tX25vZGVfdGVzdC5weSIsdHJ1ZV0= + + + UPDATE_NODE + WyJmNTZmOGIyNC00MWE2LTQ1YjQtODgyYi02NTk2MDQwYjZhZjAiLHsid2lkdGgiOjE4NywiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJGMTpjb21tX25vZGVfdGVzdC5weSIsdHJ1ZV0= + + f67f25a50f6f37ff6cd2266ab2fb2c7c + + + 1750196749273 + + UPDATE_NODE + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsid2lkdGgiOjEzNiwiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJQWjpwbXB5bWF4LnB5Iix0cnVlXQ== + + + UPDATE_NODE + WyJiZDkyZjlkOC03ZDYzLTQyYjItOTY4Yi0zOTA5ZWY0YzcyMzciLHsid2lkdGgiOjE3MCwiaGVpZ2h0Ijo1MCwib3BhY2l0eSI6MSwic2hhcGUiOiJyZWN0YW5nbGUiLCJiYWNrZ3JvdW5kQ29sb3IiOiIjZmZjYzAwIiwiYm9yZGVyQ29sb3IiOiIjMDAwIiwiYm9yZGVyV2lkdGgiOjF9LCJQWjpwbXB5bWF4X3Rlc3QucHkiLHRydWVd + + 4a9793f8c81214e6bf6b95371521c05d + + + \ No newline at end of file diff --git a/measurements/pmpymax_test.py b/measurements/pmpymax_test.py new file mode 100644 index 0000000..b735c25 --- /dev/null +++ b/measurements/pmpymax_test.py @@ -0,0 +1,57 @@ +import concore +import time +import os +import psutil +import sys + +# --- Script Configuration --- +concore.delay = 0.01 +init_simtime_u = "[0.0, 0.0, 0.0]" +init_simtime_ym = "[0.0, 0.0, 0.0]" + +# --- Measurement Initialization --- +process = psutil.Process(os.getpid()) +start_time = time.monotonic() +message_count = 0 +total_bytes = 0 + +# --- Main Script Logic --- +ym = concore.initval(init_simtime_ym) +curr = 0.0 +max_value = 100.0 +iteration = 0 +iteration_limit = 15 # Safety break + +print("pmpymax_test.py started...") + +while curr < max_value and iteration < iteration_limit: + # Wait for a value from the other node + while concore.unchanged(): + u = concore.read(1, "u", init_simtime_u) + + # Update metrics for received data + message_count += 1 + total_bytes += sys.getsizeof(u) + + # Process the value + ym[0] = u[0] + 10 # Using a smaller increment to match the A-B-C logic + curr = ym[0] + print(f"pmpymax: u={u[0]:.2f} -> ym={ym[0]:.2f}") + + # Write the processed value back + concore.write(1, "ym", ym, delta=1) + iteration += 1 + +# --- Finalize and Report Measurements --- +end_time = time.monotonic() +duration = end_time - start_time +cpu_usage = process.cpu_percent() / duration if duration > 0 else 0 + +print("\n" + "="*30) +print("--- PMPYMAX_TEST: FINAL RESULTS ---") +print(f"Total messages processed: {message_count}") +print(f"Total data processed: {total_bytes / 1024:.4f} KB") +print(f"Total execution time: {duration:.4f} seconds") +print(f"Approximate CPU usage: {cpu_usage:.2f}%") +print(f"concore retry count: {concore.retrycount}") +print("="*30)