afoley587 / pointless-performance

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Overview

Boy, oh boy, we have a fun one today. It's my first time benchmarking languages against eachother. I was inspired to do this because, recently, I had to make a choice of using python or golang for a backend API. Obviously, performance was one of the main factors we were judging in our designs.

In all, I want to see how long some simple operation takes across a few languages.

The Languages And The Tests

Today, we will be comparing a few languages:

Please note that all of these languages have vastly different pros and cons. Obviously, some languages handle different scenarios more elegantly than others! So, with that being said, take this silly performance test with a grain of salt!

What are the tests today? Oh, it's a very simple one. Each language is going to just count to 1,000,000,000 and do nothing else. To keep the tests comparable across the languages, we will not print anything to STDOUT and we will try to avoid any optimizations in the code itself. In pseudocode, all we are going to do is the below:

while counter < some_max_counter; do
    counter++
done

We will run the tests 10 times and then chart the averages of each language against eachother.

I don't want to bore the reader by going through extremely simple code in 4 languages, but let's just take the C++ one as an example:

int main(int argc, char* argv[])
{
    int counter = 0;
    int max_counter = 1000000000;

    while (counter < max_counter) {
        counter++;
    }
    return 0;
}

We can see we are literally just counting up to a billion and doing nothing else. Each language will do the exaclty the same thing so we can try to get the most control over our scenarios.

Running Them

Let's build a simple helper script that will run all of the languages for us. We will first need a function to run the commands and time.

time_language() {
    iters=5
    lang="$1"
    file="$2"
    cmd=""
    
    case $lang in 

        cpp)
            cmd="$file"
            ;;
        golang)
            cmd="$file"
            ;;
        python)
            cmd="python $file"
            ;;
        rust)
            cmd="$file"
            ;;
        *)
            cmd=""
            ;;    
    esac

    echo $lang >> $RESULTS_FILE

    i=1
    sp="/-\|"
    echo -n ' '
    for i in $(seq 1 $iters); do 
        printf "\b${sp:i++%${#sp}:1}"
        /usr/bin/time -o $RESULTS_FILE -a $cmd
    done
}

It's pretty simple, but we're just going run the unix time command and send it over to a file using both the -o and -a flags. To get somewhat of an average, we will run it 5 times each. Then we just need to actually compile the code (if needed) and run the binaries:

printf "${CYAN}Running CPP Tests${NC}\n"
cd $_PWD/cpp
g++ -o counter *.cpp
time_language "cpp" "./counter"
cd $_PWD

printf "\n${CYAN}Running GoLang Tests${NC}\n"
cd $_PWD/golang
go build
time_language "golang" "./pointless-performance-tests"
cd $_PWD

printf "\n${CYAN}Running Python Tests${NC}\n"
cd $_PWD/python
time_language "python" "./main.py"
cd $_PWD

printf "\n${CYAN}Running Rust Tests${NC}\n"
cd $_PWD/rust
cargo build
time_language "rust" "./target/debug/counting"
cd $_PWD

And that's all there is to it. We will compile/build C++, then golang, then python, then rust. Our resulting file (on my computer) looks something like this:

cpp
        0.73 real         0.63 user         0.00 sys
        0.63 real         0.62 user         0.00 sys
        0.63 real         0.62 user         0.00 sys
        0.63 real         0.62 user         0.00 sys
        0.62 real         0.62 user         0.00 sys
golang
        0.36 real         0.31 user         0.00 sys
        0.31 real         0.31 user         0.00 sys
        0.31 real         0.31 user         0.00 sys
        0.31 real         0.31 user         0.00 sys
        0.31 real         0.31 user         0.00 sys
python
       48.28 real        47.94 user         0.15 sys
       46.79 real        46.53 user         0.07 sys
       58.53 real        58.27 user         0.09 sys
       54.66 real        54.34 user         0.14 sys
       47.64 real        47.38 user         0.07 sys
rust
        1.08 real         0.95 user         0.00 sys
        0.94 real         0.93 user         0.00 sys
        0.94 real         0.93 user         0.00 sys
        0.95 real         0.94 user         0.00 sys
        0.94 real         0.93 user         0.00 sys

The Results

I was pretty blown away by the results. Now, I want to be clear that I did not do any resource profiling and I was strictly looking at the real time to see how long each iteration took. I was extremely surprised by the time in which it took python to count all the way up to a billion, while the other languages took less than a second in most cases.

Thanks for following along! The full source code can be found

About


Languages

Language:Shell 71.0%Language:C++ 9.7%Language:Rust 7.9%Language:Go 6.7%Language:Python 4.8%