summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/binder/tests/binderThroughputTest.cpp160
1 files changed, 109 insertions, 51 deletions
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 6e8f7df84d..455f2c418d 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -101,18 +101,21 @@ public:
};
static const uint32_t num_buckets = 128;
-static const uint64_t max_time_bucket = 50ull * 1000000;
-static const uint64_t time_per_bucket = max_time_bucket / num_buckets;
-static constexpr float time_per_bucket_ms = time_per_bucket / 1.0E6;
+static uint64_t max_time_bucket = 50ull * 1000000;
+static uint64_t time_per_bucket = max_time_bucket / num_buckets;
struct ProcResults {
- uint64_t m_best = max_time_bucket;
uint64_t m_worst = 0;
uint32_t m_buckets[num_buckets] = {0};
uint64_t m_transactions = 0;
+ uint64_t m_long_transactions = 0;
uint64_t m_total_time = 0;
+ uint64_t m_best = max_time_bucket;
void add_time(uint64_t time) {
+ if (time > max_time_bucket) {
+ m_long_transactions++;
+ }
m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1;
m_best = min(time, m_best);
m_worst = max(time, m_worst);
@@ -127,16 +130,24 @@ struct ProcResults {
ret.m_worst = max(a.m_worst, b.m_worst);
ret.m_best = min(a.m_best, b.m_best);
ret.m_transactions = a.m_transactions + b.m_transactions;
+ ret.m_long_transactions = a.m_long_transactions + b.m_long_transactions;
ret.m_total_time = a.m_total_time + b.m_total_time;
return ret;
}
void dump() {
+ if (m_long_transactions > 0) {
+ cout << (double)m_long_transactions / m_transactions << "% of transactions took longer "
+ "than estimated max latency. Consider setting -m to be higher than "
+ << m_worst / 1000 << " microseconds" << endl;
+ }
+
double best = (double)m_best / 1.0E6;
double worst = (double)m_worst / 1.0E6;
double average = (double)m_total_time / m_transactions / 1.0E6;
cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl;
uint64_t cur_total = 0;
+ float time_per_bucket_ms = time_per_bucket / 1.0E6;
for (int i = 0; i < num_buckets; i++) {
float cur_time = time_per_bucket_ms * i + 0.5f * time_per_bucket_ms;
if ((cur_total < 0.5f * m_transactions) && (cur_total + m_buckets[i] >= 0.5f * m_transactions)) {
@@ -154,7 +165,6 @@ struct ProcResults {
cur_total += m_buckets[i];
}
cout << endl;
-
}
};
@@ -166,13 +176,12 @@ String16 generateServiceName(int num)
return serviceName;
}
-void worker_fx(
- int num,
- int worker_count,
- int iterations,
- int payload_size,
- bool cs_pair,
- Pipe p)
+void worker_fx(int num,
+ int worker_count,
+ int iterations,
+ int payload_size,
+ bool cs_pair,
+ Pipe p)
{
// Create BinderWorkerService and for go.
ProcessState::self()->startThreadPool();
@@ -204,12 +213,12 @@ void worker_fx(
for (int i = 0; (!cs_pair || num >= server_count) && i < iterations; i++) {
Parcel data, reply;
int target = cs_pair ? num % server_count : rand() % workers.size();
- int sz = payload_size;
+ int sz = payload_size;
- while (sz > sizeof(uint32_t)) {
- data.writeInt32(0);
- sz -= sizeof(uint32_t);
- }
+ while (sz > sizeof(uint32_t)) {
+ data.writeInt32(0);
+ sz -= sizeof(uint32_t);
+ }
start = chrono::high_resolution_clock::now();
status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
end = chrono::high_resolution_clock::now();
@@ -264,47 +273,19 @@ void signal_all(vector<Pipe>& v)
}
}
-int main(int argc, char *argv[])
+void run_main(int iterations,
+ int workers,
+ int payload_size,
+ int cs_pair,
+ bool training_round=false)
{
- int workers = 2;
- int iterations = 10000;
- int payload_size = 0;
- bool cs_pair = false;
- (void)argc;
- (void)argv;
vector<Pipe> pipes;
-
- // Parse arguments.
- for (int i = 1; i < argc; i++) {
- if (string(argv[i]) == "-w") {
- workers = atoi(argv[i+1]);
- i++;
- continue;
- }
- if (string(argv[i]) == "-i") {
- iterations = atoi(argv[i+1]);
- i++;
- continue;
- }
- if (string(argv[i]) == "-s") {
- payload_size = atoi(argv[i+1]);
- i++;
- }
- if (string(argv[i]) == "-p") {
- // client/server pairs instead of spreading
- // requests to all workers. If true, half
- // the workers become clients and half servers
- cs_pair = true;
- }
- }
-
// Create all the workers and wait for them to spawn.
for (int i = 0; i < workers; i++) {
pipes.push_back(make_worker(i, iterations, workers, payload_size, cs_pair));
}
wait_all(pipes);
-
// Run the workers and wait for completion.
chrono::time_point<chrono::high_resolution_clock> start, end;
cout << "waiting for workers to complete" << endl;
@@ -326,7 +307,6 @@ int main(int argc, char *argv[])
pipes[i].recv(tmp_results);
tot_results = ProcResults::combine(tot_results, tmp_results);
}
- tot_results.dump();
// Kill all the workers.
cout << "killing workers" << endl;
@@ -338,5 +318,83 @@ int main(int argc, char *argv[])
cout << "nonzero child status" << status << endl;
}
}
+ if (training_round) {
+ // sets max_time_bucket to 2 * m_worst from the training round.
+ // Also needs to adjust time_per_bucket accordingly.
+ max_time_bucket = 2 * tot_results.m_worst;
+ time_per_bucket = max_time_bucket / num_buckets;
+ cout << "Max latency during training: " << tot_results.m_worst / 1.0E6 << "ms" << endl;
+ } else {
+ tot_results.dump();
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int workers = 2;
+ int iterations = 10000;
+ int payload_size = 0;
+ bool cs_pair = false;
+ bool training_round = false;
+ (void)argc;
+ (void)argv;
+
+ // Parse arguments.
+ for (int i = 1; i < argc; i++) {
+ if (string(argv[i]) == "--help") {
+ cout << "Usage: binderThroughputTest [OPTIONS]" << endl;
+ cout << "\t-i N : Specify number of iterations." << endl;
+ cout << "\t-m N : Specify expected max latency in microseconds." << endl;
+ cout << "\t-p : Split workers into client/server pairs." << endl;
+ cout << "\t-s N : Specify payload size." << endl;
+ cout << "\t-t N : Run training round." << endl;
+ cout << "\t-w N : Specify total number of workers." << endl;
+ return 0;
+ }
+ if (string(argv[i]) == "-w") {
+ workers = atoi(argv[i+1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-i") {
+ iterations = atoi(argv[i+1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-s") {
+ payload_size = atoi(argv[i+1]);
+ i++;
+ }
+ if (string(argv[i]) == "-p") {
+ // client/server pairs instead of spreading
+ // requests to all workers. If true, half
+ // the workers become clients and half servers
+ cs_pair = true;
+ }
+ if (string(argv[i]) == "-t") {
+ // Run one training round before actually collecting data
+ // to get an approximation of max latency.
+ training_round = true;
+ }
+ if (string(argv[i]) == "-m") {
+ // Caller specified the max latency in microseconds.
+ // No need to run training round in this case.
+ if (atoi(argv[i+1]) > 0) {
+ max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000;
+ i++;
+ } else {
+ cout << "Max latency -m must be positive." << endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ if (training_round) {
+ cout << "Start training round" << endl;
+ run_main(iterations, workers, payload_size, cs_pair, training_round=true);
+ cout << "Completed training round" << endl << endl;
+ }
+
+ run_main(iterations, workers, payload_size, cs_pair);
return 0;
}