From: Markus Triska Date: Fri, 22 May 2020 15:30:29 +0000 (+0200) Subject: ENHANCED: Faster format/3 for binary streams. X-Git-Tag: v0.8.123~4^2^2 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=48c0b0ab3c9eb4f8c8ec9b953d0c6cc61a0a47fc;p=scryer-prolog.git ENHANCED: Faster format/3 for binary streams. This speeds up web servers considerably when sending binary files. --- diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index b783ac0c..e685c65f 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -229,6 +229,7 @@ pub enum SystemClauseType { PeekCode, PointsToContinuationResetMarker, PutByte, + PutBytes, PutChar, PutCode, REPL(REPLCodePtr), @@ -415,6 +416,9 @@ impl SystemClauseType { &SystemClauseType::PutByte => { clause_name!("$put_byte") } + &SystemClauseType::PutBytes => { + clause_name!("$put_bytes") + } &SystemClauseType::PutChar => { clause_name!("$put_char") } @@ -552,6 +556,9 @@ impl SystemClauseType { ("$put_byte", 2) => { Some(SystemClauseType::PutByte) } + ("$put_bytes", 2) => { + Some(SystemClauseType::PutBytes) + } ("$put_char", 2) => { Some(SystemClauseType::PutChar) } diff --git a/src/prolog/lib/format.pl b/src/prolog/lib/format.pl index c0ef87c1..18289094 100644 --- a/src/prolog/lib/format.pl +++ b/src/prolog/lib/format.pl @@ -367,8 +367,20 @@ format(Fs, Args) :- format(Stream, Fs, Args) :- phrase(format_(Fs, Args), Cs), ( stream_property(Stream, type(binary)) -> - maplist(char_code, Cs, Bytes), - maplist(put_byte(Stream), Bytes) + % maplist(char_code, Cs, Bytes) is currently a lot slower + % than first converting Cs to an atom, and then to codes. + % In the future, we can ideally avoid creating an atom here, + % since an atom leaves traces in the system. + atom_chars(A, Cs), + atom_codes(A, Bytes), + ( member(NonByte, Bytes), NonByte > 255 -> + char_code(Char, NonByte), + throw(error(representation_error(Char), format/3)) + ; true + ), + % For binary streams, we use a specialised internal predicate + % that uses only a single "write" operation for efficiency. + '$put_bytes'(Stream, Bytes) ; maplist(put_char(Stream), Cs) ). diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 1fe7b576..0ab8411e 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -2153,6 +2153,37 @@ impl MachineState { } } } + &SystemClauseType::PutBytes => { + let mut stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?; + + let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2); + let bytes = self.integers_to_bytevec(temp_v!(2), stub); + + match stream.write(&bytes) { + Ok(_) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let stub = MachineError::functor_stub( + clause_name!("$put_bytes"), + 2, + ); + + let addr = self.heap.to_unifiable( + HeapCellValue::Stream(stream.clone()), + ); + + return Err(self.error_form( + MachineError::existence_error( + self.heap.h(), + ExistenceError::Stream(addr), + ), + stub, + )); + } + } + } &SystemClauseType::GetByte => { let mut stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;