Skip to content

Commit 55a05b7

Browse files
authored
knucleotide benchmark for Odin (#358)
1 parent afdbddb commit 55a05b7

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed

bench/algorithm/knucleotide/1.odin

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// contributed by Branimir Maksimovic
2+
3+
package main
4+
import "core:fmt"
5+
import "core:os"
6+
import "core:strings"
7+
import "core:bufio"
8+
import "core:io"
9+
import "core:thread"
10+
import "core:slice"
11+
12+
FACTOR :: 16
13+
main :: proc() {
14+
initTables()
15+
buf,err := read_lines_with_buffering()
16+
defer delete(buf)
17+
if err != io.Error.No_Progress {
18+
fmt.println("error:",err)
19+
return
20+
}
21+
Value :: union{u8,string}
22+
data:[]Value = { 1, 2 , "GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT" }
23+
for i in data {
24+
switch j in i {
25+
case u8:work(&buf,j)
26+
case string:work(&buf,j)
27+
}
28+
}
29+
}
30+
frequencies :: proc (buf:^string, count: u8) {
31+
hash := calculate(buf,cast(u32)count)
32+
defer delete_table(hash)
33+
list := make([dynamic]Value,0)
34+
defer {
35+
for i in list{
36+
delete(i.key)
37+
}
38+
delete(list)
39+
}
40+
Data :: struct { list:^[dynamic]Value, count:u8}
41+
data := Data{ &list, count}
42+
ForEach(hash,&data,proc(key:u64,value:^int,data:^Data) {
43+
append(data.list , Value{ decode(key,u32(data.count)), value^ })
44+
})
45+
slice.reverse_sort_by_key(list[:], proc(v:Value)->int{ return v.value })
46+
for entry in list {
47+
fmt.printf("%s %.3f\n", entry.key, 100.0 * f64(entry.value) / f64(len(buf) - int(count) + 1))
48+
}
49+
fmt.println()
50+
}
51+
count:: proc(buf:^string, entry: string) {
52+
hash := calculate(buf,cast(u32)len(entry))
53+
defer delete_table(hash)
54+
data, ok:=Get(hash,encode(transmute([]u8)entry))
55+
fmt.printf("%d\t%s\n",data^,entry)
56+
}
57+
work::proc { frequencies, count }
58+
hash_u64::proc(i:u64)->u64{
59+
return i
60+
}
61+
equal_u64::proc(l,r:u64)->bool{
62+
return l==r
63+
}
64+
calculate::proc(poly:^string, size: u32)->(rc:^HTable(u64,int)){
65+
rc = makeTable(u64,int,hash_u64,equal_u64)
66+
frames:[FACTOR]A;
67+
threads:[FACTOR]^thread.Thread
68+
A :: struct {
69+
poly: ^string,
70+
size: u32,
71+
i: u32,
72+
hash: ^HTable(u64,int),
73+
}
74+
ex :: proc(self: ^A){
75+
j := self.i
76+
for ;j < u32(len(self.poly)) +1 -self.size; j += FACTOR{
77+
data,ok := Get(self.hash,encode(transmute([]u8)self.poly[j:j+self.size]))
78+
data^+=1
79+
}
80+
}
81+
for frame,index in frames {
82+
frames[index] = { poly, size, u32(index), makeTable(u64,int,hash_u64,equal_u64) }
83+
threads[index] = thread.create_and_start_with_poly_data(&frames[index],ex)
84+
}
85+
for t,index in threads {
86+
thread.join(t)
87+
defer thread.destroy(t)
88+
ht := frames[index].hash
89+
defer delete_table(ht)
90+
ForEach(ht,rc,proc(key:u64,value:^int,rc:^HTable(u64,int)) {
91+
data,ok := Get(rc,key)
92+
data^+=value^
93+
})
94+
}
95+
return
96+
}
97+
read_lines_with_buffering :: proc() ->(string,io.Error){
98+
r: bufio.Reader
99+
buffer: [1024]byte
100+
f,err:=os.open(os.args[1])
101+
if err != os.ERROR_NONE {
102+
return "",io.Error(err)
103+
}
104+
defer os.close(f)
105+
bufio.reader_init_with_buf(&r, {os.stream_from_handle(f)}, buffer[:])
106+
defer bufio.reader_destroy(&r)
107+
108+
linerc:strings.Builder;
109+
strings.builder_init_none(&linerc);
110+
to_read :bool;
111+
for {
112+
line, err := bufio.reader_read_string(&r, '\n', context.allocator)
113+
defer delete(line, context.allocator)
114+
if err != nil {
115+
return strings.to_string(linerc),err
116+
}
117+
if !to_read && strings.has_prefix(line,`>THREE`) {
118+
to_read = true
119+
continue
120+
}
121+
if to_read {
122+
line = strings.trim_right(line, "\n")
123+
strings.write_string(&linerc,line)
124+
}
125+
}
126+
}
127+
Value::struct {
128+
key: string,
129+
value: int,
130+
}
131+
toChar :[256]rune
132+
toNum :[256]u8
133+
initTables :: proc () {
134+
toNum['A'] = 0
135+
toNum['C'] = 1
136+
toNum['T'] = 2
137+
toNum['G'] = 3
138+
toNum['a'] = 0
139+
toNum['c'] = 1
140+
toNum['t'] = 2
141+
toNum['g'] = 3
142+
143+
toChar[0] = 'A'
144+
toChar[1] = 'C'
145+
toChar[2] = 'T'
146+
toChar[3] = 'G'
147+
}
148+
149+
encode :: proc (i : []u8)->u64 {
150+
rc: u64
151+
for j in i {
152+
rc <<= 2
153+
rc |= u64(toNum[j])
154+
}
155+
return rc
156+
}
157+
decode::proc (i:u64,size:u32)->string {
158+
rc:strings.Builder;
159+
strings.builder_init_none(&rc);
160+
i := i
161+
for _ in 0..<size {
162+
strings.write_rune(&rc,toChar[i&3])
163+
i >>= 2
164+
}
165+
s := strings.to_string(rc)
166+
slice.reverse(transmute([]u8)s)
167+
return s
168+
}
169+
SIZE :: 1<<16
170+
HTable :: struct(Key,Value:typeid) {
171+
table:[SIZE]^Node(Key,Value),
172+
hash: proc(k:Key)->u64,
173+
equal:proc(l,r:Key)->bool,
174+
}
175+
Node :: struct(Key,Value:typeid) {
176+
key: Key,
177+
value: Value,
178+
next:^Node(Key,Value),
179+
}
180+
makeTable :: proc($Key,$Value:typeid, hash: proc(k:Key)->u64,equal:proc(l,r:Key)->bool )->^HTable(Key,Value) {
181+
rc := new(HTable(Key,Value))
182+
rc^ = {hash = hash,equal=equal}
183+
return rc
184+
}
185+
Get:: proc(input:^HTable($Key,$Value), key:Key)->(^Value,bool){
186+
hash := input.hash(key)
187+
slot := hash & (SIZE-1)
188+
n := input.table[slot]
189+
if n == nil {
190+
n = new(Node(Key,Value))
191+
n^ ={ key = key }
192+
input.table[slot] = n
193+
return &n.value,false
194+
}
195+
for ;n != nil;n=n.next {
196+
if input.equal(key,n.key) {
197+
return &n.value,true
198+
}
199+
}
200+
n = new(Node(Key,Value))
201+
n^ ={ key = key, next=input.table[slot] }
202+
input.table[slot] = n
203+
return &n.value,false
204+
}
205+
ForEach::proc(input:^HTable($Key,$Value), data:^$T, f:proc(k:Key,v:^Value,data:^T)) {
206+
for n in &input.table {
207+
for ;n!=nil;n=n.next{
208+
f(n.key,&n.value,data)
209+
}
210+
}
211+
}
212+
delete_table::proc(input:^HTable($Key,$Value)){
213+
for n in &input.table {
214+
for n!=nil{
215+
tmp := n
216+
n = n.next
217+
free(tmp)
218+
}
219+
}
220+
free(input)
221+
}

bench/bench_odin.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ problems:
33
- name: helloworld
44
source:
55
- 1.odin
6+
- name: knucleotide
7+
source:
8+
- 1.odin
69
- name: nsieve
710
source:
811
- 1.odin

0 commit comments

Comments
 (0)