[Libwebsockets] cpu > 96%

Andy Green andy at warmcat.com
Thu Jan 29 02:45:08 CET 2015



On 28 January 2015 22:30:38 GMT+08:00, Andy Green <andy at warmcat.com> wrote:
>
>
>On 28 January 2015 21:29:49 GMT+08:00, Andy Green <andy at warmcat.com>
>wrote:
>>
>>
>>On 28 January 2015 20:57:26 GMT+08:00, Gesiel <gesielmm at gmail.com>
>>wrote:
>>>Hi,
>>>
>>>Compiled without SSL support (-DLWS_WITH_SSL = 0)
>>>and the CPU is not longer tied when called
>>>libwebsocket_cancel_service()
>>>from another thread (Actually not even have to be from another
>thread,
>>>calling on the main thread already has the problem).
>>>I suspect the problem is in the lws-plat-unix.c file when compiling
>>>with -DLWS_WITH_SSL = 1, lws_plat_service function() on line 111:
>>>
>>>#ifdef LWS_OPENSSL_SUPPORT
>>>     / * If we know we have non-network pending date, do not wait in 
>>>poll * /
>>>     if (context-> ssl_flag_buffered_reads)
>>>         timeout_ms = 0;
>>>#endif
>>>
>>>I believe that somehow the timeout is being reset before reaching the
>
>>>poll() function
>>>when compiled with OPENSSL _SUPPORT and invoking 
>>>libwebsocket_cancel_service ().
>>
>>Yes it makes sense I think... it's a latency optimization that works
>>fine if someone wanted some service because it'll get priority.
>>
>>But if nobody "real" (just the interruption pipe) wanted service,
>>setting the poll timeout to 0 which is the optimization trick that
>will
>>exactly make you busyloop until someone wanted service.
>>
>>And he doesn't know we did a standalone pipe action.... hum let me
>>stare at it a bit.
>
>I can see a good way forward, I'll continue with it tomorrow.

I pushed a couple of patches that improve how buffered ssl reads are managed that should remove this problem as a side effect (if it works properly), please give current HEAD a try.

-Andy

