Hi,

I am using the following version of go :
PS C:\Temp> go version
go version go1.13.5 windows/amd64

I am trying to compare the performance of QuickUnion (just the basic one 
with no weighting/ranking/path compression) and QuickFind algorithms.
My benchmarking test cases basically create a (N-1) element array of pairs 
starting with (0,1), (1,2).....all the way upto (N-2,N-1). N is the number 
of data points. The benchmarking is run for N=10,100,1000.
The benchmark functions then test the union-find functions by creating all 
the connections from the above array of pairs.

>From the Benchmarking results, it appears that the QuickUnion function is 
taking longer than the QuickFind function for the same data size and same 
set of input pairs.

QuickFind benchmarking results.
Running tool: C:\Go\bin\go.exe test -benchmem -run=^$ github.com\en-vee\ds 
-bench ^(BenchmarkQuickFind)$

goos: windows
goarch: amd64
pkg: github.com/en-vee/ds
BenchmarkQuickFind/BenchmarkQuickFind10-8           36392860           
 33.2 ns/op         0 B/op          0 allocs/op
BenchmarkQuickFind/BenchmarkQuickFind100-8           3199598           388 
ns/op           0 B/op          0 allocs/op
BenchmarkQuickFind/BenchmarkQuickFind1000-8           300667          3852 
ns/op           0 B/op          0 allocs/op
PASS
ok      github.com/en-vee/ds    5.064s
Success: Benchmarks passed.


QuickUnion benchmarking results (See how much poorly they perform as 
compared to the QuickFind. The times per op are almost double the times for 
QuickFind).

Running tool: C:\Go\bin\go.exe test -benchmem -run=^$ github.com\en-vee\ds 
-bench ^(BenchmarkQuickUnion)$

goos: windows
goarch: amd64
pkg: github.com/en-vee/ds
BenchmarkQuickUnion/BenchmarkQuickUnion10-8             17946232           
 65.4 ns/op         0 B/op          0 allocs/op
BenchmarkQuickUnion/BenchmarkQuickUnion100-8               88495         
13516 ns/op           0 B/op          0 allocs/op
BenchmarkQuickUnion/BenchmarkQuickUnion1000-8                907       
1328386 ns/op           0 B/op          0 allocs/op
PASS
ok      github.com/en-vee/ds    4.691s
Success: Benchmarks passed.


Upon CPU profiling the BenchmarkQuickUnion test case, the two for loops 
related to the Find operation take the maximum time, but I am surprised 
that this function is taking longer because the loop does not iterate 
through the entire Array for any pair. Infact, I guess the loops must be 
performing only 2 iterations per pair. (Also see the pprof CPU profile 
attachment which shows the QuickUnion CPU profile for my function 
QuickUnion).

Is the array lookup being performed by the Find operations in QuickUnion 
function, causing this performance bottleneck ?

I guess the most surprising bit is : Why is QuickUnion slower than 
QuickFind for the same input data ? Or am I missing something ?

(BTW, the implementations are based on Robert Sedgwick's equivalent 
implementations in C as given in his excellent book)

The QuickUnion and Quick Find functions are as below : 

QuickUnion

func quickUnion(a []int, p, q int) {
   var i, j int

    for i = p; i != a[i]; i = a[i] {
   }

    for j = q; j != a[j]; j = a[j] {
   }

    if i != j {
       a[i] = j
   }
}

QuickFind

func qf(a []int, p, q int) {
   // Are p and q already connected ?
   if a[p] == a[q] {
       return
   }

    n := len(a)

    for i := 0; i < n; i++ {
       if a[i] == a[p] {
           a[i] = a[q]
       }
   }
}

My benchmarking test cases :

BenchmarkQuickUnion

func BenchmarkQuickUnion(b *testing.B) {
   type pair struct {
       X int
       Y int
   }
   bmTestSizes := []int{10, 100, 1000}
   for _, bmTestSize := range bmTestSizes {
       a := createSlice(bmTestSize)
       pairs := make([]pair, bmTestSize-1, bmTestSize-1)
       // Create a slice of pairs
       for j := 0; j < bmTestSize-1; j++ {
           pairs[j] = pair{j, j + 1}
       }
       pLen := bmTestSize - 1
       //b.ResetTimer()
       bmName := fmt.Sprintf("BenchmarkQuickUnion%d", bmTestSize)
       b.Run(bmName, func(b *testing.B) {
           for i := 0; i < b.N; i++ {
               for j := 0; j < pLen; j++ {
                   quickUnion(a, pairs[j].X, pairs[j].Y)
               }
               //qf(a, (len(a)-1)/2, len(a)-1)
           }
       })
   }
}


BenchmarkQuickFind
func BenchmarkQuickFind(b *testing.B) {

    type pair struct {
       X int
       Y int
   }
   bmTestSizes := []int{10, 100, 1000, 10000, 100000}
   for _, bmTestSize := range bmTestSizes {
       a := createSlice(bmTestSize)
       pairs := make([]pair, bmTestSize-1, bmTestSize-1)
       // Create a slice of pairs
       for j := 0; j < bmTestSize-1; j++ {
           pairs[j] = pair{j, j + 1}
       }
       pLen := bmTestSize - 1

        bmName := fmt.Sprintf("BenchmarkQuickFind%d", bmTestSize)
       b.Run(bmName, func(b *testing.B) {
           for i := 0; i < b.N; i++ {
               for j := 0; j < pLen; j++ {
                   qf(a, pairs[j].X, pairs[j].Y)
               }
           }
       })
   }
}
Enter code here...


-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/65420a77-29be-45ac-b57b-64bf05b5f480%40googlegroups.com.
Title: Pprof listing
File: ds.test.qu100
Type: cpu
Time: Feb 15, 2020 at 6:31pm (AEDT)
Duration: 1.42s, Total samples = 1.30s (91.44%)
Total: 1.30s

github.com/en-vee/ds.quickUnion

C:\Users\neeraj.vaidya\go\src\github.com\en-vee\ds\ds.go

  Total:       1.27s      1.27s (flat, cum) 97.69%
     55            .          .           	} 
     56            .          .           	//fmt.Printf("%d-%d\n", p, q) 
     57            .          .           	//fmt.Println(a) 
     58            .          .           } 
     59            .          .            
     60            .          .           func quickUnion(a []int, p, q int) {                    .          .   509b10:     SUBQ $0x18, SP                                                               ds.go:60
                   .          .   509b14:     MOVQ BP, 0x10(SP)                                                            ds.go:60
                   .          .   509b19:     LEAQ 0x10(SP), BP                                                            ds.go:60

     61            .          .            
     62            .          .           	//aLen := len(a) 
     63            .          .            
     64            .          .           	var i, j int 
     65            .          .            
     66            .          .           	// Follow from a[p] 
     67            .          .            
     68        610ms      610ms           	for i = p; i != a[i]; i = a[i] {                    .          .   509b1e:             MOVQ 0x20(SP), DX                                                    ds.go:68
                   .          .   509b23:             MOVQ 0x28(SP), BX                                                    ds.go:68
                   .          .   509b28:             MOVQ 0x38(SP), SI                                                    ds.go:68
                   .          .   509b2d:             JMP 0x509b32                                                         ds.go:68
               160ms      160ms   509b2f:             MOVQ DI, SI                                                          ds.go:68
                   .          .   509b32:             CMPQ BX, SI                                                          ds.go:68
                   .          .   509b35:             JAE 0x509b76                                                         ds.go:68
                60ms       60ms   509b37:             MOVQ 0(DX)(SI*8), DI                                                 ds.go:68
               390ms      390ms   509b3b:             CMPQ DI, SI                                                          ds.go:68
                   .          .   509b3e:             JNE 0x509b2f                                                         ds.go:68
                                     ⋮
                   .          .   509b76:             MOVQ SI, AX                                                          ds.go:68
                   .          .   509b79:             MOVQ BX, CX                                                          ds.go:68
                   .          .   509b7c:             CALL runtime.panicIndex(SB)                                          ds.go:68
                   .          .   509b81:             NOPL                                                                 ds.go:68
                   .          .   509b82:             INT $0x3                                                             
                   .          .   509b83:             INT $0x3                                                             
                   .          .   509b84:             INT $0x3                                                             
                   .          .   509b85:             INT $0x3                                                             
                   .          .   509b86:             INT $0x3                                                             
                   .          .   509b87:             INT $0x3                                                             
                   .          .   509b88:             INT $0x3                                                             
                   .          .   509b89:             INT $0x3                                                             
                   .          .   509b8a:             INT $0x3                                                             
                   .          .   509b8b:             INT $0x3                                                             
                   .          .   509b8c:             INT $0x3                                                             
                   .          .   509b8d:             INT $0x3                                                             
                   .          .   509b8e:             INT $0x3                                                             

     69            .          .           	} 
     70            .          .            
     71        610ms      610ms           	for j = q; j != a[j]; j = a[j] {                 10ms       10ms   509b40:             MOVQ 0x40(SP), DI                                                    ds.go:71
                   .          .   509b45:             JMP 0x509b4a                                                         ds.go:71
               170ms      170ms   509b47:             MOVQ R8, DI                                                          ds.go:71
                   .          .   509b4a:             CMPQ BX, DI                                                          ds.go:71
                   .          .   509b4d:             JAE 0x509b6b                                                         ds.go:71
                50ms       50ms   509b4f:             MOVQ 0(DX)(DI*8), R8                                                 ds.go:71
               380ms      380ms   509b53:             CMPQ R8, DI                                                          ds.go:71
                   .          .   509b56:             JNE 0x509b47                                                         ds.go:71
                                     ⋮
                   .          .   509b6b:             MOVQ DI, AX                                                          ds.go:71
                   .          .   509b6e:             MOVQ BX, CX                                                          ds.go:71
                   .          .   509b71:             CALL runtime.panicIndex(SB)                                          ds.go:71

     72            .          .           	} 
     73            .          .            
     74         10ms       10ms           	if i != j {                 10ms       10ms   509b58:             CMPQ SI, DI                                                          ds.go:74
                   .          .   509b5b:             JE 0x509b61                                                          ds.go:74

     75         40ms       40ms           		a[i] = j                    .          .   509b5d:                     MOVQ DI, 0(DX)(SI*8)                                         ds.go:75
                30ms       30ms   509b61:                     MOVQ 0x10(SP), BP                                            ds.go:75
                10ms       10ms   509b66:                     ADDQ $0x18, SP                                               ds.go:75
                   .          .   509b6a:                     RET                                                          ds.go:75

     76            .          .           	} 
     77            .          .           } 
     78            .          .            
     79            .          .           func quickUnionMT(a []int, p, q int) { 
     80            .          .           	//aLen := len(a) 

Reply via email to