Skip to content

Instantly share code, notes, and snippets.

@worldOneo
Created July 4, 2021 13:37
Show Gist options
  • Save worldOneo/f58d32a67873a7732b624ac235534972 to your computer and use it in GitHub Desktop.
Save worldOneo/f58d32a67873a7732b624ac235534972 to your computer and use it in GitHub Desktop.
Python performance test with C++ integration
import mymodule
import random
import time
"""
This is a test for the usecase of C++ integration in python programms.
For small function calls python doesn't gain as much from C++.
But if you keep your entire load in the C++ side, like NumPy, it is much faster.
"""
def random_string_generator(str_size, allowed_chars):
return ''.join(random.choice(allowed_chars) for x in range(str_size))
def random_int():
return random.randint(0, 500000)
def random_dict():
fields = [random_string_generator(20, "abcdefghijklmnopqrstuvwxyz") for _ in range(3_000_000)]
ret = {}
for field in fields:
ret[field] = str(random_int())
return ret, fields
def translate_with_py(d: dict, i):
for f in i:
if f not in d:
continue
d[f] = int(d[f])
def timeFunc(title, func):
_t1 = time.time()
res = func()
_t2 = time.time()
print(f"{title} took {round(_t2-_t1, 4)}s")
return res
if __name__ == "__main__":
print("\n=======\nFull C++\n=======")
t1 = time.time()
d, f = timeFunc("Generating challenge for C++ (in C++)", mymodule.generate_dict)
timeFunc("Translating dict in C++ ", lambda: mymodule.translate_dict(d, f))
t2 = time.time()
fcpp = t2-t1
print(f"Full C++ took {round(fcpp, 4)}s")
print("\n=======\nPartial C++ (Py Gen)\n=======")
t1 = time.time()
d, f = timeFunc("Generating challenge for C++ (in Py)", random_dict)
timeFunc("Translating dict in C++", lambda: mymodule.translate_dict(d, f))
t2 = time.time()
pcpppg = t2-t1
print(f"Partial C++ (PyGen) took {round(pcpppg, 4)}s")
print("\n=======\nPartial C++ (Py Calc)\n=======")
t1 = time.time()
d, f = timeFunc("Generating challenge for Py (in C++)", mymodule.generate_dict)
timeFunc("Translating dict in Py", lambda: translate_with_py(d, f))
t2 = time.time()
pcpppc = t2-t1
print(f"Partial C++ (PyCalc) took {round(pcpppc, 4)}s")
print("\n=======\nFull py\n=======")
print()
t1 = time.time()
d, f = timeFunc("Generating challenge for Py (in Py)", random_dict)
timeFunc("Translating dict in Py", lambda: translate_with_py(d, f))
t2 = time.time()
pytime = t2-t1
print(f"Python took {round(pytime, 4)}s\n")
print(f"Full C++ is {round(pytime/fcpp*100 - 100, 3)}% faster")
print(f"Partial C++ (PyGen) is {round(pytime/pcpppg*100 - 100, 3)}% faster")
print(f"Partial C++ (PyCalc) is {round(pytime/pcpppc*100 - 100, 3)}% faster")
#include <boost/python.hpp>
#include "boost/python/stl_iterator.hpp"
#include <string.h>
#include <vector>
#include <list>
#include <random>
#include <iostream>
using namespace boost;
std::string hello(int test)
{
return std::to_string(test);
}
void translate(python::dict from, python::list intFields)
{
python::stl_input_iterator<std::string> begin(intFields), end;
auto iter = std::list<std::string>(begin, end);
for (std::string field : iter)
{
if (!from.contains(field))
continue;
int n = atoi(python::extract<const char *>(from[field]));
from[field] = n;
}
}
int random_number()
{
return rand() % 500000;
}
std::string random_string(int n)
{
char letters[] = "abcdefghijklmnopqrstuvwxyz";
char *ran = (char *)malloc(n);
for (int i = 0; i < n; i++)
ran[i] = letters[rand() % n];
std::string str = std::string(ran);
free(ran);
return str;
}
python::tuple generate_dict()
{
python::dict res;
python::list fields;
for (int i = 0; i < 3000000; i++)
fields.append(random_string(20));
python::stl_input_iterator<std::string> begin(fields), end;
auto iter = std::list<std::string>(begin, end);
for (auto key : iter)
res[key] = std::to_string(random_number());
return python::make_tuple(res, fields);
}
BOOST_PYTHON_MODULE(mymodule)
{
python::def("hello", &hello);
python::def("translate_dict", &translate);
python::def("generate_dict", &generate_dict);
}
=======
Full C++
=======
Generating challenge for C++ (in C++) took 2.7518s
Translating dict in C++ took 2.1045s
Full C++ took 4.8564s
=======
Partial C++ (Py Gen)
=======
Generating challenge for C++ (in Py) took 24.9276s
Translating dict in C++ took 2.3882s
Partial C++ (PyGen) took 27.4289s
=======
Partial C++ (Py Calc)
=======
Generating challenge for Py (in C++) took 2.6688s
Translating dict in Py took 1.2791s
Partial C++ (PyCalc) took 4.1501s
=======
Full py
=======
Generating challenge for Py (in Py) took 24.4169s
Translating dict in Py took 0.968s
Python took 25.4773s
Full C++ is 424.609% faster
Partial C++ (PyGen) is -7.115% faster
Partial C++ (PyCalc) is 513.901% faster
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment