Shaving some time
I was talking to a colleague the other day and got into a discussion regarding some ways of coding c++, such as whether to use division or bit shifting — almost all modern compilers can optimize this so it’s basically just a matter of what looks best. At the same time, we got into a minor discussion regarding references and pointers in c++. I made a small test and found some rather amusing results, which is quite obvious once you think about it, but still very scary considering how common it is to use the pointer construct:
// Compile using g++ -lrt -o lala lala.cpp #include <iostream> #include <time.h> int* lala_ptr() { int *y = new int; *y = 5; return y; } int& lala_ref() { int x =5; int &y = x; return y; } timespec diff(timespec start, timespec end) { timespec temp; if ((end.tv_nsec-start.tv_nsec)<0) { temp.tv_sec = end.tv_sec-start.tv_sec-1; temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; } else { temp.tv_sec = end.tv_sec-start.tv_sec; temp.tv_nsec = end.tv_nsec-start.tv_nsec; } return temp; } int main(int argc, char **argv) { timespec time1, time2, time3; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1); for (unsigned int i=0;i<(unsigned int)-1;i++) { int &z = lala_ref(); } clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2); for (unsigned int i=0;i<(unsigned int)-1;i++) { int *z = lala_ptr(); delete z; } clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time3); std::cout << "Reference diff(" << time1.tv_sec << ":" << time1.tv_nsec << ", " << time2.tv_sec << ":" << time2.tv_nsec << ") = " << diff(time1, time2).tv_sec << ":" << diff(time1, time2).tv_nsec << std::endl; std::cout << "Pointer diff(" << time2.tv_sec << ":" << time2.tv_nsec << ", " << time3.tv_sec << ":" << time3.tv_nsec << ") = " << diff(time2, time3).tv_sec << ":" << diff(time2, time3).tv_nsec << std::endl; }
Below is a sample of the output generated by the test code above:
oan@laptop4:~/Projects/test$ ./testRefVsPointer Reference diff(0:3869272, 25:234466470) = 25:230597198 Pointer diff(25:234466470, 299:547382527) = 274:312916057
So, the question for you all, can you figure out what's wrong? 😉
Screenmovie 1.1 released
Filed under: Development, Frozentux.net, Linux, Ubuntu, Video
A quick note that Screenmovie 1.1 has been released. It’s still very crude, but adds some sound recording and the ability to turn it on/off. Postprocessing is not supported yet but should be there in the next version.
Features:
- Record video
- Record sound
- Configure file format
- Configure video codec + settings (5-6 codecs chosen for now)
- Configure audio codec + settings (2 codecs for now)
I still have some problems, but I just found some info on how to possibly make some problems better at least.
Todo:
- Fix some high cpu usage problems
- Add global keybindings
- Postprocessing encoding
- Clean up and add some values specific for codecs (as required).
Unit testing and stubbing singletons
I got a bit curious about stubbing Singletons for testing during the weekend as well. We often find ourselves needing to test large codebases at work, and in the current project I’m in, we do complete end to end signal flow tests, but people are finally realizing that this will simply not do. For this reason, we’re doing a lot of work to try to split the entire project up into manageable chunks. One of the main problems has been the incessant use of singletons. A simply half-way-there to doing full out interfaces is to simply make all public function calls virtual and then create a stub class of the singleton saving the message or whatever passed on, into a variable which can be grabbed and tested from the actual unit test.
A sample of the general idea below:
#includeclass A { public: static A *instance() { std::cout << "A::instance()" << std::endl; if (!s_instance) s_instance = new A; return s_instance; }; A() { std::cout << "A::A()" << std::endl; }; // Virtual makes the difference virtual void send(int i) { std::cout << "A::send()" << std::endl; // Blah blah, send i or something }; static A *s_instance; private: }; class stub_A: public A { public: static stub_A *instance() { std::cout << "stub_A::instance()" << std::endl; if (!s_instance) { s_instance = new stub_A; A::s_instance = s_instance; } return s_instance; }; stub_A() { std::cout << "stub_A::stub_A()" << std::endl; }; void send(int i) { std::cout << "stub_A::send()" << std::endl; y = i; }; int getMessage() { return y; }; private: int y; static stub_A *s_instance; }; A *A::s_instance = 0; stub_A *stub_A::s_instance = 0; int main(int argc, char **argv) { stub_A::instance()->send(5); std::cout << "stub_A::instance()->getMessage() == " << stub_A::instance()->getMessage() << std::endl; A::instance()->send(7); std::cout << "stub_A::instance()->getMessage() == " << stub_A::instance()->getMessage() << std::endl; }
Python multiprocessing
Sometimes I find a good time by writing small but easy to understand test programs to research specific behaviours in some language or another. Sometimes, the programs grows a bit wieldy and not so easy to understand, but all’s good that ends well. During the last year or so, I’ve grown more and more interested in python programming and finding it very enjoyable. There are some strange constructs that can be hard to wrap your head around, and sometimes I run into some very weird problems, but it’s not a big problem (imho).
My last forays has been into multiprocessing and how it behaves in Python. One of the features I had a hard time to wrap my head around since there are some syntactical weirdness that could use some addressing, or at least takes a bit of time to get your head around.
- Multiprocessing requires all objects to be pickled and sent over to the running process by a pipe. This requires all objects to be picklable, including the instance methods etc.
- Default implementation of pickling functions in python can’t handle instance methods, and hence some modifications needs to be done.
- Correct parameters must be passed to callbacks and functions, via the apply_async. Failing to do so causes very strange errors to be reported.
- Correct behaviour might be hard to predict since values are calculated at different times. This is especially true if your code has side effects.
The small but rather interesting testcode below explores and shows some of the interesting aspects mentioned above. Of special interest imho is the timing differences, it clearly shows what you get yourself into when doing multiprocessing.
#!/usr/bin/python import multiprocessing def _pickle_method(method): func_name = method.im_func.__name__ obj = method.im_self cls = method.im_class return _unpickle_method, (func_name, obj, cls) def _unpickle_method(func_name, obj, cls): for cls in cls.mro(): try: func = cls.__dict__[func_name] except KeyError: pass else: break return func.__get__(obj, cls) import copy_reg import types copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method) class A: def __init__(self): print "A::__init__()" self.weird = "weird" class B(object): def doAsync(self, lala): print "B::doAsync()" return lala**lala def callBack(self, result): print "B::callBack()" self.a.weird="wherio" print result def __init__(self, myA): print "B::__init__()" self.a = myA def callback(result): print "callback result: " + str(result) def func(x): print "func" return x**x if __name__ == '__main__': pool = multiprocessing.Pool(2) a = A() b = B(a) print a.weird print "Starting" result1 = pool.apply_async(func, [4], callback=callback) result2 = pool.apply_async(b.doAsync, [8], callback=b.callBack) print a.weird print "result1: " + str(result1.get()) print "result2: " + str(result2.get()) print a.weird print "End"
The above code resulted in the following two runs, and if you look closely, the timing problems show up rather clearly. Things simply don’t happen in the order always expected when threading applications:
oan@laptop4:~$ ./multiprocessingtest.py A::__init__() B::__init__() weird Starting weird func B::doAsync() callback result: 256 B::callBack() 16777216result1: 256 result2: 16777216 wherio End oan@laptop4:~$ ./multiprocessingtest.py A::__init__() B::__init__() weird Starting weird func B::doAsync() callback result: 256 B::callBack() 16777216 result1: 256 result2: 16777216 wherio End
One more warning is in order. A job that leaves via the multiprocessing.Pool, and then calls the callback function has a major effect that could take some getting used to. The callback is run in such a fashion that if a class was changed, the change has not taken place in the context of the callback.