HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMinor

Benchmark switch, binary search and if-else

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
searchelsebinarybenchmarkandswitch

Problem

Just for curiosity I have done some benchmark for testing the best performance between switch, binary-search, and if-else statement.
here is the code :

```
package switchStatement

type Badge struct {
score int
badge string
}

func initiateBadges() []Badge {
badge := []Badge{
{score: 4501, badge: "gold-1.gif"},
{score: 10001, badge: "gold-2.gif"},
{score: 15001, badge: "gold-3.gif"},
{score: 30001, badge: "gold-4.gif"},
{score: 45001, badge: "gold-5.gif"},
{score: 50001, badge: "diamond-1.gif"},
{score: 100001, badge: "diamond-2.gif"},
{score: 150001, badge: "diamond-3.gif"},
{score: 200001, badge: "diamond-4.gif"},
{score: 500001, badge: "diamond-5.gif"},
}

return badge
}

func GetReputationBadgeImprove(score int) string {

badges := initiateBadges()

//search score using binary search
index := BinarySearchBadge(badges, score)
if index == -1 {
return "badges-off.jpg"
}
return badges[index].badge
}

func BinarySearchBadge(badges []Badge, score int) int {
low := 0
high := len(badges) - 1
middle := (high + low) / 2

for low score {
return middle
} else if badges[middle].score >= score {
high = middle - 1

} else {
low = middle + 1
}

middle = (high + low) / 2
}

return -1
}

func GetReputationBadgeImproveSwitchCase(score int) string {
switch {
case score >= 500001:
return "diamond-5.gif"
case score >= 200001:
return "diamond-4.gif"
case score >= 150001:
return "diamond-3.gif"
case score >= 100001:
return "diamond-2.gif"
case score >= 50001:
return "diamond-1.gif"
case score >= 45001:
return "gold-5.gif"
case score >= 30001:
return "gold-4.gif"
case score >= 15001:
return "gold-3.gif"
case score >= 10001:
return "gold-2.gif"
case

Solution

In GetReputationBadge, you're needlessly allocating strings by modifying the badge variable. It would be a fairer benchmark to write it in the following way:

func GetReputationBadge(score int) string {
    if score >= 500001 {
        return "diamond-5.gif"
    }
    if score >= 200001 {
        return "diamond-4.gif"
    }
    // etc.
    if score >= 4501 {
        return "gold-1.gif"
    }
    return "badges-off.jpg"
}


(That said, I'm not convinced it matters — the compiler should probably optimize this anyway.)

I tried it and was very surprised to see that the benchmarks were still very poor. Turns out, you called the wrong function in your benchmark :-) BenchmarkGetReputation1If calls benchmarkGetReputation insead of benchmarkGetReputationIf. Retrying it with this fixed leads to the expected result:

BenchmarkGetReputation1-4           10000000       188 ns/op
BenchmarkGetReputation2-4           10000000       182 ns/op
BenchmarkGetReputation3-4           10000000       179 ns/op
BenchmarkGetReputation4-4           10000000       192 ns/op
BenchmarkGetReputation1Switch-4     300000000         4.55 ns/op
BenchmarkGetReputation2Switch-4     300000000         4.32 ns/op
BenchmarkGetReputation3Switch-4     300000000         4.63 ns/op
BenchmarkGetReputation4Switch-4     2000000000         0.84 ns/op
BenchmarkGetReputation1If-4         300000000         4.21 ns/op
BenchmarkGetReputation2If-4         300000000         4.19 ns/op
BenchmarkGetReputation3If-4         300000000         4.74 ns/op
BenchmarkGetReputation4If-4         2000000000         0.88 ns/op


Note that this benchmark is still pretty flawed: you're only testing it with a couple of values, so depending on which they are, the order of the if/else statements are going to matter. You should use much more values, picked among a reasonable distribution instead.

Code Snippets

func GetReputationBadge(score int) string {
    if score >= 500001 {
        return "diamond-5.gif"
    }
    if score >= 200001 {
        return "diamond-4.gif"
    }
    // etc.
    if score >= 4501 {
        return "gold-1.gif"
    }
    return "badges-off.jpg"
}
BenchmarkGetReputation1-4           10000000       188 ns/op
BenchmarkGetReputation2-4           10000000       182 ns/op
BenchmarkGetReputation3-4           10000000       179 ns/op
BenchmarkGetReputation4-4           10000000       192 ns/op
BenchmarkGetReputation1Switch-4     300000000         4.55 ns/op
BenchmarkGetReputation2Switch-4     300000000         4.32 ns/op
BenchmarkGetReputation3Switch-4     300000000         4.63 ns/op
BenchmarkGetReputation4Switch-4     2000000000         0.84 ns/op
BenchmarkGetReputation1If-4         300000000         4.21 ns/op
BenchmarkGetReputation2If-4         300000000         4.19 ns/op
BenchmarkGetReputation3If-4         300000000         4.74 ns/op
BenchmarkGetReputation4If-4         2000000000         0.88 ns/op

Context

StackExchange Code Review Q#149153, answer score: 2

Revisions (0)

No revisions yet.