I just got myself LPIC-1 certified (verify). I’ll try to address a few issues here, if anybody else wants to do it and doesn’t know how.
The LPIC-1 is granted upon passing 2 exams:
Exam 101 – more theoretically oriented, with many general questions.
Exam 102 – more practically oriented, with an emphasis on Scripting, Networking and Security.
The exams can be passed in any order, the certification is automatically granted upon passing both. Also, in order to get certified on the subsequent levels, you need to already have the lower level certification at hand. That is, for one of the LPIC-3 certifications you need to pass a total of 5 exams, in any order.
The “official way” of taking exams is through a Pearson VUE test center. You need to first purchase an exam voucher (EUR 150 approx, might fluctuate with exchange rates) and then go take the exam on a computer in a controlled setup.
The “alternate way” is to attend a conference where pen/paper exams are offered. In Europe you may want to register your seat on this site, then attend that particular event. The cost for taking the exam in such setup is lower and may be the way to go if you plan to attend the conference for other reasons than taking the exams alone.
I have personally taken both 101 and 102 exams during the FOSDEM 2016 event in Bruxelles, Belgium, on January 30 and 31st.
1. The default initializer gotcha
Suppose you are in an interview setting and you are being handed a piece of paper with the following Python code written on it:
No explanations, no nothing, just the obvious question: what is wrong with the code above?
… nothing in particular. Yes, nothing is wrong with the code above, it is legal Python code (apart from missing the ending “:” and that no function body is given). Who am I to judge the particular use case – after all, a bug is defined as code that does not run the way the programmer expected it to.
But suppose we add more code to that function definition:
def foo(bar=): bar.append(1) return bar
Now things are getting messier. What would a “normal” Python programmer expect to be the result of calling foo() with no arguments for 3 times in a row?
foo() #  foo() #  foo() # 
Nope. The real result is more similar to:
foo() #  foo() # [1, 1] foo() # [1, 1, 1]
How is this even possible? The issue is with how default initializers for function arguments are handled in Python and this is completely different from C/C++. The scope of the default initializer is not the function body but rather the global scope (something similar to the static variables in C/C++). And static variables are good for caching and keeping state. But yes, I believe we had enough of this.
Before getting into action, let’s split the “performance” problem in a couple of boxes, as the concept itself is quite general. First, deciding what we want to monitor (an entire system? a particular application?) – and second, deciding on what type of performance monitoring do we require (stats collection by the kernel? in-depth analysis?). Based on this particular classification, we may end up with 4 categories, each with its particular software selection:
Tracing / Profiling / Debugging
netstat offers much more info beyond statistics on interface / protocol and may also be used to monitor individual connections.
dtrace and SystemTap can also trace individual applications.