Skip to content

Commit a41b49f

Browse files
author
Alex Kahn
committed
initial commit
0 parents  commit a41b49f

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/akahn/lottery
2+
3+
go 1.19

go.sum

Whitespace-only changes.

main.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package main
2+
3+
import (
4+
"encoding/binary"
5+
"encoding/hex"
6+
"flag"
7+
"fmt"
8+
"log"
9+
"os"
10+
"runtime"
11+
"runtime/pprof"
12+
"sync"
13+
"sync/atomic"
14+
"time"
15+
)
16+
17+
var start = flag.Int64("start", 0, "start timestamp")
18+
var end = flag.Int64("end", time.Now().Unix(), "end timestamp")
19+
20+
func main() {
21+
flag.Parse()
22+
23+
// TODO: Investigate the suspiciously round numbers
24+
beginRange := *start
25+
endRange := *end
26+
span := endRange - beginRange
27+
28+
cores := runtime.NumCPU()
29+
chunkSize := int64(float64(span) / float64(cores))
30+
log.Printf("Dividing %d (%d–%d) timestamps into %d chunks of size %d", span, beginRange, endRange, cores, chunkSize)
31+
32+
if profile, _ := os.LookupEnv("PROFILE"); profile != "" {
33+
filename := fmt.Sprintf("profile_%d-%d.pprof", beginRange, endRange)
34+
f, err := os.Create(filename)
35+
if err != nil {
36+
log.Fatal(err)
37+
}
38+
39+
pprof.StartCPUProfile(f)
40+
defer pprof.StopCPUProfile()
41+
}
42+
43+
wg := sync.WaitGroup{}
44+
count := atomic.Int64{}
45+
46+
for i := 0; i < cores; i += 1 {
47+
wg.Add(1)
48+
start := beginRange + (int64(i) * chunkSize)
49+
end := start + chunkSize - 1
50+
log.Printf("Spawning goroutine %d from %d to %d (chunk size %d)", i, start, end, chunkSize)
51+
go scanRange(i, start, end, &count, &wg)
52+
}
53+
54+
wg.Wait()
55+
total := count.Load()
56+
log.Printf("Total: %d/%d (%f)", total, span, float64(total)/float64(span))
57+
}
58+
59+
func scanRange(id int, start int64, end int64, count *atomic.Int64, wg *sync.WaitGroup) {
60+
timestamp := uint32(start)
61+
62+
numericalCount := 0
63+
passes := 0
64+
65+
var b [4]byte
66+
for {
67+
if timestamp >= uint32(end) {
68+
log.Printf("Goroutine %d reached the end (%d). Found numerical hexes in %d/%d (%f) passes.", id, timestamp, numericalCount, passes, float64(numericalCount)/float64(passes))
69+
count.Add(int64(numericalCount))
70+
wg.Done()
71+
return
72+
}
73+
74+
binary.BigEndian.PutUint32(b[0:4], timestamp)
75+
// TODO: Reduce allocations by replacing EncodeToString with Encode
76+
hex := hex.EncodeToString(b[:])
77+
78+
if containsLetter([]byte(hex)) {
79+
// Found an alphabetical character, skip this ID altogether
80+
passes += 1
81+
timestamp += 1
82+
continue
83+
}
84+
85+
// No alphabetical characters encountered
86+
//fmt.Printf("%s %d\n", hex, timestamp)
87+
numericalCount += 1
88+
passes += 1
89+
timestamp += 1
90+
}
91+
}
92+
93+
func containsLetter(id []byte) bool {
94+
for _, ch := range id {
95+
if ch >= 97 && ch <= 122 {
96+
return true
97+
}
98+
}
99+
100+
return false
101+
}

0 commit comments

Comments
 (0)