123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2022 Nomadic Labs, <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openProtocol.Alpha_context.Sc_rollupletdefault_new_dissection~default_number_of_sections~(start_chunk:Game.dissection_chunk)~(our_stop_chunk:Game.dissection_chunk)=letmax_number_of_sections=Z.of_intdefault_number_of_sectionsinlettrace_length=Tick.distanceour_stop_chunk.tickstart_chunk.tickinletnumber_of_sections=Z.minmax_number_of_sectionstrace_lengthinletrem=Z.(remtrace_lengthnumber_of_sections)inletfirst_section_length,section_length=ifCompare.Z.(trace_length<=max_number_of_sections)then(* In this case, every section is of length one. *)Z.(one,one)elseletsection_length=Z.(maxone(divtrace_lengthnumber_of_sections))inifCompare.Z.(section_length=Z.one)&¬Compare.Z.(rem=Z.zero)then(* If we put [section_length] in this situation, we will most likely
have a very long last section. *)(rem,section_length)else(section_length,section_length)in(* [k] is the number of sections in [rev_dissection]. *)letrecmakerev_dissectionktick=ifZ.(equalknumber_of_sections)thenList.revrev_dissectionelseletnext_tick=Tick.jumpticksection_lengthinmake(tick::rev_dissection)(Z.succk)next_tickinmake[]Z.one(Tick.jumpstart_chunk.tickfirst_section_length)letmake_dissection~state_of_tick~state_hash_of_eval_state?start_state~start_chunk~our_stop_chunkticks=letrecmake_dissection_auxstart_stateticksacc=letopenLwt_result_syntaxinmatchtickswith|tick::rst->let*eval_state=state_of_tick?start_statetickinletstate_hash=Option.mapstate_hash_of_eval_stateeval_stateinletchunk=Dissection_chunk.{tick;state_hash}inmake_dissection_auxeval_staterst(chunk::acc)|[]->return@@List.rev(our_stop_chunk::acc)inmake_dissection_auxstart_stateticks[start_chunk]moduleWasm=structletnew_dissection~default_number_of_sections~start_chunk~our_stop_chunk=letopenDissection_chunkinletdist=Tick.distancestart_chunk.tickour_stop_chunk.tickinletticks_per_snapshot=Wasm_2_0_0PVM.ticks_per_snapshotinifCompare.Z.(dist<=ticks_per_snapshot)then(*
There are two cases that require us to fall back to the
default behavior. Either [start_chunk] is not aligned on the
size of a snapshot (meaning the PVM is stuck) or the distance
between the start and stop chunk is lesser than a snapshot,
meaning we have already found the kernel_run invocation we
were looking for.
*)default_new_dissection~default_number_of_sections~start_chunk~our_stop_chunkelseletis_stop_chunk_aligned=Compare.Z.(Z.rem(Tick.to_zour_stop_chunk.tick)ticks_per_snapshot=Z.zero)inletfinal_tick=Tick.of_zZ.(div(Tick.to_zour_stop_chunk.tick)ticks_per_snapshot*ticks_per_snapshot)inletdist=Tick.distancestart_chunk.tickfinal_tickinletmax_number_of_sections=Z.(divdistticks_per_snapshot)inletnumber_of_sections=Z.min(Z.of_int(* If [is_stop_chunk_aligned] is false, we allocate one
sections for the surplus. *)(ifis_stop_chunk_alignedthendefault_number_of_sectionselsedefault_number_of_sections-1))max_number_of_sectionsin(* [go remaining_sections last_tick dist] tries to compute
[remaining_sections] sections as evenly as possible, starting
from [last_tick] and covering [dist] ticks. *)letrecgoremaining_sectionslast_tickdistrev_acc=(* The last section is created by [make_dissection] when it
adds the [stop_chunk]. *)ifZ.(remaining_sections<=one)thenletrev_acc=(* If [is_stop_chunk_aligned] is false, we insert the
last snapshot point. *)ifis_stop_chunk_alignedthenrev_accelsefinal_tick::rev_accinList.revrev_accelse(*
We compute the length of the next section of the
dissection as the maximum size such that if we would give
this number to all remaining sections, we would not
consume more than [dist] ticks. This is ensured by
[Z.div], which computes a lower rounding.
*)letsection_len=Z.(dist/(ticks_per_snapshot*remaining_sections)*ticks_per_snapshot)inletnext_tick=Tick.jumplast_ticksection_leninletnext_dist=Z.(dist-section_len)in(*
There are two cases to consider here.
1. Either [dist] was a multiple of
[ticks_per_snapshot]. In that case, the same
[section_len] will be computed in all subsequent
calls of [go].
2. Or [dist] was not a multiple of
[ticks_per_snapshot]. In that case, the next
[section_len] in float will be slightly higher than
the previous one, because it will benefit from the
unconsumed reminder of the previous computation,
until enough is left that [dist] becomes a
multiplier of [ticks_per_snapshot]. In that case, we
will fall back to case 1.
Take case of dividing 60 into 32 chunks.
- [remaining_sections = 60], [remaining_sections = 32], and
[section_len = 1] (60 / 32 ~= 1.87)
- [remaining_sections = 59], [remaining_sections = 31], and
[section_len = 1] (59 / 31 ~= 1.90)
- [remaining_sections = 58], [remaining_sections = 30], and
[section_len = 1] (58 / 30 ~= 1.93)
- [remaining_sections = 57], [remaining_sections = 29], and
[section_len = 1] (57 / 29 ~= 1.97)
- [remaining_sections = 56], [remaining_sections = 28], and
[section_len = 2] (56 / 28 = 2)
All remaining sections will be of length 2.
*)goZ.(predremaining_sections)next_ticknext_dist(next_tick::rev_acc)ingonumber_of_sectionsstart_chunk.tickdist[]end