aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/lwtrace/tests/trace_tests.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/lwtrace/tests/trace_tests.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/lwtrace/tests/trace_tests.cpp')
-rw-r--r--library/cpp/lwtrace/tests/trace_tests.cpp715
1 files changed, 715 insertions, 0 deletions
diff --git a/library/cpp/lwtrace/tests/trace_tests.cpp b/library/cpp/lwtrace/tests/trace_tests.cpp
new file mode 100644
index 0000000000..6762e344a7
--- /dev/null
+++ b/library/cpp/lwtrace/tests/trace_tests.cpp
@@ -0,0 +1,715 @@
+#include <library/cpp/lwtrace/all.h>
+
+#include <library/cpp/getopt/last_getopt.h>
+
+#include <google/protobuf/text_format.h>
+
+#include <util/system/pipe.h>
+#include <util/generic/ymath.h>
+#include <util/string/printf.h>
+#include <util/string/vector.h>
+
+#define LWTRACE_TESTS_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(Simplest, GROUPS("Group"), TYPES(), NAMES()) \
+ PROBE(IntParam, GROUPS("Group"), TYPES(ui32), NAMES("value")) \
+ PROBE(StringParam, GROUPS("Group"), TYPES(TString), NAMES("value")) \
+ PROBE(SymbolParam, GROUPS("Group"), TYPES(NLWTrace::TSymbol), NAMES("symbol")) \
+ PROBE(CheckParam, GROUPS("Group"), TYPES(NLWTrace::TCheck), NAMES("value")) \
+ EVENT(TwoParamsEvent, GROUPS("Group"), TYPES(int, TString), NAMES("param1", "param2")) \
+ EVENT(TwoParamsCheckEvent, GROUPS("Group"), TYPES(NLWTrace::TCheck, TString), NAMES("param1", "param2")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_TESTS_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_TESTS_PROVIDER)
+LWTRACE_USING(LWTRACE_TESTS_PROVIDER)
+
+namespace NLWTrace {
+ namespace NTests {
+ TString gStrValue = "a long string value that can be possible passed as a trace probe string parameter";
+ //TString gStrValue = "short";
+
+ LWTRACE_DEFINE_SYMBOL(gSymbol, "a long symbol value that can be possible passed as a trace probe string parameter");
+
+ struct TConfig {
+ size_t Cycles;
+ size_t Runs;
+ bool UnsafeLWTrace;
+
+ TConfig() {
+ Cycles = 100000;
+ Runs = 10;
+ UnsafeLWTrace = false;
+ }
+ };
+
+ struct TMeasure {
+ double Average;
+ double Sigma;
+ TMeasure(double a, double s)
+ : Average(a)
+ , Sigma(s)
+ {
+ }
+ };
+
+#define DEFINE_MEASUREMENT(name, ...) \
+ double name##OneRun(const TConfig& cfg) { \
+ TInstant t0 = Now(); \
+ for (size_t i = 0; i < cfg.Cycles; i++) { \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ } \
+ TInstant t1 = Now(); \
+ return double(t1.MicroSeconds() - t0.MicroSeconds()) / (cfg.Cycles * 10); \
+ } \
+ TMeasure name##Time(const TConfig& cfg) { \
+ double v = 0; \
+ double vSq = 0; \
+ for (size_t i = 0; i < cfg.Runs; i++) { \
+ double value = name##OneRun(cfg); \
+ v += value; \
+ vSq += value * value; \
+ } \
+ v /= cfg.Runs; \
+ vSq /= cfg.Runs; \
+ return TMeasure(v, sqrt(vSq - v * v)); \
+ } \
+ /**/
+
+ class TProbes: public TProbeRegistry {
+ public:
+ TManager Mngr;
+
+ TProbes(bool destructiveActionsAllowed)
+ : Mngr(*this, destructiveActionsAllowed)
+ {
+ AddProbesList(LWTRACE_GET_PROBES(LWTRACE_TESTS_PROVIDER));
+ }
+
+#define HOTSPOT(name, ...) LWPROBE(name, ##__VA_ARGS__);
+ DEFINE_MEASUREMENT(Simplest);
+ DEFINE_MEASUREMENT(IntParam, 123);
+ DEFINE_MEASUREMENT(StringParam, gStrValue);
+ DEFINE_MEASUREMENT(SymbolParam, gSymbol);
+ DEFINE_MEASUREMENT(CheckParam, TCheck(13));
+#undef HOTSPOT
+ };
+
+ class TInMemoryLogTest {
+ public:
+ TInMemoryLog Log;
+
+ TInMemoryLogTest()
+ : Log(1000)
+ {
+ }
+
+#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__);
+ DEFINE_MEASUREMENT(TwoParamsEvent, 666, TString("bla-bla-bla"));
+#undef HOTSPOT
+ };
+
+ class TInMemoryLogCheckTest {
+ public:
+ TInMemoryLog Log;
+
+ TInMemoryLogCheckTest()
+ : Log(1000)
+ {
+ }
+
+#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__);
+ DEFINE_MEASUREMENT(TwoParamsCheckEvent, TCheck(666), TString("bla-bla-bla"));
+#undef HOTSPOT
+ };
+
+ NLWTrace::TQuery MakeQuery(const TString& queryStr) {
+ NLWTrace::TQuery query;
+ google::protobuf::TextFormat::ParseFromString(queryStr, &query);
+ return query;
+ }
+
+ void NoExec(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ Cout << "call to probe w/o executor: " << p.SimplestTime(cfg) << Endl;
+ }
+
+ void Log(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with logging executor: " << p.SimplestTime(cfg) << Endl;
+ }
+
+ void LogTs(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: true"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with logging (+timestamp) executor: " << p.SimplestTime(cfg) << Endl;
+ }
+
+ void FalseIntFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"1000\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with int filter (always false) executor: " << p.IntParamTime(cfg) << Endl;
+ }
+
+ void LogIntAfterFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with int filter (always true) and log executors: " << p.IntParamTime(cfg) << Endl;
+ }
+
+ void LogInt(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to int probe with log executor: " << p.IntParamTime(cfg) << Endl;
+ }
+
+ void FalseStringFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"string that never can exist\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void FalseStringFilterPartialMatch(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"" +
+ gStrValue + "-not-full-match\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void LogStringAfterFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"" +
+ gStrValue + "\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with string filter (always true) and log executors: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void LogString(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to string probe with log executor: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void LogSymbol(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"SymbolParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to symbol probe with log executor: " << p.SymbolParamTime(cfg) << Endl;
+ }
+
+ void LogCheck(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"CheckParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to check probe with log executor: " << p.CheckParamTime(cfg) << Endl;
+ }
+
+ void InMemoryLog(const TConfig& cfg) {
+ TInMemoryLogTest test;
+ Cout << "log to in-memory log with (int, string) writer: " << test.TwoParamsEventTime(cfg) << Endl;
+ }
+
+ void InMemoryLogCheck(const TConfig& cfg) {
+ TInMemoryLogCheckTest test;
+ Cout << "log to in-memory log with (leak-check, string) writer: " << test.TwoParamsCheckEventTime(cfg) << Endl;
+ }
+
+ void MultipleActionsCheck(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-multipleActions", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_LT"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"2\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_INC"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_DEC"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_SUB_EQ"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"-1\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " SleepAction {"
+ " NanoSeconds: 25000000" // 25 ms
+ " }"
+ " }"
+ " Action {"
+ " SleepAction {"
+ " NanoSeconds: 25000000" // 25 ms
+ " }"
+ " }"
+ "}"));
+ TInstant t0 = Now();
+ for (size_t i = 0; i < 10; i++) {
+ LWPROBE(Simplest);
+ }
+ TInstant t1 = Now();
+ ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds());
+ Cout << "multiple sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl;
+ }
+
+ void SleepCheck(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-sleep", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " SleepAction {"
+ " NanoSeconds: 100000000" // 100 ms
+ " }"
+ " }"
+ "}"));
+ TInstant t0 = Now();
+ for (size_t i = 0; i < 10; i++) {
+ LWPROBE(Simplest);
+ }
+ TInstant t1 = Now();
+ ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds()) / (ui64)10;
+ Cout << "sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl;
+ }
+
+ void KillCheckChild(const TConfig& cfg, TPipeHandle& writer) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-kill", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " KillAction {"
+ " }"
+ " }"
+ "}"));
+ // Send "i'm alive and ok" to the parent (0)
+ char buffer = 0;
+ writer.Write(&buffer, 1);
+ LWPROBE(Simplest);
+ // Send "i'm alive and that's not OK" to the parent (1)
+ buffer = 1;
+ writer.Write(&buffer, 1);
+ }
+
+ void KillCheckParent(TPipeHandle& reader) {
+ char buffer = -1;
+ reader.Read(&buffer, 1);
+ reader.Read(&buffer, 1);
+ if (buffer == -1)
+ Cerr << "\t\terror: process died before transfering OK message during the KillAction test!" << Endl;
+ else if (buffer != 0)
+ Cerr << "\t\terror: process failed to die on time during the KillAction test!" << Endl;
+ else
+ Cout << "\t\tkill executor tested OK." << Endl;
+ }
+
+ void KillCheck(const TConfig& cfg) {
+#ifdef _unix_
+ TPipeHandle reader;
+ TPipeHandle writer;
+ TPipeHandle::Pipe(reader, writer);
+ Cout << "forking the process..." << Endl;
+ pid_t cpid = fork();
+ if (cpid == -1) {
+ Cerr << "\t\terror forking for the KillAction test!" << Endl;
+ } else if (cpid == 0) {
+ reader.Close();
+ KillCheckChild(cfg, writer);
+ writer.Close();
+ exit(EXIT_SUCCESS);
+ } else {
+ writer.Close();
+ KillCheckParent(reader);
+ reader.Close();
+ }
+#else
+ Cout << "kill action test for windows is not implemented." << Endl;
+#endif
+ }
+
+ void LogIntModFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_ADD_EQ"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"1\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_ADD"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"1\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_MOD"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"20\""
+ " }"
+ " }"
+ " }"
+ "}"
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with int mod filter (always true, mod 10) and log executors: " << p.IntParamTime(cfg) << Endl;
+ }
+
+#define FOR_EACH_TEST() \
+ FOR_EACH_TEST_MACRO(LogIntModFilter) \
+ FOR_EACH_TEST_MACRO(SleepCheck) \
+ FOR_EACH_TEST_MACRO(MultipleActionsCheck) \
+ FOR_EACH_TEST_MACRO(KillCheck) \
+ FOR_EACH_TEST_MACRO(InMemoryLog) \
+ FOR_EACH_TEST_MACRO(InMemoryLogCheck) \
+ FOR_EACH_TEST_MACRO(NoExec) \
+ FOR_EACH_TEST_MACRO(Log) \
+ FOR_EACH_TEST_MACRO(LogTs) \
+ FOR_EACH_TEST_MACRO(FalseIntFilter) \
+ FOR_EACH_TEST_MACRO(LogIntAfterFilter) \
+ FOR_EACH_TEST_MACRO(LogInt) \
+ FOR_EACH_TEST_MACRO(FalseStringFilter) \
+ FOR_EACH_TEST_MACRO(FalseStringFilterPartialMatch) \
+ FOR_EACH_TEST_MACRO(LogStringAfterFilter) \
+ FOR_EACH_TEST_MACRO(LogString) \
+ FOR_EACH_TEST_MACRO(LogSymbol) \
+ FOR_EACH_TEST_MACRO(LogCheck) \
+ /**/
+
+ int Main(int argc, char** argv) {
+ TConfig cfg;
+ using namespace NLastGetopt;
+ TOpts opts = NLastGetopt::TOpts::Default();
+ opts.AddLongOption('c', "cycles", "cycles count").RequiredArgument("N").DefaultValue(ToString(cfg.Cycles)).StoreResult(&cfg.Cycles);
+ opts.AddLongOption('r', "runs", "runs count").RequiredArgument("N").DefaultValue(ToString(cfg.Runs)).StoreResult(&cfg.Runs);
+ opts.AddLongOption('u', "unsafe-lwtrace", "allow destructive actions").OptionalValue(ToString(true)).DefaultValue(ToString(false)).StoreResult(&cfg.UnsafeLWTrace);
+ opts.AddHelpOption('h');
+ TOptsParseResult res(&opts, argc, argv);
+
+ TVector<TString> tests = res.GetFreeArgs();
+ if (tests.empty()) {
+#define FOR_EACH_TEST_MACRO(t) tests.push_back(#t);
+ FOR_EACH_TEST()
+#undef FOR_EACH_TEST_MACRO
+ }
+ for (size_t i = 0; i < tests.size(); i++) {
+ const TString& test = tests[i];
+#define FOR_EACH_TEST_MACRO(t) \
+ if (test == #t) { \
+ Cout << #t ": \t"; \
+ t(cfg); \
+ }
+ FOR_EACH_TEST()
+#undef FOR_EACH_TEST_MACRO
+ }
+
+ if (TCheck::ObjCount != 0) {
+ Cout << ">>>>> THERE IS AN OBJECT LEAK <<<<<" << Endl;
+ Cout << "NLWTrace::TCheck::ObjCount = " << TCheck::ObjCount << Endl;
+ }
+
+ Cout << "Done" << Endl;
+ return 0;
+ }
+
+ }
+
+}
+
+template <>
+void Out<NLWTrace::NTests::TMeasure>(IOutputStream& os, TTypeTraits<NLWTrace::NTests::TMeasure>::TFuncParam measure) {
+ os << Sprintf("\n\t\t%.6lf +- %.6lf us,\tRPS: %30.3lf (%.1fM)", measure.Average, measure.Sigma, 1000000.0 / measure.Average, 1.0 / measure.Average);
+}
+
+int main(int argc, char** argv) {
+ try {
+ return NLWTrace::NTests::Main(argc, argv);
+ } catch (std::exception& e) {
+ Cerr << e.what() << Endl;
+ return 1;
+ } catch (...) {
+ Cerr << "Unknown error" << Endl;
+ return 1;
+ }
+}