1

Taking this documentation, I improperly wrote a function that calculates the power of a number in Rust, compiled it to a shared object and used it in Python. Then I have written the same algorithm with Python. I tested both and Python seems to be much faster.

sum.rs (it was supposed to sum, I changed my mind later)

#[no_mangle]
pub extern fn powerof(a: i32, b: i32) -> i32 {
    let mut c: i32 = a;
    for x in 0..b {
        c = c*a;
    }
    return c;
}

trial.py

from ctypes import cdll
import time

_powerof = cdll.LoadLibrary("./libsum.so")

def timing(f):
    # http://stackoverflow.com/a/5478448
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print('{} function took {:0.4f} ms'.format(f.__name__, (time2-time1)*1000.0))
        return ret
    return wrap

@timing
def powerof(a, b):
    global _powerof
    result = _powerof.powerof(a, b)
    return int(result)

@timing
def powerof_python(a, b):
    c = a
    for i in range(b):
        c=c*a
    return c


if __name__ == "__main__":
    print(powerof(4,5))
    print(powerof(2,3))
    print(powerof(6,4))

    print(powerof_python(4,5))
    print(powerof_python(2,3))
    print(powerof_python(6,4))

I have written and compiled Rust in the most primitive way (which means, without cargo).This is how I compiled Rust code above:

rustc sum.rs --crate-type dylib

The results are as below:

1st Test

powerof function took 0.0780 ms
4096
powerof function took 0.0136 ms
16
powerof function took 0.0064 ms
7776
powerof_python function took 0.0110 ms
4096
powerof_python function took 0.0041 ms
16
powerof_python function took 0.0050 ms
7776

2nd Test

powerof function took 0.0820 ms
4096
powerof function took 0.0083 ms
16
powerof function took 0.0057 ms
7776
powerof_python function took 0.0110 ms
4096
powerof_python function took 0.0041 ms
16
powerof_python function took 0.0041 ms
7776

3rd Test

powerof function took 0.0772 ms
4096
powerof function took 0.0098 ms
16
powerof function took 0.0069 ms
7776
powerof_python function took 0.0129 ms
4096
powerof_python function took 0.0036 ms
16
powerof_python function took 0.0043 ms
7776

It seems that the same method runs much faster in Python. Why is that?


Update: Timing within Rust

I edited content of sum.rs as below (added main function):

#[no_mangle]
pub extern fn powerof(a: i32, b: i32) -> i32 {
    let mut c: i32 = a;
    for x in 0..b {
        c = c*a;
    }
    return c;
}

fn main() {
    let a = powerof(4,5);
    let b = powerof(2,3);
    let c = powerof(6,4);

    println!("{}",a);
    println!("{}",b);
    println!("{}",c);
}

Compiled it with:

rustc sum.rs

Then run it with time in Linux, as below (after chmod +x ./sum):

time -v ./sum

Test 1

real    0m2.035s
user    0m0.140s
sys     0m0.072s

Test 2

real    0m0.176s
user    0m0.128s
sys     0m0.040s

Test 3

real    0m0.184s
user    0m0.136s
sys     0m0.044s

With rustc -O option

Compiled as below and given executable permission:

rustc -O sum.rs

Test 1

real    0m0.169s
user    0m0.132s
sys     0m0.032s

Test 2

real    0m0.207s
user    0m0.148s
sys     0m0.048s

Test 3

real    0m0.170s
user    0m0.124s
sys     0m0.040s

Environment

  • Python 3.5.2
  • Rust 1.7.0
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Eray Erdin
  • 2,633
  • 1
  • 32
  • 66
  • 4
    My guess is that some of the overhead is caused by Python having to convert values to and from `ctypes` compatible types, and [this](https://docs.scipy.org/doc/numpy-dev/user/c-info.python-as-glue.html#index-3) seems to agree with that. Might be worth comparing a function in Rust that just returns the input with the Python equivalent to see if that may be the case. – Aurora0001 Nov 18 '16 at 19:42
  • 1
    Thanks for answer... :) | As I understood correctly, I should return a Python compatible data (probably with cpython) in Rust. Unfortunately, I do not know how to use cpython, so it might take some time to learn, test and finally update this question. – Eray Erdin Nov 18 '16 at 19:53
  • 1
    Well, I'm not certain, which is why I suggest you test to see if my guess is correct. There probably isn't a lot you can do to avoid the overhead with the `ctypes` module - there will naturally be *some* cost when you convert from one type to another, though I am surprised it's about 0.05s in some cases. – Aurora0001 Nov 18 '16 at 19:55
  • 1
    Thanks again. :) I will go and read some documentations right away. – Eray Erdin Nov 18 '16 at 19:56
  • Why are you `chmod +x`? The produced binary is already executable. – Shepmaster Nov 18 '16 at 21:36
  • Just habits... There were a friend here, and suddenly vanished. Where is he? (Deleted his comments.) – Eray Erdin Nov 18 '16 at 21:38
  • 1
    Yep, comments aren't for long discussion. After you updated the question, I deleted them because they were just noise. Just like I'll delete these after a while. – Shepmaster Nov 18 '16 at 21:39
  • Are you on a very slow computer, or one that is otherwise resource-limited? Running the pure Rust code for me takes 12ms, not >150ms like your results. – Shepmaster Nov 18 '16 at 21:55
  • Note that you have linked to the documentation for Rust **1.2.0** and that the current version is **1.13.0**. Performance improvements and improved APIS happen all the time, so it's worth keeping up-to-date. – Shepmaster Nov 18 '16 at 21:56
  • Yeah, I am on a slow computer. | Yeah, updates might be the issue, too. It was just curiosity came this far. – Eray Erdin Nov 18 '16 at 21:56

0 Answers0