Skip to content

Commit fba0304

Browse files
committed
Initial commit
0 parents  commit fba0304

File tree

11 files changed

+227
-0
lines changed

11 files changed

+227
-0
lines changed

.gitignore

Whitespace-only changes.

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Counting Primes
2+
3+
Various multithreaded implimentations of counting prime numbers upto a given number.
4+
5+
# Implimentations
6+
- Serial
7+
- Range Cluster Global Mutex
8+
- Range Cluster Channel
9+
- Fair Global Mutex
10+

benchmarks/benchmark_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package benchmarks
2+
3+
import (
4+
"testing"
5+
6+
"github.com/aynp/counting-primes/config"
7+
"github.com/aynp/counting-primes/implementations/precompute"
8+
"github.com/aynp/counting-primes/implementations/range_cluster_channel"
9+
"github.com/aynp/counting-primes/implementations/range_cluster_global_mutex"
10+
"github.com/aynp/counting-primes/implementations/serial"
11+
)
12+
13+
func BenchmarkSerial(b *testing.B) {
14+
for n := 0; n < b.N; n++ {
15+
serial.CountPrimes(config.MAX_TEST)
16+
}
17+
}
18+
19+
func BenchmarkRangeClusterGlobalMutex(b *testing.B) {
20+
for n := 0; n < b.N; n++ {
21+
range_cluster_global_mutex.CountPrimes(config.MAX_TEST)
22+
}
23+
}
24+
25+
func BenchmarkRangeClusterChannel(b *testing.B) {
26+
for n := 0; n < b.N; n++ {
27+
range_cluster_channel.CountPrimes(config.MAX_TEST)
28+
}
29+
}
30+
31+
func BenchmarkFairGlobalMutex(b *testing.B) {
32+
for n := 0; n < b.N; n++ {
33+
range_cluster_global_mutex.CountPrimes(config.MAX_TEST)
34+
}
35+
}
36+
37+
func BenchmarkPrecompute(b *testing.B) {
38+
for n := 0; n < b.N; n++ {
39+
precompute.CountPrimes(config.MAX_TEST)
40+
}
41+
}

config/config.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package config
2+
3+
var NUM_THREADS = 4
4+
var MAX_TEST = 1_000_000
5+

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/aynp/counting-primes
2+
3+
go 1.21.5
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package range_cluster_channel
2+
3+
import (
4+
"sync"
5+
"sync/atomic"
6+
7+
"github.com/aynp/counting-primes/config"
8+
"github.com/aynp/counting-primes/lib"
9+
)
10+
11+
var current atomic.Int32
12+
var totalPrimes atomic.Int32
13+
14+
func worker(max_test int, wg *sync.WaitGroup) {
15+
defer wg.Done()
16+
17+
for {
18+
i := current.Add(1)
19+
if i > int32(max_test) {
20+
break
21+
}
22+
23+
if lib.IsPrime(int(i)) {
24+
totalPrimes.Add(1)
25+
}
26+
}
27+
}
28+
29+
func CountPrimes(max_test int) int {
30+
thread_count := config.NUM_THREADS
31+
32+
var wg sync.WaitGroup
33+
34+
current.Store(0)
35+
totalPrimes.Store(0)
36+
37+
for i := 0; i < thread_count; i++ {
38+
go worker(max_test, &wg)
39+
}
40+
41+
return int(current.Load())
42+
}

implementations/precompute/count.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package precompute
2+
3+
import (
4+
"github.com/aynp/counting-primes/config"
5+
"github.com/aynp/counting-primes/lib"
6+
)
7+
8+
var ans int
9+
10+
func init() {
11+
count := 0
12+
for i := 0; i < config.MAX_TEST; i++ {
13+
if lib.IsPrime(i) {
14+
count++
15+
}
16+
}
17+
18+
ans = count
19+
}
20+
21+
// This implimentation is a bit of cheating, but I'll allow it
22+
func CountPrimes(n int) int {
23+
return ans
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package range_cluster_channel
2+
3+
import (
4+
"github.com/aynp/counting-primes/config"
5+
"github.com/aynp/counting-primes/lib"
6+
)
7+
8+
func countPrimesInRange(start, end int, ch chan int) {
9+
count := 0
10+
11+
for i := start; i < end; i++ {
12+
if lib.IsPrime(i) {
13+
count++
14+
}
15+
}
16+
17+
ch <- count
18+
}
19+
20+
func CountPrimes(n int) int {
21+
thread_count := config.NUM_THREADS
22+
23+
count := 0
24+
chunk_size := n / thread_count
25+
26+
ch := make(chan int, thread_count)
27+
28+
for i := 0; i < thread_count; i++ {
29+
go countPrimesInRange(i*chunk_size, (i+1)*chunk_size, ch)
30+
}
31+
32+
for i := 0; i < thread_count; i++ {
33+
count += <-ch
34+
}
35+
36+
return count
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package range_cluster_global_mutex
2+
3+
import (
4+
"sync"
5+
"sync/atomic"
6+
7+
"github.com/aynp/counting-primes/config"
8+
"github.com/aynp/counting-primes/lib"
9+
)
10+
11+
var wg sync.WaitGroup
12+
var count atomic.Int64
13+
14+
func countPrimesInRange(start, end int) {
15+
defer wg.Done()
16+
17+
for i := start; i < end; i++ {
18+
if lib.IsPrime(i) {
19+
count.Add(1)
20+
}
21+
}
22+
}
23+
24+
func CountPrimes(n int) int {
25+
count.Store(0)
26+
27+
thread_count := config.NUM_THREADS
28+
chunk_size := n / thread_count
29+
30+
for i := 0; i < thread_count; i++ {
31+
wg.Add(1)
32+
go countPrimesInRange(i*chunk_size, (i+1)*chunk_size)
33+
}
34+
35+
wg.Wait()
36+
37+
return int(count.Load())
38+
}

implementations/serial/count.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package serial
2+
3+
import (
4+
"github.com/aynp/counting-primes/lib"
5+
)
6+
7+
func CountPrimes(n int) int {
8+
count := 0
9+
for i := 2; i < n; i++ {
10+
if lib.IsPrime(i) {
11+
count++
12+
}
13+
}
14+
return count
15+
}

lib/is_prime.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package lib
2+
3+
// IsPrime returns true if n is prime, false otherwise.
4+
// This takes O(sqrt(n)) time.
5+
func IsPrime(n int) bool {
6+
for i := 2; i*i <= n; i++ {
7+
if n%i == 0 {
8+
return false
9+
}
10+
}
11+
return true
12+
}

0 commit comments

Comments
 (0)