mapitime.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. #include "config.h"
  2. #include <chrono>
  3. #include <cerrno>
  4. #include <csignal>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <ctime>
  8. #include <getopt.h>
  9. #include <spawn.h>
  10. #include <kopano/CommonUtil.h>
  11. #include <kopano/ECLogger.h>
  12. #include <kopano/MAPIErrors.h>
  13. #include <kopano/charset/convert.h>
  14. #include <kopano/ECMemTable.h>
  15. #include <kopano/automapi.hpp>
  16. #include <kopano/memory.hpp>
  17. #ifdef HAVE_CURL_CURL_H
  18. # include <curl/curl.h>
  19. #endif
  20. struct mpt_stat_entry {
  21. struct timespec start, stop;
  22. };
  23. using namespace KCHL;
  24. static std::list<struct mpt_stat_entry> mpt_stat_list;
  25. static std::wstring mpt_userw, mpt_passw;
  26. static const wchar_t *mpt_user, *mpt_pass;
  27. static const char *mpt_socket;
  28. static size_t mpt_repeat = ~0U;
  29. static void mpt_stat_dump(int s = 0)
  30. {
  31. size_t z = mpt_stat_list.size();
  32. if (z == 0)
  33. return;
  34. const struct mpt_stat_entry &first = *mpt_stat_list.begin();
  35. const struct mpt_stat_entry &last = *mpt_stat_list.rbegin();
  36. typedef std::chrono::seconds sec;
  37. typedef std::chrono::nanoseconds nsec;
  38. auto dt = std::chrono::duration<double>(
  39. sec(last.stop.tv_sec) + nsec(last.stop.tv_nsec) -
  40. (sec(first.start.tv_sec) + nsec(first.start.tv_nsec)));
  41. if (dt.count() == 0)
  42. return;
  43. printf("\r\x1b\x5b""2K%.1f per second", z / dt.count());
  44. fflush(stdout);
  45. }
  46. static void mpt_stat_record(const struct mpt_stat_entry &dp, size_t limit = 50)
  47. {
  48. mpt_stat_list.push_back(dp);
  49. if (mpt_stat_list.size() > limit)
  50. mpt_stat_list.pop_front();
  51. }
  52. static int mpt_setup_tick(void)
  53. {
  54. struct sigaction sa;
  55. sa.sa_handler = mpt_stat_dump;
  56. sa.sa_flags = SA_RESTART;
  57. sigemptyset(&sa.sa_mask);
  58. if (sigaction(SIGALRM, &sa, NULL) < 0) {
  59. perror("sigaction");
  60. return -errno;
  61. }
  62. struct sigevent sev;
  63. memset(&sev, 0, sizeof(sev));
  64. sev.sigev_notify = SIGEV_SIGNAL;
  65. sev.sigev_signo = SIGALRM;
  66. timer_t timerid;
  67. if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) < 0) {
  68. perror("timer_create");
  69. return -errno;
  70. }
  71. struct itimerspec it;
  72. it.it_interval.tv_sec = it.it_value.tv_sec = 1;
  73. it.it_interval.tv_nsec = it.it_value.tv_nsec = 0;
  74. if (timer_settime(timerid, 0, &it, NULL) < 0) {
  75. perror("timer_settime");
  76. return -errno;
  77. }
  78. return 1;
  79. }
  80. static int mpt_main_init(void)
  81. {
  82. if (mpt_setup_tick() < 0)
  83. return EXIT_FAILURE;
  84. struct mpt_stat_entry dp;
  85. while (mpt_repeat-- > 0) {
  86. clock_gettime(CLOCK_MONOTONIC, &dp.start);
  87. HRESULT ret = MAPIInitialize(NULL);
  88. if (ret == erSuccess)
  89. MAPIUninitialize();
  90. clock_gettime(CLOCK_MONOTONIC, &dp.stop);
  91. mpt_stat_record(dp);
  92. }
  93. return EXIT_SUCCESS;
  94. }
  95. static int mpt_main_login(void)
  96. {
  97. HRESULT ret = MAPIInitialize(NULL);
  98. if (ret != hrSuccess) {
  99. perror("MAPIInitialize");
  100. return EXIT_FAILURE;
  101. }
  102. int err = mpt_setup_tick();
  103. if (err < 0)
  104. return EXIT_FAILURE;
  105. struct mpt_stat_entry dp;
  106. while (mpt_repeat-- > 0) {
  107. object_ptr<IMAPISession> ses;
  108. clock_gettime(CLOCK_MONOTONIC, &dp.start);
  109. ret = HrOpenECSession(&~ses, "mapitime", "", mpt_user, mpt_pass,
  110. mpt_socket, 0, NULL, NULL);
  111. clock_gettime(CLOCK_MONOTONIC, &dp.stop);
  112. if (ret != hrSuccess) {
  113. fprintf(stderr, "Logon failed: %s\n", GetMAPIErrorMessage(ret));
  114. sleep(1);
  115. continue;
  116. }
  117. ses.reset();
  118. mpt_stat_record(dp);
  119. }
  120. MAPIUninitialize();
  121. return EXIT_SUCCESS;
  122. }
  123. static int mpt_main_lilo(void)
  124. {
  125. HRESULT ret = MAPIInitialize(NULL);
  126. if (ret != hrSuccess) {
  127. perror("MAPIInitialize");
  128. return EXIT_FAILURE;
  129. }
  130. int err = mpt_setup_tick();
  131. if (err < 0)
  132. return EXIT_FAILURE;
  133. struct mpt_stat_entry dp;
  134. while (mpt_repeat-- > 0) {
  135. object_ptr<IMAPISession> ses;
  136. clock_gettime(CLOCK_MONOTONIC, &dp.start);
  137. ret = HrOpenECSession(&~ses, "mapitime", "", mpt_user, mpt_pass,
  138. mpt_socket, 0, NULL, NULL);
  139. if (ret != hrSuccess) {
  140. fprintf(stderr, "Logon failed: %s\n", GetMAPIErrorMessage(ret));
  141. sleep(1);
  142. continue;
  143. }
  144. ses.reset();
  145. clock_gettime(CLOCK_MONOTONIC, &dp.stop);
  146. mpt_stat_record(dp);
  147. }
  148. MAPIUninitialize();
  149. return EXIT_SUCCESS;
  150. }
  151. static int mpt_main_vft(void)
  152. {
  153. AutoMAPI mapiinit;
  154. HRESULT ret = mapiinit.Initialize();
  155. if (ret != hrSuccess) {
  156. perror("MAPIInitialize");
  157. return EXIT_FAILURE;
  158. }
  159. int err = mpt_setup_tick();
  160. if (err < 0)
  161. return EXIT_FAILURE;
  162. struct mpt_stat_entry dp;
  163. static constexpr const SizedSPropTagArray(1, spta) = {1, {PR_ENTRYID}};
  164. object_ptr<ECMemTable> mt;
  165. ret = ECMemTable::Create(spta, PT_LONG, &~mt);
  166. if (ret != hrSuccess) {
  167. ec_log_err("ECMemTable::Create died");
  168. return EXIT_FAILURE;
  169. }
  170. ECMemTableView *view;
  171. ret = mt->HrGetView(createLocaleFromName(""), 0, &view);
  172. if (ret != hrSuccess) {
  173. ec_log_err("HrGetView died");
  174. return EXIT_FAILURE;
  175. }
  176. while (mpt_repeat-- > 0) {
  177. clock_gettime(CLOCK_MONOTONIC, &dp.start);
  178. IMAPITable *imt = NULL;
  179. IUnknown *iunk = NULL;
  180. view->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(&imt));
  181. view->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&iunk));
  182. imt->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(&imt));
  183. imt->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&iunk));
  184. iunk->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(&imt));
  185. iunk->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&iunk));
  186. clock_gettime(CLOCK_MONOTONIC, &dp.stop);
  187. mpt_stat_record(dp);
  188. }
  189. return EXIT_SUCCESS;
  190. }
  191. static int mpt_main_pagetime(int argc, char **argv)
  192. {
  193. if (argc < 2) {
  194. fprintf(stderr, "Need URL to test\n");
  195. return EXIT_FAILURE;
  196. }
  197. int err = mpt_setup_tick();
  198. if (err < 0)
  199. return EXIT_FAILURE;
  200. #ifndef HAVE_CURL_CURL_H
  201. fprintf(stderr, "Not built with curl support\n");
  202. return EXIT_FAILURE;
  203. #else
  204. auto curl = curl_easy_init();
  205. curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
  206. curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true);
  207. curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
  208. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, static_cast<curl_write_callback>([](char *, size_t, size_t n, void *) { return n; }));
  209. struct mpt_stat_entry dp;
  210. while (mpt_repeat-- > 0) {
  211. clock_gettime(CLOCK_MONOTONIC, &dp.start);
  212. curl_easy_perform(curl);
  213. clock_gettime(CLOCK_MONOTONIC, &dp.stop);
  214. mpt_stat_record(dp);
  215. }
  216. return EXIT_SUCCESS;
  217. #endif
  218. }
  219. static int mpt_main_exectime(int argc, char **argv)
  220. {
  221. if (argc < 2) {
  222. fprintf(stderr, "Need program to test\n");
  223. return EXIT_FAILURE;
  224. }
  225. --argc;
  226. ++argv; // skip "exectime"
  227. int err = mpt_setup_tick();
  228. if (err < 0)
  229. return EXIT_FAILURE;
  230. struct mpt_stat_entry dp;
  231. while (mpt_repeat-- > 0) {
  232. pid_t pid;
  233. int st;
  234. clock_gettime(CLOCK_MONOTONIC, &dp.start);
  235. if (posix_spawn(&pid, argv[0], nullptr, nullptr, const_cast<char **>(argv), nullptr) == 0)
  236. wait(&st);
  237. clock_gettime(CLOCK_MONOTONIC, &dp.stop);
  238. mpt_stat_record(dp);
  239. }
  240. return EXIT_SUCCESS;
  241. }
  242. static void mpt_usage(void)
  243. {
  244. fprintf(stderr, "mapitime [-p pass] [-s server] [-u username] [-z count] {init|lilo}\n");
  245. fprintf(stderr, " -z count Run this many iterations (default: finite but almost forever)\n");
  246. fprintf(stderr, "Benchmark choices:\n");
  247. fprintf(stderr, " init Just the library initialization\n");
  248. fprintf(stderr, " lilo Send login and logoff RPCs to the server\n");
  249. fprintf(stderr, " vft Measure C++ class dispatching\n");
  250. fprintf(stderr, " pagetime Measure webpage retrieval time\n");
  251. fprintf(stderr, " exectime Measure process runtime\n");
  252. }
  253. static int mpt_option_parse(int argc, char **argv)
  254. {
  255. const char *user = NULL, *pass = NULL;
  256. int c;
  257. if (argc < 2) {
  258. mpt_usage();
  259. return EXIT_FAILURE;
  260. }
  261. while ((c = getopt(argc, argv, "p:s:u:z:")) != -1) {
  262. if (c == 'p')
  263. pass = optarg;
  264. else if (c == 'u')
  265. user = optarg;
  266. else if (c == 's')
  267. mpt_socket = optarg;
  268. else if (c == 'z')
  269. mpt_repeat = strtoul(optarg, NULL, 0);
  270. else {
  271. fprintf(stderr, "Error: unknown option -%c\n", c);
  272. mpt_usage();
  273. }
  274. }
  275. if (user == NULL) {
  276. user = "foo";
  277. fprintf(stderr, "Info: defaulting to username \"foo\"\n");
  278. }
  279. mpt_userw = convert_to<std::wstring>(user);
  280. mpt_user = mpt_userw.c_str();
  281. if (pass == NULL) {
  282. pass = "xfoo";
  283. fprintf(stderr, "Info: defaulting to password \"xfoo\"\n");
  284. }
  285. mpt_passw = convert_to<std::wstring>(pass);
  286. mpt_pass = mpt_passw.c_str();
  287. if (mpt_socket == NULL) {
  288. mpt_socket = "http://localhost:236/";
  289. fprintf(stderr, "Info: defaulting to %s\n", mpt_socket);
  290. }
  291. return EXIT_SUCCESS;
  292. }
  293. int main(int argc, char **argv)
  294. {
  295. int ret = mpt_option_parse(argc, argv);
  296. if (ret != EXIT_SUCCESS)
  297. return ret;
  298. argv += optind - 1;
  299. if (strcmp(argv[1], "init") == 0 || strcmp(argv[1], "i") == 0)
  300. return mpt_main_init();
  301. else if (strcmp(argv[1], "li") == 0)
  302. return mpt_main_login();
  303. else if (strcmp(argv[1], "lilo") == 0)
  304. return mpt_main_lilo();
  305. else if (strcmp(argv[1], "vft") == 0)
  306. return mpt_main_vft();
  307. else if (strcmp(argv[1], "exectime") == 0)
  308. return mpt_main_exectime(argc - 1, argv + 1);
  309. else if (strcmp(argv[1], "pagetime") == 0)
  310. return mpt_main_pagetime(argc - 1, argv + 1);
  311. mpt_usage();
  312. return EXIT_FAILURE;
  313. }