Free Software

Software Engineering with FOSS and Linux

Free Software in Education

The notion of Free Software is definitely political. I’m not stating the obvious, that any human work that affects a community in any way is political. Neither I suggest that the ideological (as opposed to purely technical) reasons of many Free Software supporters (and its critics) automatically brand it as a political issue. They alone might as well characterize it as philosophical, artistic or simply iconic. Free Software is political because it is strongly tied with a deep political question: that of education, and access to it.

Every modern society claims to strive for the welfare of its members. All political parties implicitly project this as their primary goal; one’s idea of ‘welfare’, ‘member’ and the means to accomplish this goal differs, but a handful of ideas is common in the rhetoric of all bands of the political spectrum. Predominate among them is that primary and secondary education (at the very least) should be freely available to all.

The thought of education as a few hours in the classroom with a teacher lecturing to a group of students is awfully obsolete. Education is a continuous, blended, all-encompassing process. Access to and manipulation of information is a crucial part of the learning process. It is the obligation of every modern society to guarantee and safeguard the access of its members to information; this is a direct result of its obligation to guarantee access to education. A large portion of the information we draw upon to learn from is nowadays digital; in the future the vast majority may very well be so. Software is the means of accessing and manipulating that information, an increasingly large portion of which is generated outside the classroom walls or even the entire state-sanctioned education system. Imposing barriers to its use not only misses the point of education, it strangles it.

One might grudgingly argue that this issue can be addressed by adhering to open standards and open formats; surely that would be enough to ensure universal access to information without having to go all the way to Free Software, right? Wrong! Obviously open standards and open formats are a necessary prerequisite, but they are not enough. Alone, they are analogous to claiming that filling a library with books written in your native language, so that everybody can read them, and then charging a hefty entrance fee, promotes access of children to knowledge. So free of charge tools to access and manipulate information is also necessary. But why Free, as in freedom of thought? Why Free Software and not just free of charge open source? Or even free of charge proprietary software?

You can read two great articles that support this: Richard Stallman’s Why schools should exclusively use free software and Jean Peyratout’s Why give precedence to Free Software at Schools. To summarize them, Free Softwares helps students assimilate and generate knowledge, instead of simply acquire technical skills; it offers education, instead of training. It helps build communities, and promotes (actually depends on) discussion, cooperation, initiative and active participation to the development process. In an increasingly expanding digital world, it embodies the ideals of education.

Advertisements

May 22, 2009 Posted by | Free Software | , , | 29 Comments

Debugging and profiling your C/C++ programs using Free Software

Every developer in Linux knows (and most likely uses) the GCC, a set of compilers, tools and libraries that form the foundation of pretty much all C and C++ development in the FOSS world. However, fewer people, even among professional software developers, are aware of the superb debugging and profiling options available to them.

Before introducing new tools, I will first talk about a few gcc options. Note that several GCC options change with each release. I am using 4.3.3; if something doesn’t work for you, check the documentation for your version.

Let’s begin with a few compiling options that will help you detect errors at compile time. This means less debugging will be needed in the future, which is always a Good Thing.

-Wall

Enable most warnings. According to GCC’s man page,

“This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros.”

Note that as of version 4.3.3, two of the most powerful features enabled by -Wall, warnings about uninitialized variables use and out of bounds array checking will only work if you specify an optimization level (-O1 for uninitialized variables, -O2 for array bounds checking). This is planned to change in future GCC versions.

It is generally suggested that all your programs are compiled with the -Wall option enabled. My suggestion is to also compile your program with -O2 to let GCC test for uninitialized variables and out of bounds array use; turn it off afterwards if you wish to have full access to debuging info.

-Wshadow

Warn about shadow variables. Shadow variables (i.e. variables declared inside an inner block with the same name as a variable already existing in the scope) are valid in C/C++, but they are quite error prone. You should avoid using them; this compiler option will help you track unintended use.

-Werror

Treat warnings as errors. This will make the compiler treat all warnings as errors, interrupting compilation. Specific warnings can be exempted from this flag. A common example is using the -Wno-invalid-offsetof flag to supress warnings about using the offsetof() marco to reference member variables of uninitialized objects.

The following flags are related to debugging and profiling:

-g

Generate debugging info in the operating system’s native format. You can use the GNU debugger (gdb) to debug programs compiled with the -g option. Note that even though you can generate debugging info for programs compiled with an optimization (-On) option, debugging data will be less informative.

You should always use the -g option when developing your programs; you can turn this off in your final product.

-pg

Generate profiling info. When running a program compiled with this option, a file named gmon.out will be generated, containing profile information; you can use the GNU profiler (gprof) to analyse this file. Note that the -pg option must be specified both in compiling and in linking options. Personally I never use -pg; I prefer the profiling tool of valgrind, which I will mention later in the article.

