Subversion Repositories general

Rev

Rev 1127 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package ak.httpbench;

import java.util.List;
import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;

public class HttpBench
{
        private static Log log = LogFactory.getLog(HttpBench.class);

        public static void main(String[] args)
                throws Exception
        {
                HttpBench hb = new HttpBench();

                if(hb.parseParams(args))
                        hb.run();
        }

        // config
        private int    threadNumber         = 10;
        private int    requestNumber        = 50;
        private int    requestPerConnection = 0;
        private int    sleepMin             = 0;
        private int    sleepMax             = 1000; // 1s
        private int    timeout              = 60000; // 1min
        private String firstUrl             = null;
        private List   urls                 = new ArrayList();

        private int parseInt(String s, String prefix, String errorMsg)
                throws Exception
        {
                try {
                        return Integer.parseInt(s.substring(prefix.length()));
                }
                catch(Exception ex) {
                        log.error(errorMsg);
                        throw ex;
                }
        }

        private boolean parseParams(String[] args)
                throws Exception
        {
                try {
                        for(int i = 0; i< args.length; i++) {
                                String s = args[i];
                                if(s.startsWith("thr=")) {
                                        threadNumber = parseInt(s, "thr=",
                                                "Cannot get number of threads from " + s);
                                }
                                else if(s.startsWith("req=")) {
                                        requestNumber = parseInt(s, "req=",
                                                "Cannot get number of requests from " + s);
                                }
                                else if(s.startsWith("rpc=")) {
                                        requestPerConnection = parseInt(s, "rpc=",
                                                "Cannot get number of requests per connection from " + s);
                                }
                                else if(s.startsWith("sleepMin=")) {
                                        sleepMin = parseInt(s, "sleepMin=",
                                                "Cannot get min sleep from " + s);
                                }
                                else if(s.startsWith("timeout=")) {
                                        timeout = parseInt(s, "timeout=",
                                                "Cannot get timeout from " + s);
                                }
                                else if(s.startsWith("sleepMax=")) {
                                        sleepMax = parseInt(s, "sleepMax=",
                                                "Cannot get max sleep from " + s);
                                }
                                else if(s.startsWith("firstUrl=")) {
                                        firstUrl = s.substring("firstUrl=".length());
                                        if(firstUrl.equals("")) firstUrl = null;
                                }
                                else {
                                        urls.add(s);
                                }
                        }

                        if(urls.isEmpty()) {
                                log.error("Need at least one URL to work");
                                return false;
                        }

                        return true;
                }
                catch(Exception ex) {
                        return false;
                }
        }

        private void run()
                throws Exception
        {
                log.info("start " + threadNumber + "/" + requestNumber + "/" + requestPerConnection
                        + " " + sleepMin + "/" + sleepMax);
                log.info("  firstUrl: " + (firstUrl == null ? "<null>" : firstUrl));
                for(int i = 0; i < urls.size(); i++)
                        log.info("  url: " + urls.get(i));

                List     threads  = new ArrayList();
                List     workers  = new ArrayList();
                String[] urlArray = (String[])urls.toArray(new String[] {});

                for(int i = 0; i < threadNumber; i++) {
                        log.debug("create thread " + i);
                        
                        HttpThread ht = new HttpThread(firstUrl, urlArray);
                        workers.add(ht);
                        ht.setRequestNumber(requestNumber);
                        ht.setRequestPerConnection(requestPerConnection);
                        ht.setSleepMin(sleepMin);
                        ht.setSleepMax(sleepMax);
                        ht.setTimeout(timeout);

                        Thread t = new Thread(ht);
                        threads.add(t);
                        t.start();
                }

                // wait for all
                for(int i = 0; i < threads.size(); i++) {
                        log.debug("wait for thread " + i);

                        Thread t = (Thread)threads.get(i);
                        try {
                                t.join();
                        }
                        catch(InterruptedException ex) {
                        }
                }

                // statistics
                long totalTime      = 0;
                long reqTime        = 0;
                long minTime        = Long.MAX_VALUE;
                long maxTime        = -1;
                int  successRequest = 0;
                int  failRequest    = 0;
                for(int i = 0; i < workers.size(); i++) {
                        HttpThread ht = (HttpThread)workers.get(i);
                        if(ht.getSuccess()) {
                                totalTime += ht.getRunTime();

                                List results = ht.getResults();
                                for(int j = 0; j < results.size(); j++) {
                                        RequestResult r = (RequestResult)results.get(j);
                                        totalTime -= r.sleepBefore;
                                        if(r.success) {
                                                successRequest++;

                                                long t = r.stopTime - r.startTime;
                                                reqTime += t;
                                                if(minTime > t) minTime = t;
                                                if(maxTime < t) maxTime = t;
                                        }
                                        else {
                                                failRequest++;
                                        }
                                }
                        }
                }

                log.info("done " + totalTime + "ms / " + successRequest + " = "
                        + (totalTime / successRequest) + "ms "
                        + minTime + "/" + (reqTime / successRequest) + "/" + maxTime
                        + " ms, " + failRequest + " failed");
        }
}

