Add USDT sample (#1229)
[platform/upstream/bcc.git] / examples / usdt_sample / usdt_sample_app1 / main.cpp
1 // std
2 #include <algorithm>
3 #include <cstdlib>
4 #include <iostream>
5 #include <mutex>
6 #include <queue>
7 #include <random>
8 #include <sstream>
9 #include <string>
10 #include <thread>
11
12 // gnu-c
13 #include <sys/types.h>
14 #include <unistd.h>
15
16 // usdt_sample_lib1
17 #include "usdt_sample_lib1/lib1.h"
18
19 void print_usage(int argc, char** argv)
20 {
21     std::cout << "Usage:" << std::endl;
22     std::cout << argv[0]
23               << " <InputPrefix> <InputMinimum (1-50)> <InputMaximum (1-50)> <CallsPerSec (1-50)> <MinimumLatencyMs (1-50)> <MaximumLatencyMs (1-50)>"
24               << std::endl;
25     std::cout << "InputPrefix: Prefix of the input string to the operation. Default: dummy" << std::endl;
26     std::cout << "InputMinimum: Minimum number to make the input string to the operation somewhat unique. Default: 1" << std::endl;
27     std::cout << "InputMaximum: Maximum number to make the input string to the operation somewhat unique. Default: 50" << std::endl;
28     std::cout << "CallsPerSec: Rate of calls to the operation. Default: 10" << std::endl;
29     std::cout << "MinimumLatencyMs: Minimum latency to apply to the operation. Default: 20" << std::endl;
30     std::cout << "MaximumLatencyMs: Maximum latency to apply to the operation. Default: 40" << std::endl;
31 }
32
33 int main(int argc, char** argv)
34 {
35     std::string inputPrefix("dummy");
36     std::uint32_t inputMinimum = 1;
37     std::uint32_t inputMaximum = 50;
38     std::uint32_t callsPerSec = 10;
39     std::uint32_t minLatMs = 20;
40     std::uint32_t maxLatMs = 40;
41
42     try {
43         if (argc > 1) {
44             inputPrefix = argv[1];
45         }
46
47         if (argc > 2) {
48             inputMinimum = static_cast<std::uint32_t>(std::max(1, std::min(50, std::atoi(argv[2]))));
49         }
50
51         if (argc > 3) {
52             inputMaximum = static_cast<std::uint32_t>(std::max(1, std::min(50, std::atoi(argv[3]))));
53         }
54
55         if (argc > 4) {
56             callsPerSec = static_cast<std::uint32_t>(std::max(1, std::min(50, std::atoi(argv[4]))));
57         }
58
59         if (argc > 5) {
60             minLatMs = static_cast<std::uint32_t>(std::max(1, std::min(50, std::atoi(argv[5]))));
61         }
62
63         if (argc > 6) {
64             maxLatMs = static_cast<std::uint32_t>(std::max(1, std::min(50, std::atoi(argv[6]))));
65         }
66     }
67     catch (const std::exception& exc) {
68         std::cout << "Exception while reading arguments: " << exc.what() << std::endl;
69         print_usage(argc, argv);
70         return -1;
71     }
72     catch (...) {
73         std::cout << "Unknown exception while reading arguments." << std::endl;
74         print_usage(argc, argv);
75         return -1;
76     }
77
78     if (inputMinimum > inputMaximum) {
79         std::cout << "InputMinimum must be smaller than InputMaximum." << std::endl;
80         print_usage(argc, argv);
81         return -1;
82     }
83
84     if (minLatMs > maxLatMs) {
85         std::cout << "MinimumLatencyMs must be smaller than MaximumLatencyMs." << std::endl;
86         print_usage(argc, argv);
87         return -1;
88     }
89
90     std::cout << "Applying the following parameters:" << std::endl
91               << "Input prefix: " << inputPrefix << "." << std::endl
92               << "Input range: [" << inputMinimum << ", " << inputMaximum << "]." << std::endl
93               << "Calls Per Second: " << callsPerSec << "." << std::endl
94               << "Latency range: [" << minLatMs << ", " << maxLatMs << "] ms." << std::endl;
95
96     const int sleepTimeMs = 1000 / callsPerSec;
97     OperationProvider op(minLatMs, maxLatMs);
98
99     std::mutex queueMutex;
100     std::queue<std::shared_future<OperationResponse>> responseQueue;
101
102     auto dequeueFuture = std::async(std::launch::async, [&]() {
103         while (true) {
104             bool empty = false;
105             {
106                 std::lock_guard<std::mutex> lg(queueMutex);
107                 empty = responseQueue.empty();
108             }
109
110             if (empty) {
111                 std::this_thread::sleep_for(std::chrono::milliseconds(sleepTimeMs));
112                 continue;
113             }
114
115             responseQueue.front().get();
116
117             // std::cout << "Removing item from queue." << std::endl;
118             std::lock_guard<std::mutex> lg(queueMutex);
119             responseQueue.pop();
120         }
121     });
122
123     std::random_device rd;
124     std::uniform_int_distribution<> dis(inputMinimum, inputMaximum);
125
126     std::cout << "You can now run the bcc scripts, see usdt_sample.md for examples." << std::endl;
127     std::cout << "pid: " << ::getpid() << std::endl;
128     std::cout << "Press ctrl-c to exit." << std::endl;
129     while (true) {
130         std::ostringstream inputOss;
131         inputOss << inputPrefix << "_" << dis(rd);
132         auto responseFuture = op.executeAsync(OperationRequest(inputOss.str()));
133
134         {
135             std::lock_guard<std::mutex> lg(queueMutex);
136             responseQueue.push(responseFuture);
137         }
138
139         // For a sample application, this is good enough to simulate callsPerSec.
140         std::this_thread::sleep_for(std::chrono::milliseconds(sleepTimeMs));
141     }
142
143     dequeueFuture.get();
144     return 0;
145 }