2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.SystemClock;
23 import android.os.Bundle;
24 import android.text.method.ScrollingMovementMethod;
25 import android.util.Log;
26 import android.view.View;
27 import android.widget.TextView;
29 import java.util.Queue;
30 import java.util.concurrent.ArrayBlockingQueue;
31 import java.util.concurrent.BlockingQueue;
32 import java.util.concurrent.ConcurrentLinkedQueue;
34 public class MainActivity extends Activity implements PongReceiver.PingPongResponseListener {
35 private static final String TAG = "AmSlam";
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};
42 private boolean mAutoRun;
44 private TextView mOutput;
46 private int mTestPhase;
47 private long mBatchStartTime;
48 private int mPendingResponses;
50 private int mBatchRemaining;
51 private int mCurrentTargetIndex;
53 private int mTotalReceived;
54 private long mTotalTime;
55 private long mTotalPingTime;
56 private long mTotalPongTime;
59 protected void onCreate(Bundle savedInstanceState) {
60 super.onCreate(savedInstanceState);
61 sAppContext = getApplicationContext();
62 setContentView(R.layout.activity_main);
63 mOutput = findViewById(R.id.output);
64 PongReceiver.addListener(this);
66 findViewById(R.id.run).setOnClickListener(view -> {
67 view.setEnabled(false);
72 mAutoRun = getIntent().getBooleanExtra("autorun", false);
74 findViewById(R.id.run).performClick();
79 protected void onDestroy() {
81 PongReceiver.removeListener(this);
84 private void startBatch() {
85 if (mBatchRemaining > 0 || mPendingResponses > 0) {
86 // Still sending, skip
89 mBatchStartTime = SystemClock.uptimeMillis();
90 mBatchRemaining = 10 * CONCURRENT_TESTS[mTestPhase];
92 mTotalTime = mTotalPingTime = mTotalPongTime = 0;
93 log("Starting test with " + CONCURRENT_TESTS[mTestPhase] + " concurrent requests...\n");
97 private Class<?> nextTarget() {
98 Class<?> ret = sTargets[mCurrentTargetIndex];
99 mCurrentTargetIndex = (mCurrentTargetIndex + 1) % sTargets.length;
103 private void continueSend() {
104 while (mPendingResponses < CONCURRENT_TESTS[mTestPhase] && mBatchRemaining > 0) {
107 Class<?> target = nextTarget();
108 Intent intent = new Intent(getApplicationContext(), target);
110 sWorkQueue.put(intent);
111 } catch (InterruptedException e) {
112 throw new RuntimeException(e);
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);
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));
141 if (mTestPhase < CONCURRENT_TESTS.length) {
146 findViewById(R.id.run).setEnabled(true);
154 private void log(String text) {
155 mOutput.append(text);
160 sTargets = new Class<?>[100];
161 for (int i = 0; i < sTargets.length; i++) {
163 sTargets[i] = Class.forName(
164 String.format("test.amslam.subreceivers.PingReceiver%03d", i));
165 } catch (ClassNotFoundException e) {
166 throw new RuntimeException(e);
170 Runnable work = () -> {
173 Intent intent = sWorkQueue.take();
174 intent.putExtra("start_time", SystemClock.uptimeMillis());
175 sAppContext.startService(intent);
176 } catch (InterruptedException e) {}
180 // How many worker threads should we spawn? ¯\_(ツ)_/¯
181 for (int i = 0; i < 10; i++) {
182 new Thread(work, "Slammer" + i).start();