reinventing the wheel: libmc

35
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Reinventing the wheel: libmc [email protected] Jan 23, 2015

Upload: myautsai-pan

Post on 15-Apr-2017

185 views

Category:

Engineering


0 download

TRANSCRIPT

Page 1: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Reinventing the wheel: libmc

[email protected]

Jan 23, 2015

Page 2: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 3: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 4: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

The memcached family

▶ memcached (the memcached server-side software)

▶ memcache (typo and nickname)

▶ mc (nickname)

▶ libmemcached ( C/C++ client library)

▶ libmemcache (yet another C client library, DEAD since 2006)

▶ python-memcached (pure python client library)

▶ python-libmemcached (Cython client, library based onlibmemcached)

▶ cmemcached (alias of python-libmemcached)

▶ pylibmc (C-Extensions for Python by hand, based onlibmemcached)

Page 5: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 6: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Bad things of libmemcached

▶ Divergence of libmemcached between upstream and thebranch we use. (the “large split” feature)

▶ Complex

▶ Buggy

▶ (lib)memcached is a weird creature.http://hoborglabs.com/en/blog/2013/memcached-php

Page 7: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 8: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Retrieval Commands

Request and Response

get <key>*\r\n

VALUE <key> <flags> <bytes>\r\n<data block>\r\n

Example

get foo bar baz\r\n

VALUE foo 0 3\r\nabc\r\nVALUE baz 0 5\r\nsimp.\r\nEND\r\n

Page 9: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Storage Commands

Request and Response

<key> <flags> <exptime> <bytes>\r\n<data block>\r\n

STORED\r\n | NOT STORED\r\n

Example

set dou 0 0 10\r\n0123456789\r\nset ban 0 0 4\r\naoei\r\n

NOT STORED\r\nSTORED\r\n

Page 10: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 11: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Design of libmc

PyClient

|

Client

| (1:1)

ConnectionPool

| (1:N)

Connection

/ | (1:1) \

BufferReader Parser BufferWriter

| (1:N)

DataBlock

Page 12: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 13: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

BufferWriter

s s i z e t sendmsg ( i n t socket , con s t s t r u c t msghdr ∗message , i n t f l a g s ) ;

s t r u c t i o v e c {vo i d ∗ i o v b a s e ;s i z e t i o v l e n ;

} ;

s t r u c t msghdr {. . .s t r u c t i o v e c ∗msg iov ;s i z e t msg i o v l e n ;. . .

} ;

▶ UIO MAXIOV

▶ commitRead

Page 14: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 15: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

BufferReader

+ Fixed + Flexible

+------------+------------+-----------------------+---------------

| 8192 recved| 8192 recved| more than 8192 recved | DataBlock ...

+----+----+-------+-------+---------------------------------------

|XXXX|OOOO|BB|BBBB|CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC| DataBlockSlice

|XXXX|OOOO|BB|BBBB|CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC| ...

+------------+------+------------+------------+-------------------

|VALU|foo | 0 0 20| value of foo value of foo valu| Token

|E | | | e of foo .....................| ...

|----+----+-------+-------------------------------+---------------

▶ peek / readUntil / skipUtil / readUnsigned / readBytes /skipBytes / (no rewind)

▶ token.size() in 0, 1, 2 / SmallVector

▶ predictive DataBlock size

Page 16: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 17: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Other parts

▶ Parser as a finite-state machine (FSM)

▶ poll in ConnectionPool

Page 18: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 19: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.

▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 20: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.

▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 21: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.

▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 22: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.

▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 23: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.

▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 24: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error

▶ Server may refuse if too much data is “send”(sent) without“recv”-ing

▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 25: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing

▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 26: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.

▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 27: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.

▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 28: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.

▶ man 2 recv: For TCP sockets, the return value 0 means thepeer has closed its half side of the connection.

▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 29: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.

▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 30: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?

▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 31: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.

▶ vim: Rip-Rip/clang complete + cpplint.py

Page 32: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Tips

▶ Prefer “switch statements” to if-else condition.▶ “Exception” and “heap allocation” are slow in C++.▶ Avoid memory copy.▶ SmallVector optimization.▶ Undocumented “UIO MAXIOV” limit in iovec.▶ clean buffer on error▶ Server may refuse if too much data is “send”(sent) without

“recv”-ing▶ Lazy connecting.▶ GIL issue.▶ gevent issue.▶ man 2 recv: For TCP sockets, the return value 0 means the

peer has closed its half side of the connection.▶ write the right benchmark. bench order? dependency?▶ md5 is slow. bugfree fnv1 is hard to implement.▶ vim: Rip-Rip/clang complete + cpplint.py

Page 33: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Outline

WordplayThe memcached family

Why reinventing the new wheelBad things of libmemcached

Design a new memcached clientThe ASCII protocol(get/set part)Module DiagramBufferWriterBufferReaderOther parts

Lessons I learnedTipsGreat Toolchain

Page 34: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Great Toolchain

▶ CMake

▶ Valgrind

▶ Callgrind(valgrind –tool=callgrind) +kcachegrind/qcachegrind

▶ googletest

Page 35: Reinventing the wheel: libmc

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Links I

libmc: https://github.com/douban/libmc

benchmark of libmc: https://gist.github.com/mckelvin/8ded053f6523931765d4

Improving performance of std::vector:http://fahrenheit2539.blogspot.com/2012/06/

introduction-in-depths-look-at.html

How to profile C++ application with Callgrind / KCacheGrind:http://baptiste-wicht.com/posts/2011/09/

profile-c-application-with-callgrind-kcachegrind.

html