Category Archives: C/C++

Adding Custom CSS Properties Using gtkmm

Adding custom CSS properties in gtkmm is actually pretty simple once you know how.  It took me quite a bit of searching along with some trial and error before I came up with a pretty simple pattern for doing so.  What I was looking for was a way to use custom CSS without having to develop a whole bunch of custom classes which extended Gtk base classes.

First thing we need to do is to create a class that extends from Gtk::Widget.  Now, we don’t necessarily have to use the class directly as a visual object however, it does need to extend the Gtk::Widget class for it to work.  The following is my example for creating simple custom CSS properties.  Let’s start off by adding a single custom property called “width”.

 

class CustomCSS : public Gtk::Widget {
 
    public:
        Gtk::StyleProperty<int> width_property;
        int width;
 
        CustomCss() :
            Glib::ObjectBase("customcss"),
            Gtk::Widget(),
 
            //-gtkmm__CustomObject_customcss-width
            width_property(*this, "width", 100),
            width(100)
            {}
};

Let’s examine the above code to find out what’s really going on here.

 

class CustomCSS : public Gtk::Widget

First we need to create a class the extends the Gtk::Widget class.

 

public:
    Gtk::StyleProperty<int> width_property;
    int width;

Next, we need to add a public style property that defines what will be reading the width values and a simple property of the type we’ll want to use, in this case an int.

 

CustomCss() :
    Glib::ObjectBase("customcss"),
    Gtk::Widget(),
 
    //-gtkmm__CustomObject_customcss-width
    width_property(*this, "width", 100),
    width(100)
    {}

Finally, we’ll want to implement a default constructor where we set the name we will be using in our CSS to reference this class “customcss”, pass in the Gtk::Widget() constructor, then we’ll need to being initializing our custom properties to be used in CSS.  For this, we initialize the width_property, give it a CSS property name of “width” and set the default value to 100.  Then we do the same for the actual property by calling width(100).

Now, if we want to use the custom CSS class and properties we’ll need to add them to our CSS file.  I noted above also that in our CSS file, the “width” property would actually need to be specified as “-gtkmm__CustomObject_customcss-width”.  The first part “-gtkmm__CustomObject_” will be the default used by gtkmm when accessing the custom property, the last two parts “customcss” and “width” we control by setting the Glib::ObjectBase(“customcss”) and the width_property(*this, “width”, 100) respectively.

 

/* somefile.css */
 
* {
    -gtkmm__CsutomObject_customcss-width: 500;
}

To enable this custom property to be used, we first need to define an all selector “*” followed by our CSS implementation which contains “-gtkmm__CsutomObject_customcss-width: 500;”.  Now, let’s use it in our C++ application.

 

#include <gtkmm.h>
 
