S03-H3 CLOSED baseline

This commit is contained in:
2026-08-27 11:12:22 +02:00
commit 4b5fbb6c23
30 changed files with 10130 additions and 0 deletions
+722
View File
@@ -0,0 +1,722 @@
#!/usr/bin/env bash
set -u
if [ "$#" -ne 1 ]; then
printf "Uso: %s <directory-run|run.log>\n" "$0" >&2
exit 2
fi
INPUT_PATH="$1"
if [ -d "$INPUT_PATH" ]; then
RUN_DIR="$(cd "$INPUT_PATH" >/dev/null 2>&1 && pwd)"
RUN_LOG="$RUN_DIR/run.log"
elif [ -f "$INPUT_PATH" ]; then
RUN_LOG="$(cd "$(dirname "$INPUT_PATH")" >/dev/null 2>&1 && pwd)/$(basename "$INPUT_PATH")"
RUN_DIR="$(dirname "$RUN_LOG")"
else
printf "[NON DIMOSTRATO] Percorso di validazione non trovato: %s\n" "$INPUT_PATH" >&2
exit 21
fi
RUN_CONFIG="$RUN_DIR/configuration.marte"
OUTPUT_FILE="$RUN_DIR/s02_output.bin"
RUNNER_SUMMARY="$RUN_DIR/runner_summary.txt"
for required_file in "$RUN_LOG" "$RUN_CONFIG" "$OUTPUT_FILE"; do
if [ ! -f "$required_file" ]; then
printf "[NON DIMOSTRATO] File richiesto assente: %s\n" "$required_file" >&2
exit 21
fi
done
count_lines() {
pattern="$1"
file="$2"
grep -Ec "$pattern" "$file" 2>/dev/null || true
}
START_LINES="$(count_lines '^\[Information - RealTimeLoader\.cpp:[0-9]+\]: Started application in state State1[[:space:]]*$' "$RUN_LOG")"
APPLICATION_START_LINES="$(count_lines '^\[Information - MARTeApp\.cpp:[0-9]+\]: Application starting[[:space:]]*$' "$RUN_LOG")"
FILE_OPEN_LINES="$(count_lines '^\[Information - FileWriter\.cpp:[0-9]+\]: Going to open file with name ' "$RUN_LOG")"
SIGINT_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application recieved SIGINT\.[[:space:]]*$' "$RUN_LOG")"
STOP_OK_LINES="$(count_lines '^\[Information - Bootstrap\.cpp:[0-9]+\]: Application successfully stopped\.[[:space:]]*$' "$RUN_LOG")"
TERMINATED_LINES="$(count_lines '^\[NoError - MARTeApp\.cpp:[0-9]+\]: Application terminated[[:space:]]*$' "$RUN_LOG")"
STARTUP_ERROR_LINES="$(count_lines 'Failed dlopen|Failed CreateByName|Failed to Initialise object|Failed to initialise the ObjectRegistryDatabase|Could not Initialise the loader' "$RUN_LOG")"
FATAL_ERROR_LINES="$(count_lines '^\[FatalError ' "$RUN_LOG")"
OS_ERROR_LINES="$(count_lines '^\[OSError ' "$RUN_LOG")"
ERROR_LINES="$(count_lines '^\[Error ' "$RUN_LOG")"
INITIALISATION_ERROR_LINES="$(count_lines '^\[InitialisationEr ' "$RUN_LOG")"
NO_ERROR_LINES="$(count_lines '^\[NoError ' "$RUN_LOG")"
WARNING_LINES="$(count_lines '^\[Warning ' "$RUN_LOG")"
PRIORITY_CLIP_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Requested a thread priority that is higher than ' "$RUN_LOG")"
PRIORITY_FAIL_LINES="$(count_lines '^\[Warning - Threads\.cpp:[0-9]+\]: Failed to change the thread priority' "$RUN_LOG")"
UNCLASSIFIED_WARNING_LINES=$((WARNING_LINES - PRIORITY_CLIP_LINES - PRIORITY_FAIL_LINES))
if [ "$UNCLASSIFIED_WARNING_LINES" -lt 0 ]; then
UNCLASSIFIED_WARNING_LINES=0
fi
DOUBLE_STOP_LINES="$(count_lines '^\[FatalError - RealTimeApplication\.cpp:[0-9]+\]: Could not stop the RealTimeApplication\. Was it ever started\?[[:space:]]*$' "$RUN_LOG")"
ASYNC_EVENTSEM_CLOSE_LINES="$(count_lines '^\[FatalError - MemoryMapAsyncOutputBroker\.cpp:[0-9]+\]: Could not Close the EventSem\.[[:space:]]*$' "$RUN_LOG")"
PTHREAD_MUTEX_DESTROY_LINES="$(count_lines '^\[OSError - EventSem\.cpp:[0-9]+\]: Error: pthread_mutex_destroy\(\)[[:space:]]*$' "$RUN_LOG")"
UNCLASSIFIED_FATAL_LINES=$((FATAL_ERROR_LINES - DOUBLE_STOP_LINES - ASYNC_EVENTSEM_CLOSE_LINES))
UNCLASSIFIED_OS_ERROR_LINES=$((OS_ERROR_LINES - PTHREAD_MUTEX_DESTROY_LINES))
if [ "$UNCLASSIFIED_FATAL_LINES" -lt 0 ]; then
UNCLASSIFIED_FATAL_LINES=0
fi
if [ "$UNCLASSIFIED_OS_ERROR_LINES" -lt 0 ]; then
UNCLASSIFIED_OS_ERROR_LINES=0
fi
PLACEHOLDER_COUNT="$(grep -o '__MARTE_RUN_DIR__' "$RUN_CONFIG" 2>/dev/null | wc -l)"
NAMESPACED_CLASS_COUNT="$(count_lines '^[[:space:]]*Class = FileDataSource::FileWriter[[:space:]]*$' "$RUN_CONFIG")"
PLAIN_CLASS_COUNT="$(count_lines '^[[:space:]]*Class = FileWriter[[:space:]]*$' "$RUN_CONFIG")"
EXPECTED_FILENAME="$RUN_DIR/s02_output.bin"
FILENAME_MATCH_LINES="$(
python3 - "$RUN_CONFIG" "$EXPECTED_FILENAME" <<'PYCONFIG'
import sys
from pathlib import Path
config_path = Path(sys.argv[1])
expected = f'Filename = "{sys.argv[2]}"'
count = sum(
1
for line in config_path.read_text(encoding="utf-8").splitlines()
if line.strip() == expected
)
print(count)
PYCONFIG
)"
MARTE_EXIT_CODE="NOT_AVAILABLE"
TEE_EXIT_CODE="NOT_AVAILABLE"
if [ -f "$RUNNER_SUMMARY" ]; then
value="$(sed -n 's/^Exit code MARTe:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
if [ -n "$value" ]; then
MARTE_EXIT_CODE="$value"
fi
value="$(sed -n 's/^Exit code tee:[[:space:]]*//p' "$RUNNER_SUMMARY" | tail -n 1)"
if [ -n "$value" ]; then
TEE_EXIT_CODE="$value"
fi
fi
case "$MARTE_EXIT_CODE" in
124)
MARTE_EXIT_CLASS="TIMEOUT_EXIT_124"
;;
137)
MARTE_EXIT_CLASS="EXIT_137_SIGKILL"
;;
0)
MARTE_EXIT_CLASS="EXIT_0"
;;
NOT_AVAILABLE)
MARTE_EXIT_CLASS="NOT_AVAILABLE"
;;
*)
MARTE_EXIT_CLASS="OTHER_EXIT_CODE"
;;
esac
CONFIG_REPORT="$(mktemp "${TMPDIR:-/tmp}/s02_validator_config_XXXXXX.log")"
BINARY_REPORT="$(mktemp "${TMPDIR:-/tmp}/s02_validator_binary_XXXXXX.log")"
trap 'rm -f -- "$CONFIG_REPORT" "$BINARY_REPORT"' EXIT
python3 - "$RUN_CONFIG" >"$CONFIG_REPORT" 2>&1 <<'PYCONFIGOBS'
import re
import sys
from decimal import Decimal, InvalidOperation
from pathlib import Path
class Node:
def __init__(self, name):
self.name = name.lstrip("+$")
self.properties = {}
def sanitise(text):
"""Remove comments while preserving strings, braces and line boundaries."""
output = []
index = 0
quote = None
block_comment = False
while index < len(text):
char = text[index]
next_char = text[index + 1] if index + 1 < len(text) else ""
if block_comment:
if char == "*" and next_char == "/":
block_comment = False
output.extend(" ")
index += 2
else:
output.append("\n" if char == "\n" else " ")
index += 1
continue
if quote:
output.append(char)
if char == "\\" and index + 1 < len(text):
output.append(text[index + 1])
index += 2
continue
if char == quote:
quote = None
index += 1
continue
if char in {'"', "'"}:
quote = char
output.append(char)
index += 1
continue
if char == "/" and next_char == "*":
block_comment = True
output.extend(" ")
index += 2
continue
if char == "/" and next_char == "/":
while index < len(text) and text[index] != "\n":
output.append(" ")
index += 1
continue
if char == "#":
while index < len(text) and text[index] != "\n":
output.append(" ")
index += 1
continue
output.append(char)
index += 1
return "".join(output)
def braces_outside_strings(line):
result = []
quote = None
index = 0
while index < len(line):
char = line[index]
if quote:
if char == "\\" and index + 1 < len(line):
index += 2
continue
if char == quote:
quote = None
elif char in {'"', "'"}:
quote = char
elif char in "{}":
result.append(char)
index += 1
return result
text = Path(sys.argv[1]).read_text(encoding="utf-8")
clean = sanitise(text)
nodes = []
stack = []
object_open = re.compile(r"^\s*([+$]?[A-Za-z_][A-Za-z0-9_.:-]*)\s*=\s*\{")
assignment = re.compile(r"^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$")
for line in clean.splitlines():
match = object_open.match(line)
if match:
node = Node(match.group(1))
nodes.append(node)
stack.append(node)
elif stack:
match = assignment.match(line)
if match and not match.group(2).startswith("{"):
stack[-1].properties[match.group(1)] = match.group(2).strip()
opens_and_closes = braces_outside_strings(line)
opening_already_consumed = bool(match and object_open.match(line))
if opening_already_consumed:
removed = False
adjusted = []
for brace in opens_and_closes:
if brace == "{" and not removed:
removed = True
continue
adjusted.append(brace)
opens_and_closes = adjusted
for brace in opens_and_closes:
if brace == "{":
stack.append(Node("<anonymous>"))
elif stack:
stack.pop()
def report_objects(prefix, classes, property_name):
matches = [node for node in nodes if node.properties.get("Class") in classes]
names = ",".join(node.name for node in matches) or "NOT_AVAILABLE_OBJECT_NOT_FOUND"
affinities = []
for node in matches:
value = node.properties.get(property_name, "NOT_EXPLICITLY_CONFIGURED")
affinities.append(f"{node.name}={value}")
affinity = ",".join(affinities) or "NOT_AVAILABLE_OBJECT_NOT_FOUND"
print(f"{prefix}_OBJECT_COUNT={len(matches)}")
print(f"{prefix}_OBJECT_NAMES={names}")
print(f"{prefix}_AFFINITY={affinity}")
report_objects("REALTIME_THREAD", {"RealTimeThread"}, "CPUs")
report_objects("FILE_WRITER", {"FileDataSource::FileWriter", "FileWriter"}, "CPUMask")
report_objects("LINUX_TIMER", {"LinuxTimer"}, "CPUMask")
frequency_values = []
for node in nodes:
raw = node.properties.get("Frequency")
if raw is None:
continue
raw = raw.strip().strip('"').strip("'")
try:
value = Decimal(raw)
except InvalidOperation:
continue
if value > 0:
frequency_values.append(value)
unique_frequencies = sorted(set(frequency_values))
if len(unique_frequencies) == 1:
frequency = unique_frequencies[0]
period = Decimal(1_000_000) / frequency
period_text = str(int(period)) if period == period.to_integral_value() else format(period, ".6f").rstrip("0").rstrip(".")
frequency_text = format(frequency, "f").rstrip("0").rstrip(".") if "." in format(frequency, "f") else format(frequency, "f")
print(f"DT_NOMINAL_PERIOD_US={period_text}")
print(f"DT_NOMINAL_SOURCE=CONFIG_FREQUENCY_{frequency_text}_HZ")
elif not unique_frequencies:
print("DT_NOMINAL_PERIOD_US=NOT_AVAILABLE")
print("DT_NOMINAL_SOURCE=NOT_AVAILABLE_NO_POSITIVE_FREQUENCY")
else:
print("DT_NOMINAL_PERIOD_US=NOT_AVAILABLE")
print("DT_NOMINAL_SOURCE=NOT_AVAILABLE_MULTIPLE_FREQUENCIES")
print("CONFIG_OBSERVABILITY_STATUS=PASS")
PYCONFIGOBS
CONFIG_RC=$?
config_value() {
key="$1"
sed -n "s/^${key}=//p" "$CONFIG_REPORT" | tail -n 1
}
CONFIG_OBSERVABILITY_STATUS="$(config_value CONFIG_OBSERVABILITY_STATUS)"
REALTIME_THREAD_OBJECT_COUNT="$(config_value REALTIME_THREAD_OBJECT_COUNT)"
REALTIME_THREAD_OBJECT_NAMES="$(config_value REALTIME_THREAD_OBJECT_NAMES)"
REALTIME_THREAD_AFFINITY="$(config_value REALTIME_THREAD_AFFINITY)"
FILE_WRITER_OBJECT_COUNT="$(config_value FILE_WRITER_OBJECT_COUNT)"
FILE_WRITER_OBJECT_NAMES="$(config_value FILE_WRITER_OBJECT_NAMES)"
FILE_WRITER_AFFINITY="$(config_value FILE_WRITER_AFFINITY)"
LINUX_TIMER_OBJECT_COUNT="$(config_value LINUX_TIMER_OBJECT_COUNT)"
LINUX_TIMER_OBJECT_NAMES="$(config_value LINUX_TIMER_OBJECT_NAMES)"
LINUX_TIMER_AFFINITY="$(config_value LINUX_TIMER_AFFINITY)"
DT_NOMINAL_PERIOD_US="$(config_value DT_NOMINAL_PERIOD_US)"
DT_NOMINAL_SOURCE="$(config_value DT_NOMINAL_SOURCE)"
python3 - "$OUTPUT_FILE" "${DT_NOMINAL_PERIOD_US:-NOT_AVAILABLE}" >"$BINARY_REPORT" 2>&1 <<'PY'
from collections import Counter
from decimal import Decimal, InvalidOperation
import struct
import sys
from pathlib import Path
path = Path(sys.argv[1])
nominal_period_raw = sys.argv[2]
data = path.read_bytes()
expected_names = [
"Counter",
"Time",
"State1_Thread1_CycleTime",
]
expected_type_hex = "0408"
expected_signals = len(expected_names)
signal_header_bytes = 2 + 32 + 4
print(f"FILE_SIZE_BYTES={len(data)}")
if len(data) < 4:
print("BINARY_STATUS=FAIL_HEADER_TOO_SMALL")
sys.exit(31)
number_of_signals = struct.unpack_from("<I", data, 0)[0]
print(f"NUMBER_OF_SIGNALS={number_of_signals}")
if number_of_signals != expected_signals:
print("BINARY_STATUS=FAIL_SIGNAL_COUNT")
sys.exit(32)
offset = 4
names = []
type_hex_values = []
elements = []
for index in range(number_of_signals):
if offset + signal_header_bytes > len(data):
print(f"TRUNCATED_SIGNAL_HEADER_INDEX={index}")
print("BINARY_STATUS=FAIL_TRUNCATED_SIGNAL_HEADER")
sys.exit(33)
type_bytes = data[offset:offset + 2]
offset += 2
raw_name = data[offset:offset + 32]
offset += 32
number_of_elements = struct.unpack_from("<I", data, offset)[0]
offset += 4
name = raw_name.split(b"\x00", 1)[0].decode("ascii", errors="replace")
names.append(name)
type_hex_values.append(type_bytes.hex())
elements.append(number_of_elements)
print(f"SIGNAL_{index}_TYPE_HEX={type_bytes.hex()}")
print(f"SIGNAL_{index}_NAME={name}")
print(f"SIGNAL_{index}_NUMBER_OF_ELEMENTS={number_of_elements}")
print("SIGNAL_NAMES=" + ",".join(names))
if names != expected_names:
print("BINARY_STATUS=FAIL_SIGNAL_NAMES")
sys.exit(34)
if any(value != expected_type_hex for value in type_hex_values):
print("BINARY_STATUS=FAIL_SIGNAL_TYPES")
sys.exit(35)
if any(value != 1 for value in elements):
print("BINARY_STATUS=FAIL_NUMBER_OF_ELEMENTS")
sys.exit(36)
header_bytes = offset
sample_bytes = expected_signals * 4
payload_bytes = len(data) - header_bytes
remainder_bytes = payload_bytes % sample_bytes
sample_count = payload_bytes // sample_bytes
print(f"HEADER_BYTES={header_bytes}")
print(f"SAMPLE_BYTES={sample_bytes}")
print(f"PAYLOAD_BYTES={payload_bytes}")
print(f"PAYLOAD_REMAINDER_BYTES={remainder_bytes}")
print(f"COMPLETE_SAMPLE_COUNT={sample_count}")
if remainder_bytes != 0:
print("BINARY_STATUS=FAIL_PAYLOAD_REMAINDER")
sys.exit(37)
records = [
struct.unpack_from("<III", data, header_bytes + index * sample_bytes)
for index in range(sample_count)
]
counters = [record[0] for record in records]
times = [record[1] for record in records]
cycle_times = [record[2] for record in records]
dt_values = [current - previous for previous, current in zip(times, times[1:])]
dt_histogram = Counter(dt_values)
distinct_dt_values = sorted(dt_histogram)
leading_zero_cycle_time_samples = 0
for value in cycle_times:
if value != 0:
break
leading_zero_cycle_time_samples += 1
print(f"DT_INTERVAL_COUNT={len(dt_values)}")
print("DT_DISTINCT_VALUES=" + (",".join(str(value) for value in distinct_dt_values) or "NOT_AVAILABLE"))
print(
"DT_HISTOGRAM="
+ (",".join(f"{value}:{dt_histogram[value]}" for value in distinct_dt_values) or "NOT_AVAILABLE")
)
print(f"DT_MIN={min(dt_values) if dt_values else 'NOT_AVAILABLE'}")
print(f"DT_MAX={max(dt_values) if dt_values else 'NOT_AVAILABLE'}")
print(f"LEADING_ZERO_CYCLE_TIME_SAMPLES={leading_zero_cycle_time_samples}")
try:
nominal_period = Decimal(nominal_period_raw)
except InvalidOperation:
nominal_period = None
if nominal_period is not None and dt_values:
anomaly_indices = [
index for index, value in enumerate(dt_values)
if Decimal(value) != nominal_period
]
print(f"DT_ANOMALY_COUNT={len(anomaly_indices)}")
print("DT_ANOMALY_INDICES=" + (",".join(str(index) for index in anomaly_indices) or "NONE"))
if anomaly_indices:
first_index = anomaly_indices[0]
print(f"DT_FIRST_ANOMALY_BETWEEN_RECORDS={first_index}_AND_{first_index + 1}")
print(f"DT_FIRST_ANOMALY_COUNTER_PAIR={counters[first_index]}_AND_{counters[first_index + 1]}")
print(f"DT_FIRST_ANOMALY_VALUE={dt_values[first_index]}")
else:
print("DT_FIRST_ANOMALY_BETWEEN_RECORDS=NONE")
print("DT_FIRST_ANOMALY_COUNTER_PAIR=NONE")
print("DT_FIRST_ANOMALY_VALUE=NONE")
else:
print("DT_ANOMALY_COUNT=NOT_AVAILABLE")
print("DT_ANOMALY_INDICES=NOT_AVAILABLE")
print("DT_FIRST_ANOMALY_BETWEEN_RECORDS=NOT_AVAILABLE")
print("DT_FIRST_ANOMALY_COUNTER_PAIR=NOT_AVAILABLE")
print("DT_FIRST_ANOMALY_VALUE=NOT_AVAILABLE")
if sample_count < 50:
print("BINARY_STATUS=FAIL_INSUFFICIENT_SAMPLES")
sys.exit(38)
counter_gap_count = sum(
1 for previous, current in zip(counters, counters[1:])
if current != previous + 1
)
time_decrease_count = sum(
1 for previous, current in zip(times, times[1:])
if current < previous
)
nonzero_cycle_times = [value for value in cycle_times if value > 0]
print(f"COUNTER_FIRST={counters[0]}")
print(f"COUNTER_LAST={counters[-1]}")
print(f"COUNTER_GAP_COUNT={counter_gap_count}")
print(f"TIME_FIRST={times[0]}")
print(f"TIME_LAST={times[-1]}")
print(f"TIME_DECREASE_COUNT={time_decrease_count}")
print(f"NONZERO_CYCLE_TIME_SAMPLES={len(nonzero_cycle_times)}")
if nonzero_cycle_times:
print(f"CYCLE_TIME_MIN={min(nonzero_cycle_times)}")
print(f"CYCLE_TIME_MAX={max(nonzero_cycle_times)}")
print(f"CYCLE_TIME_MEAN={sum(nonzero_cycle_times) / len(nonzero_cycle_times):.3f}")
else:
print("CYCLE_TIME_MIN=NOT_AVAILABLE")
print("CYCLE_TIME_MAX=NOT_AVAILABLE")
print("CYCLE_TIME_MEAN=NOT_AVAILABLE")
if counters[0] != 1 or counter_gap_count != 0:
print("BINARY_STATUS=FAIL_COUNTER_SEQUENCE")
sys.exit(39)
if time_decrease_count != 0:
print("BINARY_STATUS=FAIL_TIME_MONOTONICITY")
sys.exit(40)
if len(nonzero_cycle_times) == 0:
print("BINARY_STATUS=FAIL_NO_CYCLE_TIME")
sys.exit(41)
print("BINARY_STATUS=PASS")
PY
BINARY_RC=$?
binary_value() {
key="$1"
sed -n "s/^${key}=//p" "$BINARY_REPORT" | tail -n 1
}
BINARY_STATUS="$(binary_value BINARY_STATUS)"
FILE_SIZE_BYTES="$(binary_value FILE_SIZE_BYTES)"
NUMBER_OF_SIGNALS="$(binary_value NUMBER_OF_SIGNALS)"
SIGNAL_NAMES="$(binary_value SIGNAL_NAMES)"
HEADER_BYTES="$(binary_value HEADER_BYTES)"
SAMPLE_BYTES="$(binary_value SAMPLE_BYTES)"
PAYLOAD_BYTES="$(binary_value PAYLOAD_BYTES)"
PAYLOAD_REMAINDER_BYTES="$(binary_value PAYLOAD_REMAINDER_BYTES)"
COMPLETE_SAMPLE_COUNT="$(binary_value COMPLETE_SAMPLE_COUNT)"
COUNTER_FIRST="$(binary_value COUNTER_FIRST)"
COUNTER_LAST="$(binary_value COUNTER_LAST)"
COUNTER_GAP_COUNT="$(binary_value COUNTER_GAP_COUNT)"
TIME_FIRST="$(binary_value TIME_FIRST)"
TIME_LAST="$(binary_value TIME_LAST)"
TIME_DECREASE_COUNT="$(binary_value TIME_DECREASE_COUNT)"
NONZERO_CYCLE_TIME_SAMPLES="$(binary_value NONZERO_CYCLE_TIME_SAMPLES)"
CYCLE_TIME_MIN="$(binary_value CYCLE_TIME_MIN)"
CYCLE_TIME_MAX="$(binary_value CYCLE_TIME_MAX)"
CYCLE_TIME_MEAN="$(binary_value CYCLE_TIME_MEAN)"
DT_INTERVAL_COUNT="$(binary_value DT_INTERVAL_COUNT)"
DT_DISTINCT_VALUES="$(binary_value DT_DISTINCT_VALUES)"
DT_HISTOGRAM="$(binary_value DT_HISTOGRAM)"
DT_MIN="$(binary_value DT_MIN)"
DT_MAX="$(binary_value DT_MAX)"
DT_ANOMALY_COUNT="$(binary_value DT_ANOMALY_COUNT)"
DT_ANOMALY_INDICES="$(binary_value DT_ANOMALY_INDICES)"
DT_FIRST_ANOMALY_BETWEEN_RECORDS="$(binary_value DT_FIRST_ANOMALY_BETWEEN_RECORDS)"
DT_FIRST_ANOMALY_COUNTER_PAIR="$(binary_value DT_FIRST_ANOMALY_COUNTER_PAIR)"
DT_FIRST_ANOMALY_VALUE="$(binary_value DT_FIRST_ANOMALY_VALUE)"
LEADING_ZERO_CYCLE_TIME_SAMPLES="$(binary_value LEADING_ZERO_CYCLE_TIME_SAMPLES)"
affinity_display() {
object_count="$1"
affinity_mapping="$2"
if [ "$object_count" = "1" ]; then
printf "%s" "${affinity_mapping#*=}"
else
printf "%s" "$affinity_mapping"
fi
}
REALTIME_THREAD_AFFINITY_DISPLAY="$(affinity_display "${REALTIME_THREAD_OBJECT_COUNT:-0}" "${REALTIME_THREAD_AFFINITY:-NOT_AVAILABLE}")"
FILE_WRITER_AFFINITY_DISPLAY="$(affinity_display "${FILE_WRITER_OBJECT_COUNT:-0}" "${FILE_WRITER_AFFINITY:-NOT_AVAILABLE}")"
LINUX_TIMER_AFFINITY_DISPLAY="$(affinity_display "${LINUX_TIMER_OBJECT_COUNT:-0}" "${LINUX_TIMER_AFFINITY:-NOT_AVAILABLE}")"
printf "============================================================\n"
printf "VALIDAZIONE PRECISA S02\n"
printf "============================================================\n"
printf "Run directory: %s\n" "$RUN_DIR"
printf "Log: %s\n" "$RUN_LOG"
printf "Configurazione: %s\n" "$RUN_CONFIG"
printf "File binario: %s\n" "$OUTPUT_FILE"
printf "Avvii State1: %s\n" "$START_LINES"
printf "Application starting: %s\n" "$APPLICATION_START_LINES"
printf "Aperture FileWriter: %s\n" "$FILE_OPEN_LINES"
printf "Placeholder residui: %s\n" "$PLACEHOLDER_COUNT"
printf "Classe qualificata FileWriter: %s\n" "$NAMESPACED_CLASS_COUNT"
printf "Classe semplice FileWriter: %s\n" "$PLAIN_CLASS_COUNT"
printf "Filename corretti: %s\n" "$FILENAME_MATCH_LINES"
printf "Dimensione file: %s byte\n" "${FILE_SIZE_BYTES:-NOT_AVAILABLE}"
printf "Segnali binari: %s\n" "${NUMBER_OF_SIGNALS:-NOT_AVAILABLE}"
printf "Nomi segnali: %s\n" "${SIGNAL_NAMES:-NOT_AVAILABLE}"
printf "Header: %s byte\n" "${HEADER_BYTES:-NOT_AVAILABLE}"
printf "Record: %s byte\n" "${SAMPLE_BYTES:-NOT_AVAILABLE}"
printf "Payload: %s byte\n" "${PAYLOAD_BYTES:-NOT_AVAILABLE}"
printf "Residuo payload: %s byte\n" "${PAYLOAD_REMAINDER_BYTES:-NOT_AVAILABLE}"
printf "Campioni completi: %s\n" "${COMPLETE_SAMPLE_COUNT:-NOT_AVAILABLE}"
printf "Counter iniziale: %s\n" "${COUNTER_FIRST:-NOT_AVAILABLE}"
printf "Counter finale: %s\n" "${COUNTER_LAST:-NOT_AVAILABLE}"
printf "Salti Counter: %s\n" "${COUNTER_GAP_COUNT:-NOT_AVAILABLE}"
printf "Time iniziale: %s\n" "${TIME_FIRST:-NOT_AVAILABLE}"
printf "Time finale: %s\n" "${TIME_LAST:-NOT_AVAILABLE}"
printf "Regressioni Time: %s\n" "${TIME_DECREASE_COUNT:-NOT_AVAILABLE}"
printf "CycleTime non nulli: %s\n" "${NONZERO_CYCLE_TIME_SAMPLES:-NOT_AVAILABLE}"
printf "CycleTime minimo: %s\n" "${CYCLE_TIME_MIN:-NOT_AVAILABLE}"
printf "CycleTime massimo: %s\n" "${CYCLE_TIME_MAX:-NOT_AVAILABLE}"
printf "CycleTime medio: %s\n" "${CYCLE_TIME_MEAN:-NOT_AVAILABLE}"
printf "Stato parser binario: %s\n" "${BINARY_STATUS:-NOT_AVAILABLE}"
printf "Exit code MARTe: %s\n" "$MARTE_EXIT_CODE"
printf "Exit code tee: %s\n" "$TEE_EXIT_CODE"
printf "SIGINT ricevuti: %s\n" "$SIGINT_LINES"
printf "Stop riusciti: %s\n" "$STOP_OK_LINES"
printf "Application terminated: %s\n" "$TERMINATED_LINES"
printf "Errori startup: %s\n" "$STARTUP_ERROR_LINES"
printf "FatalError reali: %s\n" "$FATAL_ERROR_LINES"
printf "OSError reali: %s\n" "$OS_ERROR_LINES"
printf "Error reali: %s\n" "$ERROR_LINES"
printf "InitialisationError reali: %s\n" "$INITIALISATION_ERROR_LINES"
printf "NoError: %s\n" "$NO_ERROR_LINES"
printf "Doppio arresto: %s\n" "$DOUBLE_STOP_LINES"
printf "Close EventSem asincrono: %s\n" "$ASYNC_EVENTSEM_CLOSE_LINES"
printf "pthread_mutex_destroy: %s\n" "$PTHREAD_MUTEX_DESTROY_LINES"
printf "FatalError non classificati: %s\n" "$UNCLASSIFIED_FATAL_LINES"
printf "OSError non classificati: %s\n" "$UNCLASSIFIED_OS_ERROR_LINES"
printf "\n--- INTERVALLI TEMPORALI (osservativo) ---\n"
printf "Periodo nominale: %s us\n" "${DT_NOMINAL_PERIOD_US:-NOT_AVAILABLE}"
printf "Fonte periodo nominale: %s\n" "${DT_NOMINAL_SOURCE:-NOT_AVAILABLE}"
printf "Intervalli dt: %s\n" "${DT_INTERVAL_COUNT:-NOT_AVAILABLE}"
printf "Valori dt distinti: %s\n" "${DT_DISTINCT_VALUES:-NOT_AVAILABLE}"
printf "Istogramma dt: %s\n" "${DT_HISTOGRAM:-NOT_AVAILABLE}"
printf "dt minimo: %s\n" "${DT_MIN:-NOT_AVAILABLE}"
printf "dt massimo: %s\n" "${DT_MAX:-NOT_AVAILABLE}"
printf "Intervalli dt anomali: %s\n" "${DT_ANOMALY_COUNT:-NOT_AVAILABLE}"
printf "Indici dt anomali: %s\n" "${DT_ANOMALY_INDICES:-NOT_AVAILABLE}"
printf "Primo dt anomalo tra record: %s\n" "${DT_FIRST_ANOMALY_BETWEEN_RECORDS:-NOT_AVAILABLE}"
printf "Primo dt anomalo Counter: %s\n" "${DT_FIRST_ANOMALY_COUNTER_PAIR:-NOT_AVAILABLE}"
printf "Primo dt anomalo valore: %s\n" "${DT_FIRST_ANOMALY_VALUE:-NOT_AVAILABLE}"
printf "CycleTime nulli iniziali: %s\n" "${LEADING_ZERO_CYCLE_TIME_SAMPLES:-NOT_AVAILABLE}"
printf "\n--- AFFINITA' DICHIARATE IN CONFIGURAZIONE ---\n"
REALTIME_THREAD_LABEL="RealTimeThread (${REALTIME_THREAD_OBJECT_NAMES:-NOT_AVAILABLE}) CPUs:"
FILE_WRITER_LABEL="FileWriter (${FILE_WRITER_OBJECT_NAMES:-NOT_AVAILABLE}) CPUMask:"
LINUX_TIMER_LABEL="LinuxTimer (${LINUX_TIMER_OBJECT_NAMES:-NOT_AVAILABLE}) CPUMask:"
printf "%-40s %s (rc=%s)\n" "Stato parser configurazione:" "${CONFIG_OBSERVABILITY_STATUS:-NOT_AVAILABLE}" "$CONFIG_RC"
printf "%-40s %s\n" "$REALTIME_THREAD_LABEL" "${REALTIME_THREAD_AFFINITY_DISPLAY:-NOT_AVAILABLE}"
printf "%-40s %s\n" "$FILE_WRITER_LABEL" "${FILE_WRITER_AFFINITY_DISPLAY:-NOT_AVAILABLE}"
printf "%-40s %s\n" "$LINUX_TIMER_LABEL" "${LINUX_TIMER_AFFINITY_DISPLAY:-NOT_AVAILABLE}"
printf "\n--- PRIORITA' E TERMINAZIONE ---\n"
printf "Warning totali: %s\n" "$WARNING_LINES"
printf "Warning clipping priorita': %s\n" "$PRIORITY_CLIP_LINES"
printf "Warning priorita' non applic.: %s\n" "$PRIORITY_FAIL_LINES"
printf "Warning non classificati: %s\n" "$UNCLASSIFIED_WARNING_LINES"
printf "Classe exit code: %s\n" "$MARTE_EXIT_CLASS"
FUNCTIONAL_OK=0
if [ "$START_LINES" -ge 1 ] &&
[ "$APPLICATION_START_LINES" -ge 1 ] &&
[ "$FILE_OPEN_LINES" -ge 1 ] &&
[ "$STARTUP_ERROR_LINES" -eq 0 ] &&
[ "$PLACEHOLDER_COUNT" -eq 0 ] &&
[ "$NAMESPACED_CLASS_COUNT" -eq 1 ] &&
[ "$PLAIN_CLASS_COUNT" -eq 0 ] &&
[ "$FILENAME_MATCH_LINES" -eq 1 ] &&
[ "$BINARY_RC" -eq 0 ]; then
FUNCTIONAL_OK=1
fi
if [ "$FUNCTIONAL_OK" -eq 1 ]; then
FUNCTIONAL_STATUS="PASS"
else
FUNCTIONAL_STATUS="NOT_DEMONSTRATED"
fi
if [ "$MARTE_EXIT_CLASS" = "EXIT_137_SIGKILL" ]; then
TIMING_STATUS="NOT_VALID_EXIT_137_SIGKILL"
elif [ "$PRIORITY_FAIL_LINES" -ge 1 ]; then
TIMING_STATUS="NOT_VALID_PRIORITY_NOT_APPLIED"
else
TIMING_STATUS="UNASSESSED_DT_SEMANTICS"
fi
printf "\nFUNCTIONAL_STATUS=%s\n" "$FUNCTIONAL_STATUS"
printf "TIMING_STATUS=%s\n" "$TIMING_STATUS"
case "$FUNCTIONAL_STATUS:$TIMING_STATUS" in
PASS:NOT_VALID_*)
printf "FUNCTIONAL_PASS_TIMING_NOT_VALID\n"
;;
esac
printf "\n============================================================\n"
printf "CLASSIFICAZIONE\n"
printf "============================================================\n"
if [ "$FUNCTIONAL_OK" -ne 1 ]; then
printf "[NON DIMOSTRATO] Funzionamento S02 e registrazione binaria non sufficientemente provati.\n"
printf "[DA VERIFICARE] Dettaglio parser binario:\n"
cat -- "$BINARY_REPORT"
exit 20
fi
printf "[VERIFICATO] Funzionamento S02 e registrazione binaria dimostrati.\n"
if [ "$SIGINT_LINES" -ge 1 ] &&
[ "$STOP_OK_LINES" -ge 1 ] &&
[ "$TERMINATED_LINES" -ge 1 ] &&
[ "$FATAL_ERROR_LINES" -eq 0 ] &&
[ "$OS_ERROR_LINES" -eq 0 ] &&
[ "$ERROR_LINES" -eq 0 ] &&
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
printf "[VERIFICATO] Shutdown privo di Error, OSError e FatalError.\n"
exit 0
fi
KNOWN_SHUTDOWN_TOTAL=$((DOUBLE_STOP_LINES + ASYNC_EVENTSEM_CLOSE_LINES + PTHREAD_MUTEX_DESTROY_LINES))
if [ "$SIGINT_LINES" -ge 1 ] &&
[ "$STOP_OK_LINES" -ge 1 ] &&
[ "$TERMINATED_LINES" -ge 1 ] &&
[ "$KNOWN_SHUTDOWN_TOTAL" -ge 1 ] &&
[ "$UNCLASSIFIED_FATAL_LINES" -eq 0 ] &&
[ "$UNCLASSIFIED_OS_ERROR_LINES" -eq 0 ] &&
[ "$ERROR_LINES" -eq 0 ] &&
[ "$INITIALISATION_ERROR_LINES" -eq 0 ]; then
printf "[DA VERIFICARE] Funzionalità riuscita con sole anomalie di shutdown già classificate.\n"
exit 10
fi
printf "[DA VERIFICARE] Funzionalità riuscita, ma sono presenti anomalie di shutdown non classificate.\n"
exit 11