-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path1brc_hash.f90
157 lines (138 loc) · 4.12 KB
/
1brc_hash.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
module row_types
implicit none
type :: row_ptr
type(row), pointer :: p => null()
end type row_ptr
type :: row
character(len=:), allocatable :: key
real :: min
real :: max
real :: sum
integer :: count
end type row
end module row_types
module builder
use row_types
implicit none
contains
pure function str2real (str) result(f)
character(len=*), intent(in) :: str
integer :: i, off
integer, parameter :: zero = ichar('0')
real :: f
off = merge (2, 1, str(1:1)=='-')
i = len(str(off:))-1 !index(str(off:),'.')
if (i == 2) then
f = ichar(str(off:off)) - zero
else
f = (ichar(str(off:off)) - zero)*10 + ichar(str(off+1:off+1)) - zero
end if
f = f + (ichar(str(off+i:off+i)) - zero) / 10.0
if (off == 2) f = -f
end function str2real
subroutine update(buffer, hash_tbl)
character(len=*), intent(in) :: buffer
type(row_ptr), intent(inout) :: hash_tbl(:)
character(len=1), parameter :: cr = achar(10)
integer :: x, i, j, k
real :: f
integer :: offs(3) = [5,6,4]
i = 1
do while (i <= len(buffer))
k = scan(buffer(i:), cr)
do x = 1,3
j = i + k - 1 - offs(x)
if (buffer(j:j)==';') exit
end do
f = str2real(buffer(j+1:i+k-2))
call update_hash_tbl(buffer(i:j-1), f, hash_tbl)
i = i + k
end do
end subroutine update
pure function hash(key,m) result(h)
use, intrinsic :: iso_fortran_env, only: int64
integer(int64), parameter :: prime = 16777619_int64
integer(int64), parameter :: basis = 2166136261_int64
integer(int64) :: h
character(len=*), intent(in) :: key
integer, intent(in) :: m
integer :: i
h = basis
do i = 1, len(key)
h = ieor(h, iachar(key(i:i), int64))
h = mod(h * prime, 2_int64**32)
end do
h = mod (h,m)
end function hash
subroutine update_hash_tbl(key, val, hash_tbl)
character(len=*), intent(in) :: key
type(row_ptr), intent(inout) :: hash_tbl(:)
type(row), pointer :: vals
integer :: h, l
real, intent(in) :: val
l = size(hash_tbl)
h = hash(key, l)
do
vals => hash_tbl(h)%p
if (.not. associated(vals)) then
allocate (hash_tbl(h)%p)
vals => hash_tbl(h)%p
allocate(character(len=len(key)) :: vals%key)
vals%key = key
vals%min = val
vals%max = val
vals%sum = val
vals%count = 1
exit
else if (vals%key == key) then
if (val < vals%min) vals%min = val
if (val > vals%max) vals%max = val
vals%sum = vals%sum + val
vals%count = vals%count + 1
exit
else
h = mod(h+1, l)
end if
end do
end subroutine update_hash_tbl
subroutine display(hash_tbl)
type(row_ptr), intent(in) :: hash_tbl(:)
type(row), pointer :: vals
integer :: i
do i = 1, size(hash_tbl)
if (associated(hash_tbl(i)%p)) then
vals => hash_tbl(i)%p
print '(A,F5.1,F5.1,F5.1)', vals%key, &
vals%min, vals%max, vals%sum / vals%count
end if
end do
end subroutine display
end module builder
program one_brc
use row_types
use builder
implicit none
integer, parameter :: buffer_size = 65536, tail_len=100
integer, parameter :: hash_tbl_size = 65535
character(len=:), allocatable :: buffer
integer(kind=8) :: fd, read_size, off, start
type(row_ptr) :: hash_tbl(hash_tbl_size)
open(newunit=fd, file='measurements.txt', access='stream', &
form='unformatted', status='old')
inquire(unit=fd, size=read_size)
do while (read_size > 0)
allocate(character(len=min(read_size, buffer_size)) :: buffer)
read(fd) buffer
if (read_size <= buffer_size) then
call update(buffer, hash_tbl)
exit
end if
start = len(buffer)-tail_len
off = start + scan(buffer(start:), achar(10), back=.true.)-1
call update(buffer(1:off), hash_tbl)
call fseek(fd, off - len(buffer), 1)
read_size = read_size - off
deallocate(buffer)
end do
call display(hash_tbl)
end program one_brc