PPaste!

lt

Home - All the pastes - Authored by Thooms

Raw version

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#include <chrono>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

#include <curl/curl.h>

/* We'll need a mutex at some point to avoid race conditions */
std::mutex mtx;

/* Diry hack to avoid cURL polluting STDOUT */
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
    return size * nmemb;
}

/* Abstract type encoding a request result */
typedef struct {
    std::chrono::duration<double, std::milli> t; /* Time to process the request */
    long return_code; /* Return code of the request */
} Result;

void make_request(std::string url, int max_tries, std::vector<Result> *shared_results) {
    CURL *curl;
    CURLcode res;
    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);

        for (int i = 0; i < max_tries; i++) {
            /* Start timer */
            auto t_start = std::chrono::high_resolution_clock::now();

            /* Make request */
            res = curl_easy_perform(curl);

            /* Stop timer */
            auto t_end = std::chrono::high_resolution_clock::now();

            /* Register result */
            Result result;
            result.t = std::chrono::duration<double, std::milli>(t_end - t_start);
            curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &result.return_code);

            mtx.lock();
            shared_results->push_back(result);
            mtx.unlock();
        }
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
}

void lt(std::string url, int n_threads, int n_requests) {
    std::vector<Result> results;
    std::vector<std::thread> threads; /* Handmade threadpool */

    for (int i = 0; i < n_threads; i++)
        threads.push_back(std::thread(make_request, url, n_requests, &results));

    std::cout << "[LT] Launched " << n_threads
              << " threads (" << n_requests
              << " requests each)." << std::endl;

    for (auto& th : threads)
        th.join();

    std::cout << "[LT] Finished." << std::endl;

    /* Average response time */
    double avg = 0.f;
    for (auto& res : results) {
        avg += res.t.count();
    }
    avg /= results.size();
    std::cout << "[LT] Average response time: " << avg << " ms" << std::endl;

    /* Number of successful calls */
    int success = 0;
    for (auto& res : results)
        if (res.return_code == 200)
            success++;
    std::cout << "[LT] " << success << " OK responses ("
              << (double)success / (double)results.size() * 100.f
              << "%)" << std::endl;
}

int main(int argc, char* argv[]) {
    if (argc < 4)
        std::cout << "Usage: " << argv[0] << " URL N_THREADS N_REQUESTS" << std::endl;
    else {
        std::string url(argv[1]);
        int n_threads = std::atoi(argv[2]);
        int n_requests = std::atoi(argv[3]);
        lt(url, n_threads, n_requests);
    }

    return EXIT_SUCCESS;
}