| 1 | RFC - Testpoint mechanism\r |
| 2 | \r |
| 3 | Author: Christian Babeux <christian.babeux@efficios.com>\r |
| 4 | \r |
| 5 | Contributors:\r |
| 6 | * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>\r |
| 7 | \r |
| 8 | Version:\r |
| 9 | - v0.1: 11/09/2012\r |
| 10 | * Initial proposal\r |
| 11 | \r |
| 12 | Motivation\r |
| 13 | ----------\r |
| 14 | \r |
| 15 | The main goal behind the testpoint mechanism is to be able to test and\r |
| 16 | validate failure cases in different portion of the LTTng codebase. It\r |
| 17 | could also be used by developers as a debugging aid.\r |
| 18 | \r |
| 19 | By injecting code at runtime in the lttng daemons/processes/executables,\r |
| 20 | we can painlessly trigger faulty behavior, test errors paths or even\r |
| 21 | reproduce race conditions by introducing or exacerbating delays between\r |
| 22 | threads.\r |
| 23 | \r |
| 24 | Requirements\r |
| 25 | ------------\r |
| 26 | \r |
| 27 | The testpoint mechanism should be able to be triggered via scripts to\r |
| 28 | automate testing efforts.\r |
| 29 | \r |
| 30 | Ideally, the testpoint mechanism should *NOT* incur a significant\r |
| 31 | performance hit if we want to leave it always on, in a similar fashion\r |
| 32 | to the assert() macros.\r |
| 33 | \r |
| 34 | By leaving it always on, any user is able to use our tests and validate\r |
| 35 | the behavior of his installation via a simple 'make check' execution.\r |
| 36 | \r |
| 37 | Proposed solution\r |
| 38 | -----------------\r |
| 39 | \r |
| 40 | This patch introduce two new macros: TESTPOINT_DECL(name)\r |
| 41 | and testpoint(name).\r |
| 42 | \r |
| 43 | Here a quick example that shows how to use the testpoint mechanism:\r |
| 44 | \r |
| 45 | file: main.c\r |
| 46 | #include <stdio.h>\r |
| 47 | #include <common/testpoint/testpoint/testpoint.h>\r |
| 48 | \r |
| 49 | /* Testpoint declaration */\r |
| 50 | TESTPOINT_DECL(interesting_function)\r |
| 51 | \r |
| 52 | void interesting_function(void)\r |
| 53 | {\r |
| 54 | testpoint(interesting_function);\r |
| 55 | /* Some processing that can fail */\r |
| 56 | ...\r |
| 57 | }\r |
| 58 | \r |
| 59 | int main(int argc, char *argv[])\r |
| 60 | {\r |
| 61 | interesting_function();\r |
| 62 | ...\r |
| 63 | printf("End");\r |
| 64 | }\r |
| 65 | \r |
| 66 | file: testpoint.c\r |
| 67 | #include <stdio.h>\r |
| 68 | void __testpoint_interesting_function(void)\r |
| 69 | {\r |
| 70 | printf("In testpoint of interesting function!");\r |
| 71 | }\r |
| 72 | \r |
| 73 | Compile:\r |
| 74 | gcc -o test main.c\r |
| 75 | gcc -fPIC -shared -o testpoint.so testpoint.c\r |
| 76 | \r |
| 77 | Run:\r |
| 78 | > ./test\r |
| 79 | End\r |
| 80 | > export LTTNG_TESTPOINT_ENABLE=1\r |
| 81 | > LD_PRELOAD=testpoint.so ./test\r |
| 82 | In testpoint of interesting function!\r |
| 83 | End\r |
| 84 | > export LTTNG_TESTPOINT_ENABLE=0\r |
| 85 | > LD_PRELOAD=testpoint.so ./test\r |
| 86 | End\r |
| 87 | \r |
| 88 | The testpoint mechanism is triggered via the preloading of a shared\r |
| 89 | object containing the appropriate testpoint symbols and by setting the\r |
| 90 | LTTNG_TESTPOINT_ENABLE environment variable.\r |
| 91 | \r |
| 92 | The check on this environment variable is done on the application\r |
| 93 | startup with the help of a constructor (lttng_testpoint_check) which\r |
| 94 | toggle a global state variable indicating whether or not the testpoints\r |
| 95 | should be activated.\r |
| 96 | \r |
| 97 | When enabled, the testpoint() macro calls an underlying wrapper specific\r |
| 98 | to the testpoint and simply try to lookup the testpoint symbol via a\r |
| 99 | dlsym() call.\r |
| 100 | \r |
| 101 | When disabled, the testpoint() call will only incur an additionnal test\r |
| 102 | per testpoint on a global variable. This performance 'hit' should be\r |
| 103 | acceptable for production use.\r |
| 104 | \r |
| 105 | As stated previously, the testpoint mechanism should be *always on*. It\r |
| 106 | can be explicitly disabled via CFLAGS="-DNTESTPOINT" in a way similar to\r |
| 107 | NDEBUG and assert().\r |