123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- #include "config.h"
- #include <chrono>
- #include <cerrno>
- #include <csignal>
- #include <cstdio>
- #include <cstdlib>
- #include <ctime>
- #include <getopt.h>
- #include <spawn.h>
- #include <kopano/CommonUtil.h>
- #include <kopano/ECLogger.h>
- #include <kopano/MAPIErrors.h>
- #include <kopano/charset/convert.h>
- #include <kopano/ECMemTable.h>
- #include <kopano/automapi.hpp>
- #include <kopano/memory.hpp>
- #ifdef HAVE_CURL_CURL_H
- # include <curl/curl.h>
- #endif
- struct mpt_stat_entry {
- struct timespec start, stop;
- };
- using namespace KCHL;
- static std::list<struct mpt_stat_entry> mpt_stat_list;
- static std::wstring mpt_userw, mpt_passw;
- static const wchar_t *mpt_user, *mpt_pass;
- static const char *mpt_socket;
- static size_t mpt_repeat = ~0U;
- static void mpt_stat_dump(int s = 0)
- {
- size_t z = mpt_stat_list.size();
- if (z == 0)
- return;
- const struct mpt_stat_entry &first = *mpt_stat_list.begin();
- const struct mpt_stat_entry &last = *mpt_stat_list.rbegin();
- typedef std::chrono::seconds sec;
- typedef std::chrono::nanoseconds nsec;
- auto dt = std::chrono::duration<double>(
- sec(last.stop.tv_sec) + nsec(last.stop.tv_nsec) -
- (sec(first.start.tv_sec) + nsec(first.start.tv_nsec)));
- if (dt.count() == 0)
- return;
- printf("\r\x1b\x5b""2K%.1f per second", z / dt.count());
- fflush(stdout);
- }
- static void mpt_stat_record(const struct mpt_stat_entry &dp, size_t limit = 50)
- {
- mpt_stat_list.push_back(dp);
- if (mpt_stat_list.size() > limit)
- mpt_stat_list.pop_front();
- }
- static int mpt_setup_tick(void)
- {
- struct sigaction sa;
- sa.sa_handler = mpt_stat_dump;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIGALRM, &sa, NULL) < 0) {
- perror("sigaction");
- return -errno;
- }
- struct sigevent sev;
- memset(&sev, 0, sizeof(sev));
- sev.sigev_notify = SIGEV_SIGNAL;
- sev.sigev_signo = SIGALRM;
- timer_t timerid;
- if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) < 0) {
- perror("timer_create");
- return -errno;
- }
- struct itimerspec it;
- it.it_interval.tv_sec = it.it_value.tv_sec = 1;
- it.it_interval.tv_nsec = it.it_value.tv_nsec = 0;
- if (timer_settime(timerid, 0, &it, NULL) < 0) {
- perror("timer_settime");
- return -errno;
- }
- return 1;
- }
- static int mpt_main_init(void)
- {
- if (mpt_setup_tick() < 0)
- return EXIT_FAILURE;
- struct mpt_stat_entry dp;
- while (mpt_repeat-- > 0) {
- clock_gettime(CLOCK_MONOTONIC, &dp.start);
- HRESULT ret = MAPIInitialize(NULL);
- if (ret == erSuccess)
- MAPIUninitialize();
- clock_gettime(CLOCK_MONOTONIC, &dp.stop);
- mpt_stat_record(dp);
- }
- return EXIT_SUCCESS;
- }
- static int mpt_main_login(void)
- {
- HRESULT ret = MAPIInitialize(NULL);
- if (ret != hrSuccess) {
- perror("MAPIInitialize");
- return EXIT_FAILURE;
- }
- int err = mpt_setup_tick();
- if (err < 0)
- return EXIT_FAILURE;
- struct mpt_stat_entry dp;
- while (mpt_repeat-- > 0) {
- object_ptr<IMAPISession> ses;
- clock_gettime(CLOCK_MONOTONIC, &dp.start);
- ret = HrOpenECSession(&~ses, "mapitime", "", mpt_user, mpt_pass,
- mpt_socket, 0, NULL, NULL);
- clock_gettime(CLOCK_MONOTONIC, &dp.stop);
- if (ret != hrSuccess) {
- fprintf(stderr, "Logon failed: %s\n", GetMAPIErrorMessage(ret));
- sleep(1);
- continue;
- }
- ses.reset();
- mpt_stat_record(dp);
- }
- MAPIUninitialize();
- return EXIT_SUCCESS;
- }
- static int mpt_main_lilo(void)
- {
- HRESULT ret = MAPIInitialize(NULL);
- if (ret != hrSuccess) {
- perror("MAPIInitialize");
- return EXIT_FAILURE;
- }
- int err = mpt_setup_tick();
- if (err < 0)
- return EXIT_FAILURE;
- struct mpt_stat_entry dp;
- while (mpt_repeat-- > 0) {
- object_ptr<IMAPISession> ses;
- clock_gettime(CLOCK_MONOTONIC, &dp.start);
- ret = HrOpenECSession(&~ses, "mapitime", "", mpt_user, mpt_pass,
- mpt_socket, 0, NULL, NULL);
- if (ret != hrSuccess) {
- fprintf(stderr, "Logon failed: %s\n", GetMAPIErrorMessage(ret));
- sleep(1);
- continue;
- }
- ses.reset();
- clock_gettime(CLOCK_MONOTONIC, &dp.stop);
- mpt_stat_record(dp);
- }
- MAPIUninitialize();
- return EXIT_SUCCESS;
- }
- static int mpt_main_vft(void)
- {
- AutoMAPI mapiinit;
- HRESULT ret = mapiinit.Initialize();
- if (ret != hrSuccess) {
- perror("MAPIInitialize");
- return EXIT_FAILURE;
- }
- int err = mpt_setup_tick();
- if (err < 0)
- return EXIT_FAILURE;
- struct mpt_stat_entry dp;
- static constexpr const SizedSPropTagArray(1, spta) = {1, {PR_ENTRYID}};
- object_ptr<ECMemTable> mt;
- ret = ECMemTable::Create(spta, PT_LONG, &~mt);
- if (ret != hrSuccess) {
- ec_log_err("ECMemTable::Create died");
- return EXIT_FAILURE;
- }
- ECMemTableView *view;
- ret = mt->HrGetView(createLocaleFromName(""), 0, &view);
- if (ret != hrSuccess) {
- ec_log_err("HrGetView died");
- return EXIT_FAILURE;
- }
- while (mpt_repeat-- > 0) {
- clock_gettime(CLOCK_MONOTONIC, &dp.start);
- IMAPITable *imt = NULL;
- IUnknown *iunk = NULL;
- view->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(&imt));
- view->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&iunk));
- imt->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(&imt));
- imt->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&iunk));
- iunk->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(&imt));
- iunk->QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&iunk));
- clock_gettime(CLOCK_MONOTONIC, &dp.stop);
- mpt_stat_record(dp);
- }
- return EXIT_SUCCESS;
- }
- static int mpt_main_pagetime(int argc, char **argv)
- {
- if (argc < 2) {
- fprintf(stderr, "Need URL to test\n");
- return EXIT_FAILURE;
- }
- int err = mpt_setup_tick();
- if (err < 0)
- return EXIT_FAILURE;
- #ifndef HAVE_CURL_CURL_H
- fprintf(stderr, "Not built with curl support\n");
- return EXIT_FAILURE;
- #else
- auto curl = curl_easy_init();
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true);
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true);
- curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, static_cast<curl_write_callback>([](char *, size_t, size_t n, void *) { return n; }));
- struct mpt_stat_entry dp;
- while (mpt_repeat-- > 0) {
- clock_gettime(CLOCK_MONOTONIC, &dp.start);
- curl_easy_perform(curl);
- clock_gettime(CLOCK_MONOTONIC, &dp.stop);
- mpt_stat_record(dp);
- }
- return EXIT_SUCCESS;
- #endif
- }
- static int mpt_main_exectime(int argc, char **argv)
- {
- if (argc < 2) {
- fprintf(stderr, "Need program to test\n");
- return EXIT_FAILURE;
- }
- --argc;
- ++argv; // skip "exectime"
- int err = mpt_setup_tick();
- if (err < 0)
- return EXIT_FAILURE;
- struct mpt_stat_entry dp;
- while (mpt_repeat-- > 0) {
- pid_t pid;
- int st;
- clock_gettime(CLOCK_MONOTONIC, &dp.start);
- if (posix_spawn(&pid, argv[0], nullptr, nullptr, const_cast<char **>(argv), nullptr) == 0)
- wait(&st);
- clock_gettime(CLOCK_MONOTONIC, &dp.stop);
- mpt_stat_record(dp);
- }
- return EXIT_SUCCESS;
- }
- static void mpt_usage(void)
- {
- fprintf(stderr, "mapitime [-p pass] [-s server] [-u username] [-z count] {init|lilo}\n");
- fprintf(stderr, " -z count Run this many iterations (default: finite but almost forever)\n");
- fprintf(stderr, "Benchmark choices:\n");
- fprintf(stderr, " init Just the library initialization\n");
- fprintf(stderr, " lilo Send login and logoff RPCs to the server\n");
- fprintf(stderr, " vft Measure C++ class dispatching\n");
- fprintf(stderr, " pagetime Measure webpage retrieval time\n");
- fprintf(stderr, " exectime Measure process runtime\n");
- }
- static int mpt_option_parse(int argc, char **argv)
- {
- const char *user = NULL, *pass = NULL;
- int c;
- if (argc < 2) {
- mpt_usage();
- return EXIT_FAILURE;
- }
- while ((c = getopt(argc, argv, "p:s:u:z:")) != -1) {
- if (c == 'p')
- pass = optarg;
- else if (c == 'u')
- user = optarg;
- else if (c == 's')
- mpt_socket = optarg;
- else if (c == 'z')
- mpt_repeat = strtoul(optarg, NULL, 0);
- else {
- fprintf(stderr, "Error: unknown option -%c\n", c);
- mpt_usage();
- }
- }
- if (user == NULL) {
- user = "foo";
- fprintf(stderr, "Info: defaulting to username \"foo\"\n");
- }
- mpt_userw = convert_to<std::wstring>(user);
- mpt_user = mpt_userw.c_str();
- if (pass == NULL) {
- pass = "xfoo";
- fprintf(stderr, "Info: defaulting to password \"xfoo\"\n");
- }
- mpt_passw = convert_to<std::wstring>(pass);
- mpt_pass = mpt_passw.c_str();
- if (mpt_socket == NULL) {
- mpt_socket = "http://localhost:236/";
- fprintf(stderr, "Info: defaulting to %s\n", mpt_socket);
- }
- return EXIT_SUCCESS;
- }
- int main(int argc, char **argv)
- {
- int ret = mpt_option_parse(argc, argv);
- if (ret != EXIT_SUCCESS)
- return ret;
- argv += optind - 1;
- if (strcmp(argv[1], "init") == 0 || strcmp(argv[1], "i") == 0)
- return mpt_main_init();
- else if (strcmp(argv[1], "li") == 0)
- return mpt_main_login();
- else if (strcmp(argv[1], "lilo") == 0)
- return mpt_main_lilo();
- else if (strcmp(argv[1], "vft") == 0)
- return mpt_main_vft();
- else if (strcmp(argv[1], "exectime") == 0)
- return mpt_main_exectime(argc - 1, argv + 1);
- else if (strcmp(argv[1], "pagetime") == 0)
- return mpt_main_pagetime(argc - 1, argv + 1);
- mpt_usage();
- return EXIT_FAILURE;
- }
|