#include #include #include #include #include #include #include /* 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 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 *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(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 results; std::vector 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; }