ENHANCED: Faster format/3 for binary streams.

This speeds up web servers considerably when sending binary files.
This commit is contained in:
Markus Triska
2020-05-22 17:30:29 +02:00
parent cbbed310c5
commit 48c0b0ab3c
3 changed files with 52 additions and 2 deletions

View File

@@ -229,6 +229,7 @@ pub enum SystemClauseType {
PeekCode, PeekCode,
PointsToContinuationResetMarker, PointsToContinuationResetMarker,
PutByte, PutByte,
PutBytes,
PutChar, PutChar,
PutCode, PutCode,
REPL(REPLCodePtr), REPL(REPLCodePtr),
@@ -415,6 +416,9 @@ impl SystemClauseType {
&SystemClauseType::PutByte => { &SystemClauseType::PutByte => {
clause_name!("$put_byte") clause_name!("$put_byte")
} }
&SystemClauseType::PutBytes => {
clause_name!("$put_bytes")
}
&SystemClauseType::PutChar => { &SystemClauseType::PutChar => {
clause_name!("$put_char") clause_name!("$put_char")
} }
@@ -552,6 +556,9 @@ impl SystemClauseType {
("$put_byte", 2) => { ("$put_byte", 2) => {
Some(SystemClauseType::PutByte) Some(SystemClauseType::PutByte)
} }
("$put_bytes", 2) => {
Some(SystemClauseType::PutBytes)
}
("$put_char", 2) => { ("$put_char", 2) => {
Some(SystemClauseType::PutChar) Some(SystemClauseType::PutChar)
} }

View File

@@ -367,8 +367,20 @@ format(Fs, Args) :-
format(Stream, Fs, Args) :- format(Stream, Fs, Args) :-
phrase(format_(Fs, Args), Cs), phrase(format_(Fs, Args), Cs),
( stream_property(Stream, type(binary)) -> ( stream_property(Stream, type(binary)) ->
maplist(char_code, Cs, Bytes), % maplist(char_code, Cs, Bytes) is currently a lot slower
maplist(put_byte(Stream), Bytes) % 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) ; maplist(put_char(Stream), Cs)
). ).

View File

@@ -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 => { &SystemClauseType::GetByte => {
let mut stream = let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?; self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;