Removed CLP(Z) from library(json), achieving a 100x speedup in JSON parsing.
This commit is contained in:
@@ -18,7 +18,6 @@ COPY --from=cacher $CARGO_HOME $CARGO_HOME
|
|||||||
RUN cargo build --release --bin scryer-prolog
|
RUN cargo build --release --bin scryer-prolog
|
||||||
|
|
||||||
FROM debian:stable-slim
|
FROM debian:stable-slim
|
||||||
WORKDIR scryer-prolog
|
|
||||||
COPY --from=builder /scryer-prolog/target/release/scryer-prolog /usr/local/bin
|
COPY --from=builder /scryer-prolog/target/release/scryer-prolog /usr/local/bin
|
||||||
ENV RUST_BACKTRACE=1
|
ENV RUST_BACKTRACE=1
|
||||||
ENTRYPOINT ["/usr/local/bin/scryer-prolog"]
|
ENTRYPOINT ["/usr/local/bin/scryer-prolog"]
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
:- use_module(library(assoc)).
|
:- use_module(library(assoc)).
|
||||||
:- use_module(library(between)).
|
:- use_module(library(between)).
|
||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
:- use_module(library(clpz)).
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(dif)).
|
:- use_module(library(dif)).
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
@@ -164,7 +163,7 @@ json_character(PrintChar) -->
|
|||||||
{ dif(PrintChar, '"'),
|
{ dif(PrintChar, '"'),
|
||||||
dif(PrintChar, '\\'),
|
dif(PrintChar, '\\'),
|
||||||
char_code(PrintChar, PrintCharCode),
|
char_code(PrintChar, PrintCharCode),
|
||||||
PrintCharCode in 32..1114111 /* 20.10FFFF */ }.
|
PrintCharCode >= 32 /* 20.10FFFF */ }.
|
||||||
json_character(EscapeChar) --> "\\", json_escape(EscapeChar).
|
json_character(EscapeChar) --> "\\", json_escape(EscapeChar).
|
||||||
|
|
||||||
json_escape(EscapeChar) -->
|
json_escape(EscapeChar) -->
|
||||||
@@ -173,29 +172,28 @@ json_escape(EscapeChar) -->
|
|||||||
member(EscapeChar-PrintChar, EscapeMap) }.
|
member(EscapeChar-PrintChar, EscapeMap) }.
|
||||||
json_escape(EscapeChar) -->
|
json_escape(EscapeChar) -->
|
||||||
"u",
|
"u",
|
||||||
/* Logic: Define the domain of the escape character as well as the relationship between the escape character
|
{ /* Control: Get the code of the escape character if we can. Otherwise we'll end up backtracking over 65,536
|
||||||
and the four hexes */
|
|
||||||
{ [H1, H2, H3, H4] ins 0..15,
|
|
||||||
EscapeCharCode in 0..65535,
|
|
||||||
EscapeCharCode #= H1 * 16^3 + H2 * 16^2 + H3 * 16 + H4,
|
|
||||||
/* Control: Get the code of the escape character if we can. Otherwise we'll end up backtracking over 65,536
|
|
||||||
possible hex values.
|
possible hex values.
|
||||||
Logic: Only the first 32 Unicode characters not escaped in the escape map are eligible for \u-escaping
|
Logic: Only the first 32 Unicode characters not escaped in the escape map are eligible for \u-escaping
|
||||||
when generating. However, we want to be able to parse any of the 65,536 \u-escaped values when parsing. */
|
when generating. However, we want to be able to parse any of the 65,536 \u-escaped values when parsing. */
|
||||||
( nonvar(EscapeChar) ->
|
( nonvar(EscapeChar) ->
|
||||||
char_code(EscapeChar, EscapeCharCode),
|
char_code(EscapeChar, EscapeCharCode),
|
||||||
EscapeCharCode in 0..31,
|
EscapeCharCode < 32,
|
||||||
escape_map(EscapeMap),
|
escape_map(EscapeMap),
|
||||||
\+ member(EscapeChar-_, EscapeMap)
|
\+ member(EscapeChar-_, EscapeMap),
|
||||||
|
H1 = 0,
|
||||||
|
H2 = 0,
|
||||||
|
H3 is EscapeCharCode // 16,
|
||||||
|
H4 is EscapeCharCode mod 16
|
||||||
; true
|
; true
|
||||||
)
|
) },
|
||||||
},
|
|
||||||
json_hex(H1),
|
json_hex(H1),
|
||||||
json_hex(H2),
|
json_hex(H2),
|
||||||
json_hex(H3),
|
json_hex(H3),
|
||||||
json_hex(H4),
|
json_hex(H4),
|
||||||
/* Control + Logic: Get the escape character atom from the character code computed from the hexes. */
|
/* Control + Logic: Get the escape character atom from the character code computed from the hexes. */
|
||||||
{ ( var(EscapeChar) ->
|
{ ( var(EscapeChar) ->
|
||||||
|
EscapeCharCode is H1 * 16^3 + H2 * 16^2 + H3 * 16 + H4,
|
||||||
char_code(EscapeChar, EscapeCharCode)
|
char_code(EscapeChar, EscapeCharCode)
|
||||||
; true
|
; true
|
||||||
) }.
|
) }.
|
||||||
@@ -234,14 +232,14 @@ json_integer(Digit) --> json_digit(Digit).
|
|||||||
json_integer(TotalValue) -->
|
json_integer(TotalValue) -->
|
||||||
json_onenine(FirstDigit),
|
json_onenine(FirstDigit),
|
||||||
json_digits(RemainingValue, Power),
|
json_digits(RemainingValue, Power),
|
||||||
{ TotalValue #= FirstDigit * 10 ^ (Power + 1) + RemainingValue }.
|
{ TotalValue is FirstDigit * 10 ^ (Power + 1) + RemainingValue }.
|
||||||
|
|
||||||
json_digits(Digit, 0) --> json_digit(Digit).
|
json_digits(Digit, 0) --> json_digit(Digit).
|
||||||
json_digits(Value, Power) -->
|
json_digits(Value, Power) -->
|
||||||
json_digit(FirstDigit),
|
json_digit(FirstDigit),
|
||||||
json_digits(RemainingValue, NextPower),
|
json_digits(RemainingValue, NextPower),
|
||||||
{ Power #= NextPower + 1,
|
{ Power is NextPower + 1,
|
||||||
Value #= FirstDigit * 10^Power + RemainingValue }.
|
Value is FirstDigit * 10^Power + RemainingValue }.
|
||||||
|
|
||||||
json_digit(0) --> "0".
|
json_digit(0) --> "0".
|
||||||
json_digit(Digit) --> json_onenine(Digit).
|
json_digit(Digit) --> json_onenine(Digit).
|
||||||
@@ -267,7 +265,7 @@ json_exponent(Exponent) -->
|
|||||||
json_exponent_signifier,
|
json_exponent_signifier,
|
||||||
json_sign(Sign),
|
json_sign(Sign),
|
||||||
json_digits(Value, _),
|
json_digits(Value, _),
|
||||||
{ Exponent #= Sign * Value }.
|
{ Exponent is Sign * Value }.
|
||||||
|
|
||||||
json_exponent_signifier --> "E".
|
json_exponent_signifier --> "E".
|
||||||
json_exponent_signifier --> "e".
|
json_exponent_signifier --> "e".
|
||||||
|
|||||||
13
src/tests/json/README.md
Normal file
13
src/tests/json/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
### With CLP(Z):
|
||||||
|
```
|
||||||
|
?- test_json_read.
|
||||||
|
% CPU time: 41.522 seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
### After removing CLP(Z):
|
||||||
|
```
|
||||||
|
?- test_json_read.
|
||||||
|
% CPU time: 0.444 seconds
|
||||||
|
```
|
||||||
27
src/tests/json/test_json.pl
Normal file
27
src/tests/json/test_json.pl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
:- module(test_json, [test_json_read/0]).
|
||||||
|
|
||||||
|
:- use_module(library(json)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(os)).
|
||||||
|
:- use_module(library(pio)).
|
||||||
|
:- use_module(library(time)).
|
||||||
|
|
||||||
|
test_path(TestName, TestPath) :-
|
||||||
|
getenv("SCRYER_JSON_TESTS_PATH", JsonPath),
|
||||||
|
append(JsonPath, TestName, TestPathChars),
|
||||||
|
atom_chars(TestPath, TestPathChars).
|
||||||
|
|
||||||
|
name_parse(Name, Json) :-
|
||||||
|
test_path(Name, Path),
|
||||||
|
once(phrase_from_file(json_chars(Json), Path)).
|
||||||
|
|
||||||
|
test_json_read :-
|
||||||
|
name_parse("pass_null.json", _),
|
||||||
|
name_parse("pass_alnum.json", _),
|
||||||
|
name_parse("pass_special.json", _),
|
||||||
|
name_parse("pass_mandatory_escapes.json", _),
|
||||||
|
name_parse("pass_forward_slash.json", _),
|
||||||
|
name_parse("pass_hex.json", _),
|
||||||
|
name_parse("pass_smallfloat.json", _),
|
||||||
|
name_parse("pass_bigfloat.json", _),
|
||||||
|
time(name_parse("pass_everything.json", _)).
|
||||||
Reference in New Issue
Block a user