Skip to content

Instantly share code, notes, and snippets.

@cellularmitosis cellularmitosis/README.md
Last active Apr 29, 2020

Embed
What would you like to do?
Trivial rect filling SDL2 benchmark in Golang and Python

Blog 2020/4/19

<- previous | index | next ->

Trivial rect filling SDL2 benchmark in Golang and Python

I threw together a few trivial benchmarks to compare the rect filling performance of golang vs. python. The underlying SDL2 libraries are of course written in C, but I wanted to compare the overhead of the language bindings.

Screen Shot 2020-04-19 at 6 31 34 PM

The performance is similar enough that it isn't a deciding factor in language choice.

Mid-2012 Macbook Pro, macOS:

cell@flouride(master)$ go run rectbench.go 
1000 fills (fps): 67751.2
100 fills per update (fps): 13550.6
10 fills per update (fps): 2951.8
1 fill per update (fps): 262.7

cell@flouride(master)$ go run rectbench.go 
1000 fills (fps): 67186.1
100 fills per update (fps): 14093.7
10 fills per update (fps): 3193.3
1 fill per update (fps): 245.0

cell@flouride(master)$ go run rectbench.go 
1000 fills (fps): 67935.5
100 fills per update (fps): 11114.6
10 fills per update (fps): 2994.6
1 fill per update (fps): 269.3
cell@flouride(master)$ ./rectbench.py 
1000 fills (fps): 36009.1
100 fills per update (fps): 12388.7
10 fills per update (fps): 2340.7
1 fill per update (fps): 307.2

cell@flouride(master)$ ./rectbench.py 
1000 fills (fps): 35918.4
100 fills per update (fps): 10807.4
10 fills per update (fps): 2400.5
1 fill per update (fps): 285.5

cell@flouride(master)$ ./rectbench.py 
1000 fills (fps): 34685.2
100 fills per update (fps): 11710.3
10 fills per update (fps): 2826.9
1 fill per update (fps): 294.2

HP ProBook 4530s, Linux:

cell@hp(master)$ ./rectbench.py 
1000 fills (fps): 24023.3
100 fills per update (fps): 26091.9
10 fills per update (fps): 11327.5
1 fill per update (fps): 2255.1

cell@hp(master)$ ./rectbench.py 
1000 fills (fps): 25701.3
100 fills per update (fps): 24788.9
10 fills per update (fps): 8994.3
1 fill per update (fps): 2392.3

cell@hp(master)$ ./rectbench.py 
1000 fills (fps): 27946.9
100 fills per update (fps): 25059.9
10 fills per update (fps): 10226.5
1 fill per update (fps): 2332.7
cell@hp(master)$ go run rectbench.go 
1000 fills (fps): 44600.8
100 fills per update (fps): 47399.3
10 fills per update (fps): 16091.7
1 fill per update (fps): 3480.6

cell@hp(master)$ go run rectbench.go 
1000 fills (fps): 41921.4
100 fills per update (fps): 47761.1
10 fills per update (fps): 15688.6
1 fill per update (fps): 3061.9