As I mentioned, you can use the GNU debugger (gdb) to debug a program compiled with the -g option. An extended description of gdb is beyond the scope of this post; you can check one of the numerous tutorials available on the Internet. However, a few points of interest:

  • You can debug a running process of an executable. Use ps to find the process id (pid) of an executable, run gdb <executable> to begin gdb, and use the attach <pid> command to attach gdb to the running process.
  • You can debug an executable based on a core dump. Simply run gdb <executable> <core>. Note that nowadays programs will not generate a core when they crash, unless the ulimit -c option has been specified in the shell. This is done for security reasons, as an unintented core file can be used to hack into a program. Do not forget to enable this option when developing.

There are several graphical front-ends to gdb available. I prefer to work from the command line, since most of the time I’m debugging remote programs using a terminal window. However I have found kdbg to be an excellent front-end. Here is a screenshot:kdbg - A graphical front-end to gdb

Other available options include ddd, xxgdb and nemiver. Most C/C++ IDEs, such as Eclipse, Netbeans,  KDevelop and Anjuta also contain integrated front-ends to gdb. However getting familiar with the core gdb functionality outside an IDE is probably a good idea.

Valgrind, which I already mentioned earlier, is an invaluable set of tools to anyone dealing with non-trivial debugging and profiling. The platform currently contains the following tools:

  • A memory error detector
  • Two thread error detectors, including race conditions
  • Three profilers: cache and branch-prediction profiler, call-graph generating cache profiler, and heap profiler

Extended documentation on the various tools is provided on http://valgrind.org. Here I will display examples of my favotire tools: the memory error detector, and the call-graph generating cache profiler.

Consider the following trivial and utterly useless program:

#include <string.h>
#include <stdio.h>

void myfunc( const char *arg )
{
    char *p, *ptr;
    ptr = strdup( arg );
    /* process ptr here, but forget to free memory */
}

int main( int argc, char *argv[] )
{
    myfunc( "hello world" );
    return 0;
}
Checking this program with valgrind will reveal the memory leak:
xenofon@umbra:~/tmp$ valgrind --track-origins=yes --leak-check=full ./a.out |tee valgrind.out
[...]
==21882== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==21882==    at 0x4026FDE: malloc (vg_replace_malloc.c:207)
==21882==    by 0x40BB34F: strdup (in /lib/tls/i686/cmov/libc-2.9.so)
==21882==    by 0x80483D4: myfunc (in /home/xenofon/tmp/a.out)
==21882==    by 0x80483F6: main (in /home/xenofon/tmp/a.out)
[...]

In non-trivial examples this alone can be a big saver. But the memory check of valgrind is MUCH more than this. Consider the following example:

#include <iostream>
#include <string>
using namespace std;

class Person {
private:
    string name;
    int age, sex;
public:
    enum { MALE, FEMALE };
    Person( string name, int age, int sex )
    {
        this->name = name;
        this->age = age;
        //this->sex = sex; /* we forgot this! */
    }
    void Print( )
    {
        cout << "Name: " << name << endl;
        cout << "Age : " << age << endl;
        cout << "Sex : " << ( sex == MALE ? "Male" : "Female" ) << endl;
    }
};

int main( int argc, char *argv[] )
{
    Person p( "alphamale", 32, Person::MALE );
    p.Print();
    return 0;
}

Valgrind will catch the error:

[...]
Name: alphamale
Age : 32
==22871== Conditional jump or move depends on uninitialised value(s)
==22871==    at 0x8048BCC: Person::Print() (in /home/xenofon/tmp/a.out)
==22871==    by 0x8048A5B: main (in /home/xenofon/tmp/a.out)
==22871==  Uninitialised value was created by a stack allocation
==22871==    at 0x80489D0: main (in /home/xenofon/tmp/a.out)
Sex : Female
[...]

Even though this example is also trivial, using uninitialized variables is an extremely common mistake. The -Wuninitialized compiler option of gcc (which is automatically included if you specify the -Wall flag) will help in some cases, but not all. It will not detect the above case, and it certainly cannot detect any case that can only occur at run-time. Valgrind checks all the allocated memory at bit level, and issues a warning when you attempt to use uninitialized areas.

Valgrind can also be used for profiling. I commonly use the call-graph cache profiler to generate profile data which can be analyzed by specialized tools. First, ask valgrind to use the appropriate tool:

xenofon@umbra:~/program/arctic/server$ valgrind --tool=callgrind ./server 2702

Once the program terminates, a file named callgrind.out.<pid> is generated. This file contains the profiling info of your program. If your program forks, a seperate callgrind.out file is generated for every child, distinguished by the pid extension. You can then use the amazing kcachegrind tool to inspect the info:

kcachegrind

Kcachegrind lets you inspect CPU time spent in each function and all its subroutines, navigate through the call graph, check a list of callers and callees, and is generally an invaluable tool to detect bottlenecks in the performance of your program. Furthermore, it is extremely user-friendly. Give it a try, you will love it.

Obviously there are several more tools to help you debug and profile your C/C++ programs. Furthermore, debugging and profiling, just like all programming, is more about the process than the tools. However, once you learn to make them part of your programming activities, you will happily find out that there are several superb free software tools to support your endeavours.

May 18, 2009 Posted by | Programming | , , , , , , , , | 12 Comments