I followed, as far as I could understand, the discussion on the possibilities and limitations of mmap.
For this reason and to gain experience with some aspects of IO, I tried to “play” with the following script which only uses the basic functions and the float parsing function as defined by @mkitti
no dependencies and seems very fast
julia> using BenchmarkTools
julia> file="IO_lammpstr.txt"
"IO_lammpstr.txt"
julia> function pmk(bytes::AbstractVector{UInt8}, _start::Int = 1, _end::Int = length(bytes))
int_val = 0
power = 0
for i in _start:_end
byte = bytes[i]
if byte != 0x2e
int_val *= 10
int_val += byte - 0x30
power *= 10
else
power = 1
end
end
q = int_val / power
return q
end
pmk (generic function with 3 methods)
julia> function fn(c,ch, s)
for i in s:lastindex(ch)
c==ch[i] && return i
end
end
fn (generic function with 1 method)
julia> function chnkpmk(ch)
res=[(0.,0.,0.) for _ in 1:2000]
ez=i=1
while ez <length(ch)
ei1=fn(0x20,ch,ez)
ei2=fn(0x20,ch,ei1+1)
ex=fn(0x20,ch,ei2+1)
x=pmk(ch,ei2+1,ex-1)
ey=fn(0x20,ch,ex+1)
y=pmk(ch,ex+1,ey-1)
ez=fn(0x0a,ch,ey)
z=pmk(ch,ey+1,ez-1)
res[i]=(x,y,z)
i+=1
end
res
end
chnkpmk (generic function with 1 method)
julia> function atomsb(buffer, L)
from=codeunits("TEM: ATOMS id type xs ys zs")
to=codeunits("ITEM: TIMESTEP")
lto=length(to)
append!(buffer,to)
t=last(findfirst(to,buffer))
f=last(findfirst(from,buffer))
while true
t=last(findnext(to,buffer,f))
ch=@view buffer[f+2:t-lto]
t>L&& (return f)
chnkpmk(ch)
f=last(findnext(from,buffer,t))
end
end
atomsb (generic function with 1 method)
julia> function fa(file, chunk=10^6)
buffer=[0x0]
io=open(file)
pos=1
while !eof(io)
L=readbytes!(io, buffer,chunk)
p=atomsb(buffer, L)
pos+=p
seek(io,pos)
end
end
fa (generic function with 2 methods)
julia> @btime fa(file)
24.145 ms (391 allocations: 10.73 MiB)
julia> @btime fa(file,3*10^5)
21.692 ms (318 allocations: 7.95 MiB)
julia> @btime fa(file,10^5)
8.434 ms (16 allocations: 247.91 KiB)
I’m not entirely sure that something isn’t lost in the transitions from one chunk to another.
But since it’s very fast and shows how performance can vary depending on the size of the chin k, maybe it’s worth testing it a bit
below are some tests to see how many steps per chunk are “processed”
tests
function atomsbtest(buffer, L)
from=codeunits("TEM: ATOMS id type xs ys zs")
to=codeunits("ITEM: TIMESTEP")
lto=length(to)
append!(buffer,to)
t=last(findfirst(to,buffer))
f=last(findfirst(from,buffer))
i=1
while true
t=last(findnext(to,buffer,f))
ch=@view buffer[f+2:t-lto]
t>L&& (return (f,i))
chnkpmk(ch)
i+=1
f=last(findnext(from,buffer,t))
end
end
function fatest(file, chunk=10^6)
buffer=[0x0]
io=open(file)
cn=[]
pos=1
while !eof(io)
L=readbytes!(io, buffer,chunk)
(p,i)=atomsb(buffer, L)
pos+=p
push!(cn,i)
seek(io,pos)
end
cnjulia> function atomsbtest(buffer, L)
from=codeunits("TEM: ATOMS id type xs ys zs")
to=codeunits("ITEM: TIMESTEP")
lto=length(to)
append!(buffer,to)
t=last(findfirst(to,buffer))
f=last(findfirst(from,buffer))
i=1
while true
t=last(findnext(to,buffer,f))
ch=@view buffer[f+2:t-lto]
t>L&& (return (f,i))
chnkpmk(ch)
i+=1
f=last(findnext(from,buffer,t))
end
end
atomsbtest (generic function with 1 method)
julia> function fatest(file, chunk=10^6)
buffer=[0x0]
io=open(file)
cn=[]
pos=1
while !eof(io)
L=readbytes!(io, buffer,chunk)
(p,i)=atomsbtest(buffer, L)
pos+=p
push!(cn,i)
seek(io,pos)
end
cn
end
fatest (generic function with 2 methods)
julia> fatest(file)
15-element Vector{Any}:
16
15
15
15
15
15
15
15
15
15
15
15
15
5
1
julia> fatest(file,3*10^5)
51-element Vector{Any}:
5
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
⋮
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
1
julia> fatest(file,10^5)
201-element Vector{Any}:
2
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
⋮
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
This text will be hidden