Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Debugowanie kompilacji

Kompilator transformuje plik .rql w plan wykonania przez kilka etapów. Efekt każdego etapu jest widoczny przez flagi diagnostyczne xretractor. Opisane tutaj narzędzia pozwalają odpowiedzieć na pytania: dlaczego schemat wygląda inaczej niż napisałem? skąd ta delta? dlaczego pojawił się substrat?

Podstawowe narzędzie: flaga -c

Flaga -c (--onlycompile) zatrzymuje xretractor po kompilacji i drukuje skompilowany plan na standardowe wyjście — bez uruchamiania przetwarzania:

xretractor -c query.rql

Kod wyjścia 0 oznacza sukces. Kod 1 — błąd kompilacji. Komunikaty błędów trafiają na stderr:

xretractor -c query.rql 2>errors.txt
echo $?

Kompilację można wywołać nawet gdy inny proces xretractor już działa — flaga -c nie próbuje przejąć blokady wykonania.

Jak czytać plan kompilacji

Dla kanonicznego query.rql z tego rozdziału plan wygląda następująco:

merged(1/10)
        :- PUSH_STREAM(core0)
        :- PUSH_STREAM(core1)
        :- STREAM_ADD
        core0_0: BYTE
                PUSH_ID(merged[0])
        core0_1: INTEGER
                PUSH_ID(merged[1])
        core1_2: INTEGER
                PUSH_ID(merged[2])
        core1_3: FLOAT
                PUSH_ID(merged[3])
result(1/10)
        :- PUSH_STREAM(merged)
        result_0: BYTE
                PUSH_ID(merged[0])
        result_1: INTEGER
                PUSH_ID(merged[2])
        result_2: BYTE
                PUSH_ID(merged[0])
        result_3: INTEGER
                PUSH_ID(merged[2])
core0(1/10)     sensor_a.txt
        a: BYTE
        b: INTEGER
core1(1/5)      sensor_b.txt
        c: INTEGER
        d: FLOAT
core2(3/10)     sensor_c.txt
        e: INTEGER

Każdy blok ma ustalony format:

nazwaStrumienia(delta)
        :- operacjaStrumieniowa(arg)
        nazwaPolaWyjściowego: TYP
                instrukcja
                ...
ElementZnaczenie
nazwaStrumienia(delta)Nazwa strumienia i jego interwał jako ułamek: 1/10 = 0.1 s = 10 Hz
:- PUSH_STREAM(x)Pcha strumień x na stos strumieniowy; pojawia się raz na każdy argument FROM
:- STREAM_ADDOperator sumy strumieni (+ w FROM)
:- STREAM_HASHOperator synchronizacji strumieni (# w FROM)
:- STREAM_TIMEMOVE(n)Przesunięcie w czasie (>n w FROM)
pole: TYPPole schematu wynikowego po równaniu typów w górę
PUSH_ID(s[n])Odkłada na stos wartość pola n ze strumienia s — tu widoczny efekt aliasowania
PUSH_VAL(x)Odkłada stałą x na stos
ADD, MULTIPLY, …Operacja arytmetyczna: zdejmuje dwa argumenty ze stosu, odkłada wynik

Bloki efemerydów (DECLARE) pojawiają się na końcu planu — zawierają listę pól i ścieżkę do pliku danych.

Aliasowanie w planie: jeśli dwa pola wyjściowe wskazują na ten sam PUSH_ID, są aliasami. W przykładzie result_0 i result_2 oba to PUSH_ID(merged[0]) — potwierdzenie, że merged[0] i core0[0] to ta sama pozycja. Patrz Aliasowanie.

Substraty w planie: automatycznie wygenerowany substrat pojawia się jako blok z nazwą w stylu STREAM_HASH_core0_core1 — bez odpowiadającego SELECT w pliku źródłowym. Patrz Substraty.

Wizualizacja grafu zależności

Zamiast tekstu można wygenerować graf w formacie DOT i przetworzyć przez graphviz:

xretractor -c -d -f -s query.rql > out.dot && dot -Tsvg out.dot -o out.svg

Dostępne flagi modyfikujące wyjście DOT:

FlagaPełna nazwaZnaczenie
-d--dotgeneruj wyjście DOT zamiast tekstowego planu
-f--fieldspokaż pola strumieni w węzłach grafu
-s--streamprogspokaż sekwencje instrukcji stosu w węzłach
-u--rulespokaż reguły RULE
-p--transparentprzezroczyste tło — do osadzania w dokumentach

Graf pokazuje zależności między strumieniami jako krawędzie skierowane od źródeł do wyników. Substraty mają inny kolor niż strumienie jawnie zdefiniowane przez użytkownika. Patrz Budowa drzewa zależności.

NOTE: Opisana funkcjonalność ma pokrycie w teście: issue31_doc opisanym w załączniku pt. Testy Integracyjne.

Weryfikacja interwałów

Jeśli delta strumienia wynikowego jest niespodziewana:

  1. Sprawdź delty strumieni źródłowych — widoczne w blokach DECLARE na końcu planu.
  2. Sprawdź operator w klauzuli FROM — każdy operator ma inne równanie na deltę.

Przykład: core0(1/10) # core1(1/5) daje deltę 1/15 (średnia harmoniczna), nie 1/10. Jeśli spodziewałeś się 1/10, użyj + zamiast #. Pełne równania — patrz Rozwiązywanie interwałów.

Typowe błędy kompilacji

Cykl w grafie zależności

[error] Circular dependency: stream interval resolution stalled with N unresolved streams

Strumień odwołuje się pośrednio lub bezpośrednio do samego siebie. Wygeneruj graf przez -d — cykl będzie widoczny jako pętla. Patrz Wykrywanie pętli.

Nieznany strumień

Odwołanie do strumienia, który nie został jeszcze zadeklarowany. Pliki .rql przetwarzane są sekwencyjnie — SELECT nie może odwoływać się do strumienia zdefiniowanego niżej w pliku. Przesuń DECLARE lub SELECT wyżej.

Niezgodność krotności schematów przy _

Oba strumienie w wyrażeniu core0[_] * core1[_] muszą mieć schematy tej samej liczności. Sprawdź ile pól ma każdy z argumentów w blokach DECLARE planu. Patrz Przetwarzanie symbolu _.

Plik danych niedostępny

Błąd ten nie pojawia się przy -c — flaga weryfikuje poprawność zapytania, nie sprawdza czy pliki danych istnieją. Błąd dostępu do pliku pojawi się dopiero przy uruchamianiu przetwarzania bez -c.