int main(int argc, char ** argv){
 
    //your code doing something useful
 
    //setup our css context and provider
    Glib::ustring cssFile = "/path/to/somefile.css";
    Glib::RefPtr<Gtk::CssProvider> css_provider = Gtk::CssProvider::create();
    Glib::RefPtr<Gtk::StyleContext> style_context = Gtk::StyleContext::create();
 
    //load our css file, wherever that may be hiding
    if(css_provider->load_from_path(HOME_DIRECTORY + "/.config/xfce4/finder/xfce4-finder.css")){
        Glib::RefPtr<Gdk::Screen> screen = window->get_screen();
        style_context->add_provider_for_screen(screen, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
    }
 
    //instantiate our custom css class
    CustomCss css;
 
    //get the width
    int width = css.width_property.get_value();
 
    //do something useful with the width we retrieved from css
 
    //run application run
    application->run(main_window);
 
    return EXIT_SUCCESS;
}

As you can see from the above, we’ve created both a CssProvider and a StyleContext, then we load our CSS file by using load_from_path, set our screen to be the main application window’s screen, then finally we add a provider by calling add_provider_for_screen.  Once that’s all done we can use our CustomCSS class.  Simply instantiate it, and call get_value() of the property we want to use.  It’s that simple.  If we wanted to add more than one property, we just added them to the constructor’s inline calls like so.

 

class CustomCSS : public Gtk::Widget {
    public:
 
    Gtk::StyleProperty<int> width_property;
    int width;
 
    Gtk::StyleProperty<int> height_property;
    int height;
 
    //etc...
 
    CustomCss() :
        Glib::ObjectBase("customcss"),
        Gtk::Widget(),
 
        //-gtkmm__CustomObject_customcss-width
        width_property(*this, "width", 100),
        width(100),
 
        //-gtkmm__CustomObject_customcss-height
        height_property(*this, "height", 50),
        height(50)
 
        //etc...
        {}
};

 

Once again, we add the new properties if we want to our CSS file.

/* somefile.css */
 
* {
    -gtkmm__CsutomObject_customcss-width: 500;
    -gtkmm__CsutomObject_customcss-height: 100;
    /* etc... */
}

 

Then we access them the same way as before in our C++ code.

//instantiate our custom css class
CustomCss css;
 
//get the width
int width = css.width_property.get_value();
 
//get the height
int height = css.height_property.get_value();
 
//get etc...

 

I hope this helps.  I found this a simple and clean way of introducing custom CSS properties without having to create a bunch of Gtk::Widget classes.  As always, thanks for stopping by and let me know if there’s anything I can do to help.

 

 

Quick Start Embedding Lua In C++

Lua is a pretty straight forward simple scripting language that can be implemented in a number of languages.  Today I’m going to show you how easy it is to embed Lua in C++.  First thing you’re going to need to do is create a sane build environment by installing the Lua programming language and development packages.  Depending on the OS and version you are using this can vary, for simplicity sake I’m going to assume your using linux with RPM support and I’ll be using the 5.1 version of Lua.

First let’s download and install the Lua packages:
(Please note these are the 64-bit library versions, you may need a different version depending on your distro and architecture)

user@computer:$ cd /usr/src
user@computer:$ wget http://dl.fedoraproject.org/pub/epel/5/x86_64/lua-5.1.4-4.el5.x86_64.rpm wget http://dl.fedoraproject.org/pub/epel/5/x86_64/lua-devel-5.1.4-4.el5.x86_64.rpm
user@computer:$ rpm -i lua-5.1.4-4.el5.x86_64.rpm lua-devel-5.1.4-4.el5.x86_64.rpm

 

Next let’s create a host application to execute our Lua code:

user@computer:$ mkdir lua-host
user@computer:$ cd lua-host

 

Create a lua-host.cpp file and add the following contents:

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}
 
#include "stdio.h"
 
