123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- #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;
- }
- }
|