>-Andy
>
>>-Andy
>>
>>>Thanks
>>>
>>>
>>>On 27/01/2015 17:12, Andy Green wrote:
>>>>
>>>> On 28 January 2015 02:27:32 GMT+08:00, Gesiel <gesielmm at gmail.com>
>>>wrote:
>>>>> First thanks for the library.
>>>>> I noticed that after a call libwebsocket_cancel_service in another
>>>>> thread, the CPU rises above 96%.
>>>>> I tested also calling
>>libwebsocket_callback_on_writable_all_protocol
>>>>> that same thread, showing the same thing.
>>>>> This thread is simply by setting one flag (ws_flags_write_all) for
>>>the
>>>>> main thread calls libwebsocket_callback_on_writable_all_protocol.
>>>>> The problem presents itself when enters 'y' via keyboard on which
>>>sets
>>>>> the flag and calls libwebsocket_cancel_service.
>>>>> In this thread I can get around this by setting the flag and just
>>>never
>>>>> calling libwebsocket_cancel_service or
>>>>> libwebsocket_callback_on_writable_all_protocol,
>>>>> using a small timeout in libwebsocket_service.
>>>>> It is curious because libwebsocket_cancel_service just write the
>>>dummy
>>>>> pipe while libwebsocket_callback_on_writable_all_protocol do more
>>>>> things.
>>>> Usually the way to debug busywaiting is find out where he's
>spinning
>>>and then why he feels he should spin.
>>>>
>>>> Normally the answer with threads is 'you can't call that from
>>another
>>>thread' but in this case, it's meant to be threadsafe.  So I guess
>the
>>>problem is when you call writeable api, he triggers the pipe AND
>>>somebody needs service.  Maybe trigger the pipe but nobody else has
>>>POLLx on their fd has a bug.
>>>>
>>>> So stick some logging in the platform service routine and see what
>>>the flow is like in there when you start spinning.
>>>>
>>>> -Andy
>>>>
>>>>> I'm running on the raspberry pi model b.
>>>>>
>>>>> My Thread:
>>>>>
>>>------------------------------------------------------------------------------------
>>>>>
>>>>> static volatile int ws_flags_write_all = 0;
>>>>>
>>>>> static void * my_thread(void *arg){
>>>>>      char buf[25];
>>>>>
>>>>>      while(!force_exit) {
>>>>>
>>>>>          printf("\n>>>");
>>>>>          fflush(stdout);
>>>>>
>>>>>          if(fgets(buf, 20, stdin)==NULL)
>>>>>              continue;
>>>>>
>>>>>          if(buf[0] == 'q' || buf[0] == 'Q'){
>>>>>              force_exit = 1;
>>>>>              libwebsocket_cancel_service(context);
>>>>>              break;
>>>>>          }
>>>>>
>>>>>          switch(buf[0]){
>>>>>              case 'x': ws_flags_write_all = 1; break;  /* continue
>>>dumb
>>>>> protocol, cpu OK  */
>>>>>              case 'X': ws_flags_write_all = 0; break;  /* pause
>>dumb
>>>>> protocol, cpu OK     */
>>>>>             case 'y':                                  /* continue
>>>dumb
>>>>> protocol cpu > 96% !!!! */
>>>>>                  ws_flags_write_all = 1;
>>>>>                  libwebsocket_cancel_service(context);
>>>>>          }
>>>>>      }
>>>>>
>>>>>      return NULL;
>>>>> }
>>>>>
>>>>>
>>>-------------------------------------------------------------------------------------
>>>>>
>>>>> Part Main thread:
>>>>>
>>>>>          pthread_t thr;
>>>>>          if((n = pthread_create(&thr, NULL, &my_thread, NULL)) !=
>>>0){
>>>>>              errno = n;
>>>>>              perror("pthread_create");
>>>>>              return -1;
>>>>>          }
>>>>>
>>>>>          n = 0;
>>>>>          while (n >= 0 && !force_exit) {
>>>>>                  struct timeval tv;
>>>>>
>>>>>                  gettimeofday(&tv, NULL);
>>>>>
>>>>>                  /*
>>>>>                   * This provokes the
>LWS_CALLBACK_SERVER_WRITEABLE
>>>for
>>>>> every
>>>>>                   * live websocket connection using the
>>>DUMB_INCREMENT
>>>>> protocol,
>>>>>                   * as soon as it can take more packets (usually
>>>>> immediately)
>>>>>                   */
>>>>>                  if(ws_flags_write_all){  /* set only in my_thread
>>>*/
>>>>>                      ms = (tv.tv_sec * 1000) + (tv.tv_usec /
>1000);
>>>>>                      if ((ms - oldms) > 50) {
>>>>>
>>>libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_DUMB_INCREMENT]);
>>>>>                          oldms = ms;
>>>>>                      }
>>>>>                  }
>>>>> #ifdef EXTERNAL_POLL
>>>>>
>>>>>                  /*
>>>>>               * this represents an existing server's single poll
>>>action
>>>>>                   * which also includes libwebsocket sockets
>>>>>                   */
>>>>>
>>>>>                  n = poll(pollfds, count_pollfds, 50);
>>>>>                  if (n < 0)
>>>>>                          continue;
>>>>>
>>>>>
>>>>>                  if (n)
>>>>>                          for (n = 0; n < count_pollfds; n++)
>>>>>                                  if (pollfds[n].revents)
>>>>>                                          /*
>>>>>                                         * returns immediately if
>>the
>>>fd
>>>>> does not
>>>>>                                          * match anything under
>>>>> libwebsockets
>>>>>                                          * control
>>>>>                                          */
>>>>>                                          if
>>>>> (libwebsocket_service_fd(context,
>>>>> &pollfds[n]) < 0)
>>>>>                                                  goto done;
>>>>> #else
>>>>>                  /*
>>>>>                   * If libwebsockets sockets are all we care
>about,
>>>>>                   * you can use this api which takes care of the
>>>poll()
>>>>>                   * and looping through finding who needed
>service.
>>>>>                   *
>>>>>                 * If no socket needs service, it'll return anyway
>>>after
>>>>>                   * the number of ms in the second argument.
>>>>>                   */
>>>>>
>>>>>                  n = libwebsocket_service(context, 50);
>>>>> #endif
>>>>>          }
>>>>>
>>>>> #ifdef EXTERNAL_POLL
>>>>> done:
>>>>> #endif
>>>>>
>>>>>          libwebsocket_context_destroy(context);
>>>>>
>>>>>          lwsl_notice("libwebsockets-test-server exited
>cleanly\n");
>>>>>
>>>>> #ifndef WIN32
>>>>>          closelog();
>>>>> #endif
>>>>>
>>>>>          pthread_cancel(thr);
>>>>>          pthread_join(thr, NULL);
>>>>>
>>>>>          return 0;
>>>>>
>>>--------------------------------------------------------------------------------------
>>>>>
>>>>> Console output:
>>>>>
>>>>> lwsts [31255]: libwebsockets test server - (C) Copyright 2010-2014
>>>Andy
>>>>> Green <andy at warmcat.com> - licensed under LGPL2.1
>>>>> Using resource path "/home/pi/test-server"
>>>>> lwsts [31255]: Initial logging level 7
>>>>> lwsts [31255]: Library version: 1.3 080e6dd
>>>>> lwsts [31255]: IPV6 not compiled in
>>>>> lwsts [31255]: libev support not compiled in
>>>>> lwsts [31255]: static allocation: 4480 + (12 x 1024 fds) = 16768
>>>bytes
>>>>> lwsts [31255]: canonical_hostname raspberrypi
>>>>> lwsts [31255]: per-conn Memory: 144 + 2100 + protocol headers rx
>>buf
>>>>> lwsts [31255]: Compiled with OpenSSL support
>>>>> lwsts [31255]: Using non-SSL mode
>>>>> lwsts [31255]: Listening on port 7681
>>>>>
>>>>>
>>>>> Modified file test-server.c
>>>>> http://pastebin.com/DMah3jNc
>>>>>
>>>>>
>>>>> Thank U
>>>>>
>>>>> ---
>>>>> Este email foi escaneado pelo Avast antivírus.
>>>>> http://www.avast.com
>>>
>>>
>>>---
>>>Este email foi escaneado pelo Avast antivírus.
>>>http://www.avast.com
>>
>>_______________________________________________
>>Libwebsockets mailing list
>>Libwebsockets at ml.libwebsockets.org
>>http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
>
>_______________________________________________
>Libwebsockets mailing list
>Libwebsockets at ml.libwebsockets.org
>http://ml.libwebsockets.org/mailman/listinfo/libwebsockets




More information about the Libwebsockets mailing list