stats.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to
  8. * deal in the Software without restriction, including without limitation the
  9. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. * sell copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22. * IN THE SOFTWARE.
  23. */
  24. #include "private-lib-core.h"
  25. #if defined(LWS_WITH_STATS)
  26. uint64_t
  27. lws_stats_get(struct lws_context *context, int index)
  28. {
  29. struct lws_context_per_thread *pt = &context->pt[0];
  30. if (index >= LWSSTATS_SIZE)
  31. return 0;
  32. return pt->lws_stats[index];
  33. }
  34. static const char * stat_names[] = {
  35. "C_CONNECTIONS",
  36. "C_API_CLOSE",
  37. "C_API_READ",
  38. "C_API_LWS_WRITE",
  39. "C_API_WRITE",
  40. "C_WRITE_PARTIALS",
  41. "C_WRITEABLE_CB_REQ",
  42. "C_WRITEABLE_CB_EFF_REQ",
  43. "C_WRITEABLE_CB",
  44. "C_SSL_CONNECTIONS_FAILED",
  45. "C_SSL_CONNECTIONS_ACCEPTED",
  46. "C_SSL_CONNECTIONS_ACCEPT_SPIN",
  47. "C_SSL_CONNS_HAD_RX",
  48. "C_TIMEOUTS",
  49. "C_SERVICE_ENTRY",
  50. "B_READ",
  51. "B_WRITE",
  52. "B_PARTIALS_ACCEPTED_PARTS",
  53. "US_SSL_ACCEPT_LATENCY_AVG",
  54. "US_WRITABLE_DELAY_AVG",
  55. "US_WORST_WRITABLE_DELAY",
  56. "US_SSL_RX_DELAY_AVG",
  57. "C_PEER_LIMIT_AH_DENIED",
  58. "C_PEER_LIMIT_WSI_DENIED",
  59. "C_CONNECTIONS_CLIENT",
  60. "C_CONNECTIONS_CLIENT_FAILED",
  61. };
  62. static int
  63. quantify(struct lws_context *context, int tsi, char *p, int len, int idx,
  64. uint64_t *sum)
  65. {
  66. const lws_humanize_unit_t *schema = humanize_schema_si;
  67. struct lws_context_per_thread *pt = &context->pt[tsi];
  68. uint64_t u, u1;
  69. lws_pt_stats_lock(pt);
  70. u = pt->lws_stats[idx];
  71. /* it's supposed to be an average? */
  72. switch (idx) {
  73. case LWSSTATS_US_SSL_ACCEPT_LATENCY_AVG:
  74. u1 = pt->lws_stats[LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED];
  75. if (u1)
  76. u = u / u1;
  77. break;
  78. case LWSSTATS_US_SSL_RX_DELAY_AVG:
  79. u1 = pt->lws_stats[LWSSTATS_C_SSL_CONNS_HAD_RX];
  80. if (u1)
  81. u = u / u1;
  82. break;
  83. case LWSSTATS_US_WRITABLE_DELAY_AVG:
  84. u1 = pt->lws_stats[LWSSTATS_C_WRITEABLE_CB];
  85. if (u1)
  86. u = u / u1;
  87. break;
  88. }
  89. lws_pt_stats_unlock(pt);
  90. *sum += u;
  91. switch (stat_names[idx][0]) {
  92. case 'U':
  93. schema = humanize_schema_us;
  94. break;
  95. case 'B':
  96. schema = humanize_schema_si_bytes;
  97. break;
  98. }
  99. return lws_humanize(p, len, u, schema);
  100. }
  101. void
  102. lws_stats_log_dump(struct lws_context *context)
  103. {
  104. struct lws_vhost *v = context->vhost_list;
  105. uint64_t summary[LWSSTATS_SIZE];
  106. char bufline[128], *p, *end = bufline + sizeof(bufline) - 1;
  107. int n, m;
  108. if (!context->updated)
  109. return;
  110. context->updated = 0;
  111. memset(summary, 0, sizeof(summary));
  112. lwsl_notice("\n");
  113. lwsl_notice("LWS internal statistics dump ----->\n");
  114. for (n = 0; n < (int)LWS_ARRAY_SIZE(stat_names); n++) {
  115. uint64_t u = 0;
  116. /* if it's all zeroes, don't report it */
  117. for (m = 0; m < context->count_threads; m++) {
  118. struct lws_context_per_thread *pt = &context->pt[m];
  119. u |= pt->lws_stats[n];
  120. }
  121. if (!u)
  122. continue;
  123. p = bufline;
  124. p += lws_snprintf(p, lws_ptr_diff(end, p), "%28s: ",
  125. stat_names[n]);
  126. for (m = 0; m < context->count_threads; m++)
  127. quantify(context, m, p, lws_ptr_diff(end, p), n, &summary[n]);
  128. lwsl_notice("%s\n", bufline);
  129. }
  130. lwsl_notice("Simultaneous SSL restriction: %8d/%d\n",
  131. context->simultaneous_ssl,
  132. context->simultaneous_ssl_restriction);
  133. lwsl_notice("Live wsi: %8d\n",
  134. context->count_wsi_allocated);
  135. while (v) {
  136. if (v->lserv_wsi &&
  137. v->lserv_wsi->position_in_fds_table != LWS_NO_FDS_POS) {
  138. struct lws_context_per_thread *pt =
  139. &context->pt[(int)v->lserv_wsi->tsi];
  140. struct lws_pollfd *pfd;
  141. pfd = &pt->fds[v->lserv_wsi->position_in_fds_table];
  142. lwsl_notice(" Listen port %d actual POLLIN: %d\n",
  143. v->listen_port,
  144. (int)pfd->events & LWS_POLLIN);
  145. }
  146. v = v->vhost_next;
  147. }
  148. for (n = 0; n < context->count_threads; n++) {
  149. struct lws_context_per_thread *pt = &context->pt[n];
  150. struct lws *wl;
  151. int m = 0;
  152. lwsl_notice("PT %d\n", n + 1);
  153. lws_pt_lock(pt, __func__);
  154. lwsl_notice(" AH in use / max: %d / %d\n",
  155. pt->http.ah_count_in_use,
  156. context->max_http_header_pool);
  157. wl = pt->http.ah_wait_list;
  158. while (wl) {
  159. m++;
  160. wl = wl->http.ah_wait_list;
  161. }
  162. lwsl_notice(" AH wait list count / actual: %d / %d\n",
  163. pt->http.ah_wait_list_length, m);
  164. lws_pt_unlock(pt);
  165. }
  166. #if defined(LWS_WITH_PEER_LIMITS)
  167. m = 0;
  168. for (n = 0; n < (int)context->pl_hash_elements; n++) {
  169. lws_start_foreach_llp(struct lws_peer **, peer,
  170. context->pl_hash_table[n]) {
  171. m++;
  172. } lws_end_foreach_llp(peer, next);
  173. }
  174. lwsl_notice(" Peers: total active %d\n", m);
  175. if (m > 10) {
  176. m = 10;
  177. lwsl_notice(" (showing 10 peers only)\n");
  178. }
  179. if (m) {
  180. for (n = 0; n < (int)context->pl_hash_elements; n++) {
  181. char buf[72];
  182. lws_start_foreach_llp(struct lws_peer **, peer,
  183. context->pl_hash_table[n]) {
  184. struct lws_peer *df = *peer;
  185. if (!lws_plat_inet_ntop(df->af, df->addr, buf,
  186. sizeof(buf) - 1))
  187. strcpy(buf, "unknown");
  188. #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
  189. lwsl_notice(" peer %s: count wsi: %d, count ah: %d\n",
  190. buf, df->count_wsi,
  191. df->http.count_ah);
  192. #else
  193. lwsl_notice(" peer %s: count wsi: %d\n",
  194. buf, df->count_wsi);
  195. #endif
  196. if (!--m)
  197. break;
  198. } lws_end_foreach_llp(peer, next);
  199. }
  200. }
  201. #endif
  202. lwsl_notice("\n");
  203. }
  204. void
  205. lws_stats_bump(struct lws_context_per_thread *pt, int i, uint64_t bump)
  206. {
  207. lws_pt_stats_lock(pt);
  208. pt->lws_stats[i] += bump;
  209. if (i != LWSSTATS_C_SERVICE_ENTRY) {
  210. pt->updated = 1;
  211. pt->context->updated = 1;
  212. }
  213. lws_pt_stats_unlock(pt);
  214. }
  215. void
  216. lws_stats_max(struct lws_context_per_thread *pt, int index, uint64_t val)
  217. {
  218. lws_pt_stats_lock(pt);
  219. if (val > pt->lws_stats[index]) {
  220. pt->lws_stats[index] = val;
  221. pt->updated = 1;
  222. pt->context->updated = 1;
  223. }
  224. lws_pt_stats_unlock(pt);
  225. }
  226. #endif