int main(int argc, char ** argv){
 
    //iterate all files and execute
    for(int n=1; n<argc; n++){
        const char * file = argv[n];
 
        //create a new lua state
        lua_State * L = luaL_newstate();
 
        //open all libraries
        luaL_openlibs(L);
 
        int s = luaL_loadfile(L, file);
 
        if(!s)
            s = lua_pcall(L, 0, LUA_MULTRET, 0);
 
        //show any errors
        if(s){
            printf("Error: %s \n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
 
        lua_close(L);
    }
 
    return 0;
}

Now let’s examine the above C++ code.  The first thing we do is iterate over the passed in arguments in this case expected to be file names (ie. ./lua-host test.lua). For each passed in file we create a new state or context for the execution of the Lua script files.  Next we make a call to openlibs which allows access to all the standard Lua libraries from the passed in files.  Next, we check the return value of the loadfile call to ensure everything is still a go, then we invoke pcall which executes the chunk of code contained within the file.  Lastly, we check for any errors that might have occurred and display them, then close that instance of the Lua state.  Wash, rinse, repeat for all the files passed in along the command line.

Now, let’s go ahead and compile the lua-host application.

user@computer:$ g++ lua-host.cpp -o lua-host -llua

 

Hopefully if all when well and you are sans typos, you should now have a shiny new lua-host executable at your disposal. So next, let’s test it.

Start by creating a simple “Hello World” script in Lua, create a new file called “hello_world.lua” and put the following in it:

print("Lua says: Hello World")

 

Next, let’s execute the “hello_world.lua” file against our new host application:

user@computer:$ ./lua-host hello_world.lua

 

You should receive the following:

user@computer:$ ./lua-host hello_world.lua
Lua says: Hello World

Booyah! Well that was easy. Now how about adding a custom function in C++ that can be make callable from Lua. This is actually very simple as well.

Let’s modify our “lua-host.cpp” file and add a custom method called “hello”:

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}
 
#include "stdio.h"
 
//new custom hello method
int hello(lua_State * L){
    printf("C++ says: Hello World\n");
 
    return 1;
}
 
int main(int argc, char ** argv){
 
    //iterate all files and execute
    for(int n=1; n<argc; n++){
        const char * file = argv[n];
 
        //create a new lua state
        lua_State * L = luaL_newstate();
 
        //open all libraries
        luaL_openlibs(L);
 
        //register new custom method
        lua_register(L, "hello", hello);
 
        int s = luaL_loadfile(L, file);
 
        if(!s)
            s = lua_pcall(L, 0, LUA_MULTRET, 0);
 
        //show any errors
        if(s){
            printf("Error: %s \n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
 
        lua_close(L);
    }
 
    return 0;
}

So what did we just do? We defined a new “hello” method and had it’s implementation just do a printf of “C++ says: Hello World”, then in the body of the main method we added a call to lua_register(L, “hello”, hello), which as you might have guessed registers the “hello” method as “hello” in Lua. This simply maps the hello() Lua call to the C++ hello method.

Now let’s compile it:

user@computer:$ g++ lua-host.cpp -o lua-host -llua

Hopefully once again no typos. Next, let’s update the “hello_world.lua” and add a call to the new C++ “hello” method.

Edit the “hello_world.lua” file and ensure it has the following:

print("Lua says: Hello World")
hello()

Now that we have the new “hello” method call added to our Lua script, let’s execute it in our host application:

user@computer:$ ./lua-host hello_world.lua
Lua says: Hello World
C++ says: Hello World

Booyah part 2! Now we’ve successfully added a custom method to our Lua host application. I think the last thing we should do is make the custom method a bit more intelligent. Let’s add parameters to the function and a return value.

Once again edit the “lua-host.cpp” file and modify to the following:

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}
 
#include "stdio.h"
 
//new custom hello method
int hello(lua_State * L){
    printf("C++ says: Hello World\n");
 
    //get the count of arguments passed to the hello function
    int argc = lua_gettop(L);
 
    //iterate the arguments as display them
    for(int n=1; n<=argc; ++n)
        printf("argument received - index: %d - value: %s\n", n, lua_tostring(L, n));
 
    //let's return a value - it's the answer to the universe
    lua_pushnumber(L, 42);
 
    return 1;
}
 
int main(int argc, char ** argv){
 
    //iterate all files and execute
    for(int n=1; n<argc; n++){
        const char * file = argv[n];
 
        //create a new lua state
        lua_State * L = luaL_newstate();
 
        //open all libraries
        luaL_openlibs(L);
 
        //register new custom method
        lua_register(L, "hello", hello);
 
        int s = luaL_loadfile(L, file);
 
        if(!s)
            s = lua_pcall(L, 0, LUA_MULTRET, 0);
 
        //show any errors
        if(s){
            printf("Error: %s \n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
 
        lua_close(L);
    }
 
    return 0;
}

 

Now let’s compile it:

user@computer:$ g++ lua-host.cpp -o lua-host -llua

Finally, let’s add some parameters to our “hello” call in Lua and check the return value.

Edit the “hello_world.lua” file and ensure it has the following:

print("Lua says: Hello World")
r = hello("booyah!", "biscuits!")
print("The value returned from the hello call was: ", r)

So we’ve added two parameters to our C++ “hello” call, “booyah!” and “biscuits!”. We’re also storing the return value in the variable “r” and displaying it by way of the print() call. Now, let’s run it and see what we get:

user@computer:$ ./lua-host hello_world.lua
Lua says: Hello World
C++ says: Hello World
argument received - index: 1 - value: booyah!
argument received - index: 2 - value: biscuits!
The value returned from the hello call was: 42

Perfection is the key! Hopefully that wasn’t too confusing and will help you get started in implementing Lua into your applications. Let me know if you have any issues or questions in the comments below.

Optimizing memcpy Routines

First let’s understand what the problem is. Memcpy copies memory one byte at a time. Which is fine as long as you don’t have a lot of memory to copy. If you find yourself needing to copy large chunks of memory from one spot to the next you may very well find yourself loosing a lot of process time in the memcpy routine. One possible way to optimize this call is to define a copy routine of your own that is optimized for the data types you need to copy. For example, let’s say that you have data that will always be in 8 byte sections. A good way to optimize this would be to copy the data 8 bytes at a time versus 1 byte at a time via memcpy. Consider the following code:

void uint8copy(void *dest, void *src, size_t n){
    uint64_t * ss = (uint64_t)src;
    uint64_t * dd = (uint64_t)dest;
    n = n * sizeof(uint8_t)/sizeof(uint64_t); 
 
    while(n--)
        *dd++ = *ss++;
}//end uint8copy()

The code is pretty simple, it takes in a dest, src, and n (size) the same as memcpy. But, it converts the src and dest pointers to uint64_t or 64 bit pointers before making the copy. Next it determines how many times to iterate and begins copying data 64 bits or 8 bytes at a time. This approach works well for this particular scenario and may assist in being a starting point for your code as well.

Finding The Fastest Write Method

I was recently tasked to develop a system that would need to write data in the Gigabytes per second range directly to disk. While doing so, I needed to spec out and build a machine that allowed for that type of bandwidth to be persisted as well as find the most optimized filesystem and write method available in C. Once the specs were done and the machine arrived, it was time to determine which filesystem and write method under Linux would give the best results for writing. I initially tested with bonnie++, but soon became aware that the results I was receiving were not a true test of the raid configuration and filesystem, but were instead block writes and reads. For my purposes I need to benchmark the write speed of several different writing types including asynchronous writing, standard IO and generic (open,write,read) IO. To do so, I created a simple writetest program:

#include <aio.h>
#include <time.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <math.h> 
 
int nVersionMajor = 1;
int nVersionMinor = 0;
int nVersionBuild = 1;
int64_t mb = 1048576;
char szOutputDir[1024];
long nSize = 0;
int nIteration;
short nUseAio;
short nUseStd;
short nUseGen;
unsigned long long nStdioAvg = 0;
unsigned long long nAioAvg = 0;
unsigned long long nGenAvg = 0;
double nSec = 1000000.0; 
 
char * pBytes; 
 
void stdioWrite(char * filename){
    FILE * pFile;
    struct timeval tvStart;
    struct timeval tvEnd;
    int64_t nEnd;
    int64_t nStart; 
 
    gettimeofday(&tvStart);
    nStart = tvStart.tv_sec * 1000000 + tvStart.tv_usec; 
 
    pFile = fopen(filename,"w");
    if(!pFile){
        fprintf(stderr, "[Error] could not open %s for writing.n", filename);
        exit(1);
    }//end if 
 
    fwrite(pBytes, strlen(pBytes), 1, pFile);     
 
    fclose(pFile); 
 
    gettimeofday(&tvEnd);
    nEnd = tvEnd.tv_sec * 1000000 + tvEnd.tv_usec; 
 
    nStdioAvg += (nEnd-nStart);
    printf("stdio->fopen,fwrite,fclose t%f sec.n", (nEnd-nStart)/nSec);
}//end stdioWrite() 
 
void aioWrite(char * filename){
    struct aiocb aio;
    int outFile;
    struct timeval tvStart;
    struct timeval tvEnd;
    int64_t nEnd;
    int64_t nStart; 
 
    gettimeofday(&tvStart);
    nStart = tvStart.tv_sec * 1000000 + tvStart.tv_usec; 
 
    outFile = open(filename, O_WRONLY|O_CREAT, 0666); 
 
    if(outFile == -1){
        fprintf(stderr, "[Error] Could not open %s for writing.n", filename);
        exit(1);
    }//end if 
 
    aio.aio_offset = 0;
    aio.aio_fildes = outFile;
    aio.aio_reqprio = 0;
    aio.aio_buf = pBytes;
    aio.aio_nbytes = strlen(pBytes);
    aio.aio_sigevent.sigev_notify = SIGEV_NONE; 
 
    aio_write(&aio); 
 
    while(aio_error(&aio) == EINPROGRESS);
    close(outFile); 
 
    gettimeofday(&tvEnd);
    nEnd = tvEnd.tv_sec * 1000000 + tvEnd.tv_usec; 
 
    nAioAvg += (nEnd-nStart);
    printf("aio->open,aio_write,close t%f sec.n", (nEnd-nStart)/nSec);
}//end aioWrite() 
 
void genWrite(char * filename){
    int outFile;
    struct timeval tvStart;
    struct timeval tvEnd;
    int64_t nEnd;
    int64_t nStart; 
 
    gettimeofday(&tvStart);
    nStart = tvStart.tv_sec * 1000000 + tvStart.tv_usec; 
 
    outFile = open(filename, O_WRONLY|O_CREAT, 0666); 
 
    if(outFile == -1){
        fprintf(stderr, "[Error] Could not open %s for writing.n", filename);
        exit(1);
    }//end if 
 
    write(outFile, pBytes, strlen(pBytes)); 
 
    close(outFile); 
 
    gettimeofday(&tvEnd);
    nEnd = tvEnd.tv_sec * 1000000 + tvEnd.tv_usec; 
 
    nGenAvg += (nEnd-nStart);
    printf("gen->open,write,close     t%f sec.n", (nEnd-nStart)/nSec);
}//end genWrite() 
 
void displayUsage(){
    printf("writetest - GodLikeMouse file write testing Version %d.%d.%dn", nVersionMajor, nVersionMinor, nVersionBuild);
    printf("tCopyright 2008 GodLikeMouse (www.GodLikeMouse.com)n");
    printf("n");
    printf("Usage:n");
    printf("tnqpcapd [options]n");
    printf("n");
    printf("Options:n");
    printf("t--output-dir [directory]n");
    printf("ttThe directory to write to for testing (default .test).n");
    printf("t--i [iterations]n");
    printf("ttThe amount of times to write (default 1).n");
    printf("t--mb [megabytes to write]n");
    printf("ttThe size of the files to write in megabytes.n");
    printf("t--b [bytes to write]n");
    printf("ttThe size of the files to write in bytes.n");
    printf("ttwritten (default /data).n");
    printf("t--stdion");
    printf("ttUse fopen,fwrite,fclose.n");
    printf("t--aion");
    printf("ttUse open,aio_write,close.n");
    printf("t--genion");
    printf("ttUse open,write,close.n");
    printf("t--helpn");
    printf("ttDisplay this help message.n");
    printf("t--versionn");
    printf("ttDisplay the version information.n");
    printf("n");
}//end displayUsage() 
 
void parseArgs(int argc, char ** argv){
    int i; 
 
    for(i=0; i<argc; i++){ 
 
        if(strstr(argv[i], "--output-dir")){
            sprintf(szOutputDir, "%s", argv[++i]);
            continue;
        }//end if 
 
        if(strstr(argv[i], "--mb")){
            nSize = mb * atol(argv[++i]);
            continue;
        }//end if 
 
        if(strstr(argv[i], "--b")){
            nSize = atol(argv[++i]);
            continue;
        }//end if 
 
        if(strstr(argv[i], "--help")){
            displayUsage();
            exit(0);
        }//end if 
 
        if(strstr(argv[i], "--i")){
            nIteration = atoi(argv[++i]);
            continue;
        }//end if 
 
        if(strstr(argv[i], "--aio")){
            nUseAio = 1;
            continue;
        }//end if 
 
        if(strstr(argv[i], "--stdio")){
            nUseStd = 1;
            continue;
        }//end if 
 
        if(strstr(argv[i], "--genio")){
            nUseGen = 1;
            continue;
        }//end if 
 
        if(strstr(argv[i], "--version")){
            printf("writetest - GodLikeMouse file write testing Version %d.%d.%dn", nVersionMajor, nVersionMinor, nVersionBuild);
            exit(0);
        }//end if
    }//end for
}//end parseArgs() 
 
void printSeparator(){
    printf("---------------------------------------------n");
}//end printSeparator() 
 
void printAverages(){
    double nTemp; 
 
    if(nUseStd){
        nTemp = ((double)nStdioAvg/nIteration)/nSec;
        printf("stdio average write time: t%f sec.n", nTemp);
        printf("stdio average throughput: t%.0f bytes/sec ", nSize/nTemp);
        printf("%.0f MB/secn", (nSize/nTemp)/mb);
    }//end if 
 
    if(nUseAio){
        nTemp = ((double)nAioAvg/nIteration)/nSec;
        printf("aio average write time: t%f sec.n", nTemp);
        printf("aio average throughput: t%.0f bytes/sec ", nSize/nTemp);
        printf("%.0f MB/secn", (nSize/nTemp)/mb);
    }//end if 
 
    if(nUseGen){
        nTemp = ((double)nGenAvg/nIteration)/nSec;
        printf("gen average write time: t%f sec.n", nTemp);
        printf("gen average throughput: t%.0f bytes/sec ", nSize/nTemp);
        printf("%.0f MB/secn", (nSize/nTemp)/mb);
    }//end if
}//end printAverages() 
 
int main(int argc, char ** argv){
    int i;
    char szFile[2048]; 
 
    nIteration = 1;
    nSize = 1024;
    strcpy(szOutputDir, ".test");
    nUseStd = 0;
    nUseAio = 0;
    nUseGen = 0; 
 
    parseArgs(argc, argv); 
 
    printf("n");
    printf("Beginning cycle writen");
    printf("Writing %ld bytes, %ld MBn", nSize, (nSize/mb)); 
 
    printSeparator(); 
 
    for(i=0; i<nIteration; i++){
        if(nUseStd){
            pBytes = (char *)malloc(nSize);
            memset(pBytes, 'X', nSize);
            sprintf(szFile, "%s/%s.%d", szOutputDir, "stdio", i);
            stdioWrite(szFile);
            free(pBytes);
        }//end if 
 
        if(nUseAio){
            pBytes = (char *)malloc(nSize);
            memset(pBytes, 'X', nSize);
            sprintf(szFile, "%s/%s.%d", szOutputDir, "aio", i);
            aioWrite(szFile);
            free(pBytes);
        }//end if 
 
        if(nUseGen){
            pBytes = (char *)malloc(nSize);
            memset(pBytes, 'X', nSize);
            sprintf(szFile, "%s/%s.%d", szOutputDir, "gen", i);
            genWrite(szFile);
            free(pBytes);
        }//end if 
 
        printSeparator();
    }//end for 
 
    printf("n");
    printAverages();
    printf("n");
    printf("n"); 
 
    printf("Beginning sequential writen");
    printf("Writing %ld bytes, %ld MBn", nSize, (nSize/mb)); 
 
    printSeparator(); 
 
    nStdioAvg = 0;
    nAioAvg = 0;
    nGenAvg = 0; 
 
    if(nUseStd){
        for(i=0; i<nIteration; i++){
            pBytes = (char *)malloc(nSize);
            memset(pBytes, 'X', nSize);
            sprintf(szFile, "%s/%s.%d", szOutputDir, "stdio", i);
            stdioWrite(szFile);
            free(pBytes);
        }//end for
        printSeparator();
    }//end if 
 
    if(nUseAio){
        for(i=0; i<nIteration; i++){
            pBytes = (char *)malloc(nSize);
            memset(pBytes, 'X', nSize);
            sprintf(szFile, "%s/%s.%d", szOutputDir, "aio", i);
            aioWrite(szFile);
            free(pBytes);
        }//end for
        printSeparator();
    }//end if 
 
    if(nUseGen){
        for(i=0; i<nIteration; i++){
            pBytes = (char *)malloc(nSize);
            memset(pBytes, 'X', nSize);
            sprintf(szFile, "%s/%s.%d", szOutputDir, "gen", i);
            genWrite(szFile);
            free(pBytes);
        }//end for
        printSeparator();
    }//end if 
 
    printf("n");
    printAverages();
    printf("n"); 
 
}//end main()

This simple program took in a set of parameters to determine which write methods to use to write, how much data, how many times and where to write it. Using this I began testing all the available free filesystems I could find for Linux. The fastest write speeds were given by XFS with the following make and mount options.

root@localhost:$ mkfs.xfs -l size=32m -d agcount=4 /dev/sda4
mount /dev/sda4 /data -o noatime,nodiratime,osyncisdsync

The first round metrics I received using this method to test are as follows:

root@localhost:$ writetest # src/writetest --output-dir /data/ --stdio --aio --genio --i 3 --mb 500

Beginning cycle write
Writing 524288000 bytes, 500 MB
---------------------------------------------
stdio->fopen,fwrite,fclose 1.047127 sec.
aio->open,aio_write,close 5.724001 sec.
gen->open,write,close 2.580516 sec.
---------------------------------------------
stdio->fopen,fwrite,fclose 2.063382 sec.
aio->open,aio_write,close 5.954485 sec.
gen->open,write,close 1.351529 sec.
---------------------------------------------
stdio->fopen,fwrite,fclose 1.729958 sec.
aio->open,aio_write,close 6.457802 sec.
gen->open,write,close 1.754718 sec.
---------------------------------------------

stdio average write time: 1.613489 sec.
stdio average throughput: 324940548 bytes/sec 310 MB/sec
aio average write time: 6.045429 sec.
aio average throughput: 86724693 bytes/sec 83 MB/sec
gen average write time: 1.895588 sec.
gen average throughput: 276583357 bytes/sec 264 MB/sec

Beginning sequential write
Writing 524288000 bytes, 500 MB
---------------------------------------------
stdio->fopen,fwrite,fclose 1.479412 sec.
stdio->fopen,fwrite,fclose 1.597659 sec.
stdio->fopen,fwrite,fclose 1.851250 sec.
---------------------------------------------
aio->open,aio_write,close 6.575862 sec.
aio->open,aio_write,close 7.003166 sec.
aio->open,aio_write,close 6.991679 sec.
---------------------------------------------
gen->open,write,close 1.465857 sec.
gen->open,write,close 0.980143 sec.
gen->open,write,close 0.841066 sec.
---------------------------------------------

stdio average write time: 1.642774 sec.
stdio average throughput: 319148043 bytes/sec 304 MB/sec
aio average write time: 6.856902 sec.
aio average throughput: 76461349 bytes/sec 73 MB/sec
gen average write time: 1.095689 sec.
gen average throughput: 478500888 bytes/sec 456 MB/sec

Writing 500MB of data directly to disk using stdio (fopen,fwrite,fclose) aio (open,aio_write,close) and genio (open,write,close) for 3 iterations yeilded 456 when calling open,write,close consecutively; which is great, it meant I’m on the right track. After a few more tweaks and using genio (open,write,close) I started seeing:

root@localhost:$ src/writetest --output-dir /data/ --genio --i 3 --mb 500

Beginning cycle write
Writing 524288000 bytes, 500 MB
---------------------------------------------
gen->open,write,close 0.804808 sec.
---------------------------------------------
gen->open,write,close 0.850169 sec.
---------------------------------------------
gen->open,write,close 0.867514 sec.
---------------------------------------------

gen average write time: 0.840830 sec.
gen average throughput: 623536021 bytes/sec 595 MB/sec

Beginning sequential write
Writing 524288000 bytes, 500 MB
---------------------------------------------
gen->open,write,close 0.855086 sec.
gen->open,write,close 0.947534 sec.
gen->open,write,close 0.842693 sec.
---------------------------------------------

gen average write time: 0.881771 sec.
gen average throughput: 594585215 bytes/sec 567 MB/sec

Perfect, now I getting where I need to go and I know that XFS with the options I specified along with using the generic open,read,write approach would give me the best write times. Feel free to take the above writetest program and use it to tune your filesystem and to make sure that you’re using the fastest possible write method for your chosen filesystem. Be sure to compile with -laio. I thought these findings were worth mentioning.

**************** Update ********************

After changing the OS from a 32-bit to 64-bit system and with a few additional modifications to the kernel, new and even more impressive speeds have been reached

root@localhost:$ src/writetest --mb 500 --i 10 --output-dir /data --genio

Beginning cycle write
Writing 524288000 bytes, 500 MB
---------------------------------------------
gen->open,write,close 0.460466 sec.
---------------------------------------------
gen->open,write,close 0.493884 sec.
---------------------------------------------
gen->open,write,close 0.494179 sec.
---------------------------------------------
gen->open,write,close 0.492141 sec.
---------------------------------------------
gen->open,write,close 0.491546 sec.
---------------------------------------------
gen->open,write,close 0.490171 sec.
---------------------------------------------
gen->open,write,close 0.490388 sec.
---------------------------------------------
gen->open,write,close 0.489386 sec.
---------------------------------------------
gen->open,write,close 0.489673 sec.
---------------------------------------------
gen->open,write,close 0.491476 sec.
---------------------------------------------

gen average write time: 0.488331 sec.
gen average throughput: 1073632434 bytes/sec 1024 MB/sec

Beginning sequential write
Writing 524288000 bytes, 500 MB
---------------------------------------------
gen->open,write,close 0.484176 sec.
gen->open,write,close 0.489009 sec.
gen->open,write,close 0.491489 sec.
gen->open,write,close 0.487558 sec.
gen->open,write,close 0.489555 sec.
gen->open,write,close 0.486413 sec.
gen->open,write,close 0.492973 sec.
gen->open,write,close 0.489842 sec.
gen->open,write,close 0.487276 sec.
gen->open,write,close 0.489895 sec.
---------------------------------------------

gen average write time: 0.488819 sec.
gen average throughput: 1072561478 bytes/sec 1023 MB/sec