class RequestResult
{
        public boolean   success = false;
        public String    url;
        public long      sleepBefore;
        public long      startTime;
        public long      stopTime;
        public int       code;
        public Exception exception;
}

class HttpThread implements Runnable
{
        private static int threadCount = 0;
        private static Log log         = LogFactory.getLog(HttpThread.class);

        private int      id;
        private String   firstUrl; // is used one time only, may be null
        private String[] urls;
        private int      requestNumber = 1;
        private int      requestPerConnection = 0; // 0 == all
        private int      sleepMin = 0;
        private int      sleepMax = 0;
        private int      timeout  = 0;

        private boolean  success;
        private long     runTime;
        private List     results;

        public HttpThread(String firstUrl, String[] urls)
        {
                id = threadCount++;
                this.firstUrl = firstUrl;
                this.urls     = urls;
        }

        public int getId()
        {
                return id;
        }

        public int getRequestNumber()
        {
                return requestNumber;
        }

        public void setRequestNumber(int requestNumber)
        {
                this.requestNumber = requestNumber;
        }

        public int getRequestPerConnection()
        {
                return requestPerConnection;
        }

        public void setRequestPerConnection(int requestPerConnection)
        {
                this.requestPerConnection = requestPerConnection;
        }

        public void setSleepMin(int sleepMin)
        {
                this.sleepMin = sleepMin;
        }

        public int getSleepMax()
        {
                return sleepMax;
        }

        public void setSleepMax(int sleepMax)
        {
                this.sleepMax = sleepMax;
        }

        public int getTimeout()
        {
                return timeout;
        }

        public void setTimeout(int timeout)
        {
                this.timeout = timeout;
        }

        public boolean getSuccess()
        {
                return success;
        }

        public long getRunTime()
        {
                return runTime;
        }

        public List getResults()
        {
                return results;
        }

        public void run()
        {
                long sumSleep = 0;
                log.info(Integer.toString(id) + ": start");

                try {
                        HttpClient client = new HttpClient();

                        results = new ArrayList();
                        for(int i = 0; i < requestNumber; i++) {
                                results.add(new RequestResult());
                        }

                        long startTime = System.currentTimeMillis();
                        for(int i = 0; i < requestNumber; i++) {
                                RequestResult result = (RequestResult)results.get(i);

                                if(sleepMax > 0) {
                                        long sleep = (long)(Math.random() * (sleepMax - sleepMin)) + sleepMin;
                                        sumSleep += sleep;
                                        result.sleepBefore = sleep;
                                        log.trace(Integer.toString(id) + ": sleep for " + sleep + "ms");
                                        Thread.sleep(sleep);
                                }

                                if(i == 0 && firstUrl != null)
                                        result.url = firstUrl;
                                else
                                        result.url = urls[(firstUrl == null ? i : i-1) % urls.length];

                                GetMethod get = new GetMethod(result.url);
                                get.getParams().setSoTimeout(timeout);

                                try {
                                        result.startTime = System.currentTimeMillis();
                                        result.code      = client.executeMethod(get);
                                        result.stopTime  = System.currentTimeMillis();
                                        result.success   = true;

                                        if(log.isTraceEnabled()) {
                                                String response = get.getResponseBodyAsString();
                                                log.trace(Integer.toString(id) + ": got " + result
                                                        + " in " + (result.stopTime - result.startTime)
                                                        + "ms \n'" + response.substring(0, 100) + "'");
                                        }
                                        else if(log.isDebugEnabled()) {
                                                log.debug(Integer.toString(id) + ": got " + result
                                                        + " in " + (result.stopTime - result.startTime) + "ms");
                                        }
                                }
                                catch(Exception ex) {
                                        result.stopTime  = System.currentTimeMillis();
                                        result.exception = ex;
                                }
                                finally {
                                        get.releaseConnection();
                                }

                                if(requestPerConnection > 0 && (i+1) % requestPerConnection == 0
                                        && i < requestNumber-1)
                                {
                                        log.debug(Integer.toString(id)
                                                + ": request per connection limit reached at " + i);
                                        client.getHttpConnectionManager().closeIdleConnections(0);
                                }
                        }

                        client.getHttpConnectionManager().closeIdleConnections(0);
                        success = true;
                        runTime = System.currentTimeMillis() - startTime;
                }
                catch(Exception ex) {
                        success = false;
                        log.warn(Integer.toString(id), ex);
                }

                log.info(Integer.toString(id) + ": done" + (success ? " " + runTime
                        + "/" + sumSleep + "/" + (runTime - sumSleep) + " ms": " with error"));
        }
}