0

I have two threads that increase the CPU overhead. 1. Reading from the socket in a synchronous way. 2. Waiting to accept connections from other clients

Problem 1, I'm just trying to read any data that comes from the client, and I can not use readline, because the incoming data has newlines that I mark for knowing the header end of a message. So I'm using that way in a thread, but it increases the CPU overhead

 public static String convertStreamToString(TCPServerConnectionListner socket) throws UnsupportedEncodingException, IOException, InterruptedException {

        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getSocket().getInputStream()));
        // At this point it is too early to read. So it most likely return false
        System.out.println("Buffer Reader ready? " + reader.ready());
        // StringBuilder to hold the response
        StringBuilder sb = new StringBuilder();
        // Indicator to show if we have started to receive data or not
        boolean dataStreamStarted = false;
        // How many times we went to sleep waiting for data
        int sleepCounter = 0;
        // How many times (max) we will sleep before bailing out
        int sleepMaxCounter = 5;
        // Sleep max counter after data started
        int sleepMaxDataCounter = 50;
        // How long to sleep for each cycle
        int sleepTime = 5;
        // Start time
        long startTime = System.currentTimeMillis();
        // This is a tight loop. Not sure what it will do to CPU
        while (true) {
            if (reader.ready()) {
                sb.append((char) reader.read());
                // Once started we do not expect server to stop in the middle and restart
                dataStreamStarted = true;
            } else {
                Thread.sleep(sleepTime);
                if (dataStreamStarted && (sleepCounter >= sleepMaxDataCounter)) {
                    System.out.println("Reached max sleep time of " + (sleepMaxDataCounter * sleepTime) + " ms after data started");
                    break;
                } else {
                    if (sleepCounter >= sleepMaxCounter) {
                        System.out.println("Reached max sleep time of " + (sleepMaxCounter * sleepTime) + " ms. Bailing out");
                        // Reached max timeout waiting for data. Bail..
                        break;
                    }
                }
                sleepCounter++;
            }

        }
        long endTime = System.currentTimeMillis();

        System.out.println(sb.toString());
        System.out.println("Time " + (endTime - startTime));

        return sb.toString();
    }

Problem 2, I don't know what is the best way for doing that, I'm just having a thread that constantly wait for other clients, and accept it. But this also takes a lot of CPU overhead.

 // Listner to accept any client connection
    @Override
    public void run() {

        while (true) {
            try {
                mutex.acquire();
                if (!welcomeSocket.isClosed()) {
                    connectionSocket = welcomeSocket.accept();
                   // Thread.sleep(5);
                }


            } catch (IOException ex) {
                Logger.getLogger(TCPServerConnectionListner.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InterruptedException ex) {
                Logger.getLogger(TCPServerConnectionListner.class.getName()).log(Level.SEVERE, null, ex);
            }
            finally
            {
                mutex.release();
            }

        }
    }
}

A Profiler Picture would also help, but I'm wondering why the SwingWorker Thread Takes that much time? enter image description here

Update Code For Problem One:

    public static String convertStreamToString(TCPServerConnectionListner socket) throws UnsupportedEncodingException, IOException, InterruptedException {

            byte[] resultBuff = new byte[0];
            byte[] buff = new byte[65534];
            int k = -1;
            k = socket.getSocket().getInputStream().read(buff, 0, buff.length);
                byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
                System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
                System.arraycopy(buff, 0, tbuff, resultBuff.length, k);  // copy current lot
                resultBuff = tbuff; // call the temp buffer as your result buff

        return new String(resultBuff);
    }

}
        ![snapshot][2]
andre_lamothe
  • 2,171
  • 2
  • 41
  • 74
  • Well I don't understand problem 2. What is the mutex for? Also, since accept() is a blocking call, the CPU use should be minimal. – Martin James Apr 12 '13 at 08:13
  • The welcomeSocket can be accessed from the main thread so I was protecting it. Well OK, Then it is not what it takes most of the CPU Cycle, what about the first problem ?. The read() also blocking, so why it eats CPU cycles? – andre_lamothe Apr 12 '13 at 08:17
  • OK, now you have a blocking read, but it takes 60ms. First, has your total CPU use dropped? I'm asking in case you have any more avoidable loops in your other threads. – Martin James Apr 12 '13 at 11:21
  • @MartinJames I will provide a snapshot of netbeans profiler. It did but little bit, just 3% minus. – andre_lamothe Apr 12 '13 at 11:25

3 Answers3

2

Just get rid of the ready() call and block. Everything you do while ready() is false is literally a complete waste of time, including the sleep. The read() will block for exactly the right amount of time. A sleep() won't. You are either not sleeping for long enough, which wastes CPU time, or too long, which adds latency. Once in a while you may sleep for the correct time, but this is 100% luck, not good management. If you want a read timeout, use a read timeout.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

You appear to be waiting until there is not more data after some timeout.

I suggest you use Socket.setSoTimeout(timeout in seconds)

A better solution is to not need to do this by having a protocol which allows you to know when the end of data is reached. You would only do this if you the server is poorly implemented and you have no way to fix it.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • So I would better to remove the while(true), and just read, then I set socket.SetSoTimeout()? Does it affect the read() function ? – andre_lamothe Apr 12 '13 at 08:30
  • Profilers can report read() and blocking but this doesn't mean it is using CPU. – Peter Lawrey Apr 12 '13 at 09:41
  • That is exactly what it does. BTW I wouldn't use StringBuilder if you can avoid it, it is better to process the data as you get it. – Peter Lawrey Apr 12 '13 at 09:42
  • Do you think using Java.NIO would help ?. I would like to use read() to read the data as I get, but it will block the thread. – andre_lamothe Apr 12 '13 at 09:58
  • You can use non-blocking IO but is much complicated but it's not clear to me what you gain. i.e. why is blocking the thread a problem in this case? – Peter Lawrey Apr 12 '13 at 10:04
  • it takes a lot from the CPU. – andre_lamothe Apr 12 '13 at 10:49
  • I have updated the code for the first problem, I added the socket time out also. The read() takes about 60ms its too much :/ – andre_lamothe Apr 12 '13 at 11:09
  • When its blocked it take very little from the CPU. It can context switch which can cost 10-100 micro-seconds. Are you sure you are talking about a real problem and not an artifact of the profiler? It doesn't matter how long the read() takes as the CPU can run another thread instead. – Peter Lawrey Apr 12 '13 at 11:37
  • +1 Peter :) Thanks. But Then I will get many timeout exceptions, is this correct way ? – andre_lamothe Apr 12 '13 at 11:45
  • You will get one timeout per connection. I wouldn't wait for multiple timeouts. (Not sure why you are waiting for one at all ;) – Peter Lawrey Apr 12 '13 at 11:49
  • I'm waiting for any connection to connect to my server. That's why I'm waiting... or is there a better way ? – andre_lamothe Apr 12 '13 at 11:54
  • Just use a blocking read(). One thread for the acceptor and one for each reading thread. – Peter Lawrey Apr 12 '13 at 11:59
  • That is the simplest thing to do. And even if the profile says read() is using CPU this really means it is blocking on a read() which isn't using CPU. – Peter Lawrey Apr 12 '13 at 13:35
0

For Problem 1. 100% CPU may be because you are reading single char from the BufferedReader.read(). Instead you can read chunk of data to an array and add it to your stringbuilder.

pranav
  • 1