начал писать еще в поезде, поэтому на онглейскам
The lesson I learned today is that before you start optimizing something, you must make sure that you're optimizing the right thing =)
The system analyst gave me a task to fix one thing and asked to make it reasonably fast, meaning so that the code would be fast.
The code was written in C mostly with some rare feats of C++ used and mostly worked with C-strings checking them for certain conditions, parsing a bit, and modifying them. So I fixed the problem making some minor optimizations along the way or maybe even not optimizations but you know, simplifying, using library functions instead of square wheels, stuff like that.
Then I isolated all the code that was involved into a separate file, basically made kinda like a testing shell for this code, ran it against example strings some 150000 times and measured the time, even though my code added some more work to be done, it was faster than the old code by ~one second. But still, considering that the machine had a 3 Ghz Pentium 4, I wasn't satisfied by the execution time.
I looked at the functions which I wrote and modified but they were already optimized to the limit, or let's put it like this, any further optimizations wouldn't be worth the effort. I was about to let it go, but a gut feeling told me to do a profiling of the program. I compiled the prog like g++ -gp test.cc -o test ran it and then looked at the results with
gprof(1). The profiling showed me that ~70% of the execution time was spent in just one function, the one I had completely overlooked, the one which was at least two screens higher than the code I was working on =)
I looked at that function... And everything was clear to me from the first sight, the function was converting a string which contained unprintable (lol) characters into a string with hex-codes in place of those chars.
The body of the loop looked approximately like this:
...
{
if (c < LOWER && c > UPPER)
sprintf(tmpbuf, "\\%02x", c);
else
sprintf(tmpbuf, "%c", c);
strcat(buf, tmpbuf);
}
...
I rewrote it like this:
...
static const char *hex_tab[] = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f'
};
...
{
if (isgraph(*p)) {
*q++ = *p;
} else {
*q++ = '\\';
*q++ = hex_tab[(*p >> 4) & 0xf];
*q++ = hex_tab[*p & 0xf];
}
}
...
The execution time went down from 11 seconds to ~1.5 second.
I knew the time I spent sitting at home in summer a few years ago, doing all those excercises from The C Programming Language while everyone was having a good time in Jurmala wasn't a waste!
Еще я недавно писал одну хрень, где надо было типа на основании того что пришло во входяшем сообщении, составить исходящее сообщение и передать дальше. Правила короче нужны были.
Я в конце концов определился со структурами данных, но не обрел умиротворения. Как-то уж слишком громоздко все получалось. Я хотел было использовать еще более хитрую структуру данных, которая уже чем-то смахивала на выполняемый байт-код и вот тогда то я и осознал одну вещь.
Я осознал, что фактически, пытаюсь избавиться от этих правил вообще. Пытаюсь сделать так, чтобы мне не надо было программировать эти правила. Но фишка в том, что чтобы я не делал -- эти правила все равно придется о/писать. Хоть структурой данных, хоть продвинутой байт-код подобной структурой данных, хоть написать их на встроенном скриптовом языке. Это неизбежно.
Компьютер делает только то, что я ему говорю делать, а не то что я хочу чтобы он сделал. (видел эту фразу однажды в fortune'е)
статья опубликована с письменного разрешения Капитана Очевидности