cell@hp(master)$ go run rectbench.go 
1000 fills (fps): 51489.0
100 fills per update (fps): 43015.8
10 fills per update (fps): 15517.8
1 fill per update (fps): 3354.9
package main
import (
"fmt"
"math/rand"
"os"
"time"
"github.com/veandco/go-sdl2/sdl"
)
func die(msg string, err error, code int) {
fmt.Fprintf(os.Stderr, "%s: %s\n", msg, err)
os.Exit(code)
}
func main() {
err := sdl.Init(sdl.INIT_EVERYTHING)
if err != nil {
die("Failed to initialize sdl", err, 1)
}
window, err := sdl.CreateWindow(
"Lesson 1",
sdl.WINDOWPOS_UNDEFINED,
sdl.WINDOWPOS_UNDEFINED,
512, 512,
sdl.WINDOW_SHOWN,
)
if err != nil {
die("Failed to create window", err, 2)
}
surface, err := window.GetSurface()
if err != nil {
die("Failed to get surface", err, 3)
}
// macOS won't display the window if events are never polled.
sdl.PollEvent()
// benchmark: 1000 random fills.
then := time.Now()
for i := 0; i < 1000; i++ {
rect := sdl.Rect{
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
}
color := sdl.MapRGB(
surface.Format,
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
)
surface.FillRect(&rect, color)
}
elapsed := time.Since(then)
fps := 1000 / elapsed.Seconds()
fmt.Printf("1000 fills (fps): %.01f\n", fps)
// benchmark: 100 fills per update.
then = time.Now()
for j := 0; j < 10; j++ {
for i := 0; i < 100; i++ {
rect := sdl.Rect{
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
}
color := sdl.MapRGB(
surface.Format,
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
)
surface.FillRect(&rect, color)
}
window.UpdateSurface()
}
elapsed = time.Since(then)
fps = 1000 / elapsed.Seconds()
fmt.Printf("100 fills per update (fps): %.01f\n", fps)
// benchmark: 10 fills per update.
then = time.Now()
for j := 0; j < 100; j++ {
for i := 0; i < 10; i++ {
rect := sdl.Rect{
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
}
color := sdl.MapRGB(
surface.Format,
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
)
surface.FillRect(&rect, color)
}
window.UpdateSurface()
}
elapsed = time.Since(then)
fps = 1000 / elapsed.Seconds()
fmt.Printf("10 fills per update (fps): %.01f\n", fps)
// benchmark: 1 fill per update.
then = time.Now()
for i := 0; i < 1000; i++ {
rect := sdl.Rect{
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
int32(rand.Intn(256)),
}
color := sdl.MapRGB(
surface.Format,
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
uint8(rand.Intn(256)),
)
surface.FillRect(&rect, color)
window.UpdateSurface()
}
elapsed = time.Since(then)
fps = 1000 / elapsed.Seconds()
fmt.Printf("1 fill per update (fps): %.01f\n", fps)
window.Destroy()
sdl.Quit()
}
#!/usr/bin/env python3
import sdl2
import sdl2.ext
from sdl2 import *
import time
import random
if __name__ == "__main__":
SDL_Init(SDL_INIT_EVERYTHING)
window = SDL_CreateWindow(
b"bench",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
512, 512,
SDL_WINDOW_SHOWN
)
surface = SDL_GetWindowSurface(window)
# macOS won't display the window until an event is polled.
SDL_PollEvent(None)
# benchmark: 1000 random fills.
then = time.time()
for _ in range(1000):
rect = SDL_Rect(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
color = SDL_Color(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
# this is goofy, I must be doing this wrong...
color_int = color.r << 16 | color.g << 8 | color.b
SDL_FillRect(surface, rect, color_int)
now = time.time()
elapsed = now - then
fps = 1000 / elapsed
print("1000 fills (fps): %.01f" % fps)
# benchmark: 100 fills per update.
then = time.time()
for _ in range(10):
for _ in range(100):
rect = SDL_Rect(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
color = SDL_Color(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
# this is goofy, I must be doing this wrong...
color_int = color.r << 16 | color.g << 8 | color.b
SDL_FillRect(surface, rect, color_int)
SDL_UpdateWindowSurface(window, surface)
now = time.time()
elapsed = now - then
fps = 1000 / elapsed
print("100 fills per update (fps): %.01f" % fps)
# benchmark: 10 fills per update.
then = time.time()
for _ in range(100):
for _ in range(10):
rect = SDL_Rect(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
color = SDL_Color(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
# this is goofy, I must be doing this wrong...
color_int = color.r << 16 | color.g << 8 | color.b
SDL_FillRect(surface, rect, color_int)
SDL_UpdateWindowSurface(window, surface)
now = time.time()
elapsed = now - then
fps = 1000 / elapsed
print("10 fills per update (fps): %.01f" % fps)
# benchmark: 1000 random fills.
then = time.time()
for _ in range(1000):
rect = SDL_Rect(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
color = SDL_Color(
random.randrange(0, 256),
random.randrange(0, 256),
random.randrange(0, 256),
)
# this is goofy, I must be doing this wrong...
color_int = color.r << 16 | color.g << 8 | color.b
SDL_FillRect(surface, rect, color_int)
SDL_UpdateWindowSurface(window, surface)
now = time.time()
elapsed = now - then
fps = 1000 / elapsed
print("1 fill per update (fps): %.01f" % fps)
SDL_Quit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.