blob: 17fca091ac0915eed010ea401056914e07d39f59 [file] [log] [blame]
John Reckb89a6342016-05-05 10:16:09 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package test.amslam;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.os.SystemClock;
23import android.os.Bundle;
24import android.text.method.ScrollingMovementMethod;
25import android.util.Log;
26import android.view.View;
27import android.widget.TextView;
28
29import java.util.Queue;
30import java.util.concurrent.ArrayBlockingQueue;
31import java.util.concurrent.BlockingQueue;
32import java.util.concurrent.ConcurrentLinkedQueue;
33
34public class MainActivity extends Activity implements PongReceiver.PingPongResponseListener {
35 private static final String TAG = "AmSlam";
36
37 private static final Class<?>[] sTargets;
38 private static final BlockingQueue<Intent> sWorkQueue = new ArrayBlockingQueue<>(100);
39 private static Context sAppContext;
40 private static final int[] CONCURRENT_TESTS = {1, 2, 4, 6, 8, 10};
41
42 private boolean mAutoRun;
43
44 private TextView mOutput;
45
46 private int mTestPhase;
47 private long mBatchStartTime;
48 private int mPendingResponses;
49
50 private int mBatchRemaining;
51 private int mCurrentTargetIndex;
52
53 private int mTotalReceived;
54 private long mTotalTime;
55 private long mTotalPingTime;
56 private long mTotalPongTime;
57
58 @Override
59 protected void onCreate(Bundle savedInstanceState) {
60 super.onCreate(savedInstanceState);
61 sAppContext = getApplicationContext();
62 setContentView(R.layout.activity_main);
Alan Viverette51efddb2017-04-05 10:00:01 -040063 mOutput = findViewById(R.id.output);
John Reckb89a6342016-05-05 10:16:09 -070064 PongReceiver.addListener(this);
65
66 findViewById(R.id.run).setOnClickListener(view -> {
67 view.setEnabled(false);
68 mOutput.setText("");
69 startBatch();
70 });
71
72 mAutoRun = getIntent().getBooleanExtra("autorun", false);
73 if (mAutoRun) {
74 findViewById(R.id.run).performClick();
75 }
76 }
77
78 @Override
79 protected void onDestroy() {
80 super.onDestroy();
81 PongReceiver.removeListener(this);
82 }
83
84 private void startBatch() {
85 if (mBatchRemaining > 0 || mPendingResponses > 0) {
86 // Still sending, skip
87 return;
88 }
89 mBatchStartTime = SystemClock.uptimeMillis();
90 mBatchRemaining = 10 * CONCURRENT_TESTS[mTestPhase];
91 mTotalReceived = 0;
92 mTotalTime = mTotalPingTime = mTotalPongTime = 0;
93 log("Starting test with " + CONCURRENT_TESTS[mTestPhase] + " concurrent requests...\n");
94 continueSend();
95 }
96
97 private Class<?> nextTarget() {
98 Class<?> ret = sTargets[mCurrentTargetIndex];
99 mCurrentTargetIndex = (mCurrentTargetIndex + 1) % sTargets.length;
100 return ret;
101 }
102
103 private void continueSend() {
104 while (mPendingResponses < CONCURRENT_TESTS[mTestPhase] && mBatchRemaining > 0) {
105 mPendingResponses++;
106 mBatchRemaining--;
107 Class<?> target = nextTarget();
108 Intent intent = new Intent(getApplicationContext(), target);
109 try {
110 sWorkQueue.put(intent);
111 } catch (InterruptedException e) {
112 throw new RuntimeException(e);
113 }
114 }
115 }
116
117 @Override
118 public void onPingPongResponse(long send, long bounce, long recv, String remote) {
119 if (send < mBatchStartTime || mPendingResponses == 0) {
120 Log.e(TAG, "received outdated response??");
121 Log.e(TAG, "send " + send + ", bounce " + bounce + ", recv " + recv
122 + ", batchStart " + mBatchStartTime + ", remote: " + remote);
123 }
124 mPendingResponses--;
125 mTotalReceived++;
126 continueSend();
127 mTotalTime += (recv - send);
128 mTotalPingTime += (bounce - send);
129 mTotalPongTime += (recv - bounce);
130 if (mPendingResponses == 0) {
131 long now = SystemClock.uptimeMillis();
132 log(String.format("Sent %d ping/pongs, %d concurrent.\n"
133 + "Total duration %dms (%dms eff. avg)\n"
134 + "Average message took %dms (%dms + %dms)\n",
135 mTotalReceived, CONCURRENT_TESTS[mTestPhase],
136 (now - mBatchStartTime), (now - mBatchStartTime) / mTotalReceived,
137 mTotalTime / mTotalReceived, mTotalPingTime / mTotalReceived,
138 mTotalPongTime / mTotalReceived));
139
140 mTestPhase++;
141 if (mTestPhase < CONCURRENT_TESTS.length) {
142 startBatch();
143 } else {
144 mTestPhase = 0;
145 log("Finished\n");
146 findViewById(R.id.run).setEnabled(true);
147 if (mAutoRun) {
148 finish();
149 }
150 }
151 }
152 }
153
154 private void log(String text) {
155 mOutput.append(text);
156 Log.d(TAG, text);
157 }
158
159 static {
160 sTargets = new Class<?>[100];
161 for (int i = 0; i < sTargets.length; i++) {
162 try {
163 sTargets[i] = Class.forName(
164 String.format("test.amslam.subreceivers.PingReceiver%03d", i));
165 } catch (ClassNotFoundException e) {
166 throw new RuntimeException(e);
167 }
168 }
169
170 Runnable work = () -> {
171 while (true) {
172 try {
173 Intent intent = sWorkQueue.take();
174 intent.putExtra("start_time", SystemClock.uptimeMillis());
175 sAppContext.startService(intent);
176 } catch (InterruptedException e) {}
177 }
178 };
179
180 // How many worker threads should we spawn? ¯\_(ツ)_/¯
181 for (int i = 0; i < 10; i++) {
182 new Thread(work, "Slammer" + i).start();
183 }
184 }
185}