Home | History | Annotate | Download | only in amslam
      1 /*
      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 
     17 package test.amslam;
     18 
     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;
     28 
     29 import java.util.Queue;
     30 import java.util.concurrent.ArrayBlockingQueue;
     31 import java.util.concurrent.BlockingQueue;
     32 import java.util.concurrent.ConcurrentLinkedQueue;
     33 
     34 public 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);
     63         mOutput = findViewById(R.id.output);
     64         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 }
    186